Compare commits
5 Commits
37799e3d8e
...
63962b7818
Author | SHA1 | Date | |
---|---|---|---|
63962b7818 | |||
8c4a683c1d | |||
c0906f7c21 | |||
26357d0627 | |||
de32ee578b |
Binary file not shown.
Before Width: | Height: | Size: 622 B |
Binary file not shown.
Before Width: | Height: | Size: 850 B |
BIN
frontend/img/maskable_icon_x512.png
Normal file
BIN
frontend/img/maskable_icon_x512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="16.000000pt" height="16.000000pt" viewBox="0 0 16.000000 16.000000"
|
|
||||||
preserveAspectRatio="xMidYMid meet">
|
|
||||||
<metadata>
|
|
||||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
|
||||||
</metadata>
|
|
||||||
<g transform="translate(0.000000,16.000000) scale(0.002286,-0.002286)"
|
|
||||||
fill="#000000" stroke="none">
|
|
||||||
<path d="M3220 6574 c-154 -16 -224 -25 -230 -29 -3 -2 -26 -6 -50 -10 -130
|
|
||||||
-18 -361 -83 -545 -152 -418 -159 -812 -431 -1075 -743 -30 -36 -60 -69 -66
|
|
||||||
-75 -18 -17 -111 -150 -156 -222 -42 -69 -138 -248 -138 -257 0 -3 35 -22 78
|
|
||||||
-43 42 -20 102 -55 132 -77 162 -118 604 -587 765 -810 11 -16 36 -49 56 -75
|
|
||||||
124 -161 287 -425 391 -634 28 -56 54 -104 58 -107 6 -4 2072 -5 2116 -1 6 1
|
|
||||||
21 25 35 54 39 84 161 304 227 408 218 344 467 647 809 982 156 153 220 203
|
|
||||||
330 258 94 46 92 34 26 159 -217 413 -559 756 -1009 1011 -57 32 -106 59 -109
|
|
||||||
59 -2 0 -33 14 -67 31 -181 89 -548 207 -723 233 -22 4 -65 11 -95 16 -30 5
|
|
||||||
-77 11 -105 14 -27 3 -77 8 -110 12 -98 11 -432 10 -545 -2z"/>
|
|
||||||
<path d="M578 4828 c-182 -24 -427 -197 -515 -363 -45 -87 -62 -162 -59 -264
|
|
||||||
6 -159 63 -291 211 -491 109 -146 231 -350 317 -529 l59 -125 41 47 c93 109
|
|
||||||
276 207 418 224 30 4 281 7 557 8 l502 0 -27 50 c-137 263 -367 594 -587 845
|
|
||||||
-113 129 -355 376 -454 463 -121 107 -296 158 -463 135z"/>
|
|
||||||
<path d="M6270 4832 c-43 -6 -133 -33 -180 -54 -78 -35 -124 -73 -287 -236
|
|
||||||
-212 -210 -283 -288 -438 -482 -139 -175 -273 -366 -338 -483 -14 -25 -37 -63
|
|
||||||
-51 -86 -14 -22 -26 -43 -26 -45 0 -3 -13 -28 -30 -56 -16 -27 -26 -50 -22
|
|
||||||
-51 4 0 243 -2 532 -4 504 -2 528 -3 598 -24 132 -39 263 -118 340 -207 l41
|
|
||||||
-48 60 125 c108 223 174 334 317 530 153 210 216 369 209 528 -6 144 -49 242
|
|
||||||
-154 354 -65 68 -196 162 -261 187 -19 7 -39 17 -45 21 -27 19 -202 40 -265
|
|
||||||
31z"/>
|
|
||||||
<path d="M1135 3039 c-13 -4 -26 -5 -28 -2 -7 7 -98 -22 -147 -47 -109 -56
|
|
||||||
-195 -177 -217 -305 -7 -45 -7 -1013 1 -1067 23 -164 130 -288 296 -344 53
|
|
||||||
-17 155 -18 2460 -18 1970 0 2412 2 2445 13 180 60 288 180 311 349 8 55 9
|
|
||||||
1035 1 1072 -14 70 -61 166 -104 215 -55 62 -168 121 -253 131 -70 9 -4732 11
|
|
||||||
-4765 3z"/>
|
|
||||||
<path d="M1222 962 c-18 -2 -31 -6 -28 -10 2 -4 7 -34 10 -67 10 -108 56 -458
|
|
||||||
61 -465 6 -9 344 -10 350 -1 2 4 7 32 10 62 3 30 8 65 10 79 2 14 7 48 10 75
|
|
||||||
5 50 10 91 20 163 3 20 7 59 10 85 3 27 7 53 11 58 3 5 -2 12 -10 15 -16 6
|
|
||||||
-399 11 -454 6z"/>
|
|
||||||
<path d="M5367 962 c-32 -2 -56 -6 -53 -10 2 -4 7 -32 10 -62 7 -63 13 -110
|
|
||||||
21 -160 2 -19 7 -57 10 -85 3 -27 7 -61 10 -75 2 -14 7 -52 10 -85 4 -32 9
|
|
||||||
-63 11 -67 6 -9 343 -8 349 1 3 6 17 100 31 216 2 22 7 58 10 80 11 80 13 91
|
|
||||||
19 150 3 33 8 68 11 78 4 14 -1 17 -28 18 -230 3 -363 3 -411 1z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.7 KiB |
@ -5,10 +5,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="Description" content="Canapé">
|
<meta name="Description" content="Canapé">
|
||||||
<link rel="icon" type="image/png" href="<%= require("./img/favicon-16x16.png").default %>" sizes="16x16">
|
<meta name="msapplication-navbutton-color" content="#4e5d6c">
|
||||||
<link rel="icon" type="image/png" href="<%= require("./img/favicon-32x32.png").default %>" sizes="32x32">
|
|
||||||
<meta name="msapplication-navbutton-color" content="#4E5D6C">
|
|
||||||
<link rel="mask-icon" href="<%= require("./img/safari-pinned-tab.svg").default %>" color="#5bbad5">
|
|
||||||
<title>Canapé</title>
|
<title>Canapé</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
// Import default image
|
// Import default image
|
||||||
import "../img/noimage.png";
|
import "../img/noimage.png";
|
||||||
|
|
||||||
// Import favicon settings
|
|
||||||
import "../img/favicon-16x16.png";
|
|
||||||
import "../img/favicon-32x32.png";
|
|
||||||
import "../img/favicon.ico";
|
|
||||||
import "../img/safari-pinned-tab.svg";
|
|
||||||
|
|
||||||
// Styles
|
// Styles
|
||||||
import "../scss/app.scss";
|
import "../scss/app.scss";
|
||||||
|
|
||||||
@ -91,6 +85,12 @@ const App = () => (
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ("serviceWorker" in navigator) {
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
navigator.serviceWorker.register("/service-worker.js");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router history={history}>
|
<Router history={history}>
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import moment from "moment";
|
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
import { format } from "timeago.js";
|
||||||
|
|
||||||
import { UserEdit } from "./userEdit";
|
import { UserEdit } from "./userEdit";
|
||||||
|
|
||||||
export const User = ({ id }) => {
|
export const User = ({ id }) => {
|
||||||
const user = useSelector((state) => state.admin.users.get(id));
|
const user = useSelector((state) => state.admin.users.get(id));
|
||||||
const polochon = user.polochon;
|
const polochon = user.polochon;
|
||||||
const lastSeen = moment(user.last_seen, "YYYY-MM-DDTHH:mm:ss.SZ");
|
const lastSeen = new Date(user.last_seen);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
@ -33,7 +33,7 @@ export const User = ({ id }) => {
|
|||||||
}
|
}
|
||||||
></span>
|
></span>
|
||||||
</td>
|
</td>
|
||||||
<td>{lastSeen.isValid() ? lastSeen.fromNow() : "-"}</td>
|
<td>{isNaN(lastSeen) ? "-" : format(lastSeen)}</td>
|
||||||
<td>
|
<td>
|
||||||
<UserEdit id={id} />
|
<UserEdit id={id} />
|
||||||
</td>
|
</td>
|
||||||
|
@ -76,15 +76,21 @@ const Player = ({ url, subtitles }) => {
|
|||||||
<video className="embed-responsive-item" controls>
|
<video className="embed-responsive-item" controls>
|
||||||
<source src={url} type="video/mp4" />
|
<source src={url} type="video/mp4" />
|
||||||
{subtitles &&
|
{subtitles &&
|
||||||
[...subtitles.entries()].map(([lang, sub]) => (
|
[...subtitles.entries()].map(([lang, sub]) => {
|
||||||
|
if (sub.embedded) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<track
|
<track
|
||||||
key={lang}
|
key={lang}
|
||||||
kind="subtitles"
|
kind="subtitles"
|
||||||
label={sub.language}
|
label={sub.lang}
|
||||||
src={sub.vvt_file}
|
src={sub.vvt_file}
|
||||||
srcLang={sub.language}
|
srcLang={sub.lang}
|
||||||
/>
|
/>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,21 +1,26 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import moment from "moment";
|
import { format } from "timeago.js";
|
||||||
|
|
||||||
const prettyDate = (input) => {
|
const prettyDate = (input) => {
|
||||||
if (typeof input !== "string" || input === "") {
|
if (typeof input !== "string" || input === "") {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
const date = moment(input, "YYYY-MM-DD HH:mm:ss Z");
|
const date = new Date(input);
|
||||||
if (!date.isValid()) {
|
if (isNaN(date)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = date.format("DD/MM/YYYY");
|
const dd = date.getDay().toString().padStart(2, "0");
|
||||||
|
const mm = date.getMonth().toString().padStart(2, "0");
|
||||||
|
const yyyy = date.getFullYear();
|
||||||
|
let output = `${dd}/${mm}/${yyyy}`;
|
||||||
|
|
||||||
if (date > moment().subtract(1, "month") && date < moment().add(1, "month")) {
|
const now = new Date();
|
||||||
output += " (" + date.fromNow() + ")";
|
const days = Math.abs((now - date) / (24 * 60 * 60 * 1000));
|
||||||
|
if (days < 31) {
|
||||||
|
output += ` (${format(date)})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -2,7 +2,7 @@ import React, { useEffect } from "react";
|
|||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { UAParser } from "ua-parser-js";
|
import { UAParser } from "ua-parser-js";
|
||||||
import moment from "moment";
|
import { format } from "timeago.js";
|
||||||
|
|
||||||
import { getUserTokens, deleteUserToken } from "../../actions/users";
|
import { getUserTokens, deleteUserToken } from "../../actions/users";
|
||||||
|
|
||||||
@ -27,6 +27,9 @@ export const UserTokens = () => {
|
|||||||
|
|
||||||
const Token = ({ token }) => {
|
const Token = ({ token }) => {
|
||||||
const ua = UAParser(token.user_agent);
|
const ua = UAParser(token.user_agent);
|
||||||
|
const lastUsed = new Date(token.last_used);
|
||||||
|
const createdAt = new Date(token.created_at);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card mt-3">
|
<div className="card mt-3">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
@ -39,8 +42,8 @@ const Token = ({ token }) => {
|
|||||||
<div className="card-body row">
|
<div className="card-body row">
|
||||||
<div className="col-12 col-md-6">
|
<div className="col-12 col-md-6">
|
||||||
<p>Last IP: {token.ip}</p>
|
<p>Last IP: {token.ip}</p>
|
||||||
<p>Last used: {moment(token.last_used).fromNow()}</p>
|
<p>Last used: {isNaN(lastUsed) ? "-" : format(lastUsed)}</p>
|
||||||
<p>Created: {moment(token.created_at).fromNow()}</p>
|
<p>Created: {isNaN(createdAt) ? "-" : format(createdAt)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-md-6">
|
<div className="col-12 col-md-6">
|
||||||
<p>
|
<p>
|
||||||
|
1668
frontend/package-lock.json
generated
1668
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,6 @@
|
|||||||
"immer": "^9.0.5",
|
"immer": "^9.0.5",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"moment": "^2.29.1",
|
|
||||||
"popper.js": "^1.15.0",
|
"popper.js": "^1.15.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
@ -49,14 +48,18 @@
|
|||||||
"eslint-plugin-react": "^7.24.0",
|
"eslint-plugin-react": "^7.24.0",
|
||||||
"eslint-plugin-react-hooks": "^4.2.0",
|
"eslint-plugin-react-hooks": "^4.2.0",
|
||||||
"html-webpack-plugin": "^5.3.2",
|
"html-webpack-plugin": "^5.3.2",
|
||||||
|
"mini-css-extract-plugin": "^2.2.0",
|
||||||
"postcss-loader": "^6.1.1",
|
"postcss-loader": "^6.1.1",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
|
"purgecss-webpack-plugin": "^4.0.3",
|
||||||
"sass": "^1.37.5",
|
"sass": "^1.37.5",
|
||||||
"sass-loader": "^12.1.0",
|
"sass-loader": "^12.1.0",
|
||||||
"style-loader": "^3.2.1",
|
"style-loader": "^3.2.1",
|
||||||
|
"timeago.js": "^4.0.2",
|
||||||
"universal-cookie": "^4.0.4",
|
"universal-cookie": "^4.0.4",
|
||||||
"webpack": "^5.50.0",
|
"webpack": "^5.50.0",
|
||||||
"webpack-cli": "^4.7.2",
|
"webpack-cli": "^4.7.2",
|
||||||
"webpack-pwa-manifest": "^4.3.0"
|
"webpack-pwa-manifest": "^4.3.0",
|
||||||
|
"workbox-webpack-plugin": "^6.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
var webpack = require("webpack");
|
var webpack = require("webpack");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
|
const glob = require("glob");
|
||||||
var WebpackPwaManifest = require("webpack-pwa-manifest");
|
var WebpackPwaManifest = require("webpack-pwa-manifest");
|
||||||
var HtmlWebpackPlugin = require("html-webpack-plugin");
|
var HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
var { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
var { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||||
|
const WorkboxPlugin = require("workbox-webpack-plugin");
|
||||||
|
const PurgeCSSPlugin = require("purgecss-webpack-plugin");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
|
||||||
var mode = "development";
|
var mode = "development";
|
||||||
var BUILD_DIR = path.resolve(__dirname, "../build/public/");
|
var BUILD_DIR = path.resolve(__dirname, "../build/public/");
|
||||||
@ -20,7 +24,7 @@ const config = {
|
|||||||
output: {
|
output: {
|
||||||
path: BUILD_DIR,
|
path: BUILD_DIR,
|
||||||
filename: "[contenthash]-app.js",
|
filename: "[contenthash]-app.js",
|
||||||
assetModuleFilename: "[hash]-[name][ext][query]",
|
assetModuleFilename: "[contenthash]-[name][ext][query]",
|
||||||
},
|
},
|
||||||
optimization: {},
|
optimization: {},
|
||||||
module: {
|
module: {
|
||||||
@ -35,9 +39,18 @@ const config = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/i,
|
||||||
|
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
use: ["style-loader", "css-loader", "sass-loader", "postcss-loader"],
|
use: [
|
||||||
|
MiniCssExtractPlugin.loader,
|
||||||
|
"css-loader",
|
||||||
|
"sass-loader",
|
||||||
|
"postcss-loader",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|jpg|svg|ico)$/,
|
test: /\.(png|jpg|svg|ico)$/,
|
||||||
@ -62,12 +75,13 @@ const config = {
|
|||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: path.join(SRC_DIR, "index.html"),
|
template: path.join(SRC_DIR, "index.html"),
|
||||||
|
favicon: path.join(SRC_DIR, "img/favicon.ico"),
|
||||||
}),
|
}),
|
||||||
new WebpackPwaManifest({
|
new WebpackPwaManifest({
|
||||||
fingerprints: true,
|
fingerprints: true,
|
||||||
inject: true,
|
inject: true,
|
||||||
ios: {
|
ios: {
|
||||||
"apple-mobile-web-app-status-bar-style": "default",
|
"apple-mobile-web-app-status-bar-style": "#4e5d6c",
|
||||||
"apple-mobile-web-app-title": "Canapé",
|
"apple-mobile-web-app-title": "Canapé",
|
||||||
},
|
},
|
||||||
name: "Canapé",
|
name: "Canapé",
|
||||||
@ -84,6 +98,11 @@ const config = {
|
|||||||
src: path.resolve(__dirname, "img/android-chrome-512x512.png"),
|
src: path.resolve(__dirname, "img/android-chrome-512x512.png"),
|
||||||
sizes: [96, 128, 192, 256, 384, 512],
|
sizes: [96, 128, 192, 256, 384, 512],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
src: path.resolve(__dirname, "img/maskable_icon_x512.png"),
|
||||||
|
size: "512x512",
|
||||||
|
purpose: "maskable",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
src: path.resolve(__dirname, "img/apple-touch-icon.png"),
|
src: path.resolve(__dirname, "img/apple-touch-icon.png"),
|
||||||
sizes: [80, 120, 152, 167, 180],
|
sizes: [80, 120, 152, 167, 180],
|
||||||
@ -91,6 +110,13 @@ const config = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: "[contenthash].css",
|
||||||
|
}),
|
||||||
|
new PurgeCSSPlugin({
|
||||||
|
paths: () => glob.sync(`${SRC_DIR}/**/*`, { nodir: true }),
|
||||||
|
}),
|
||||||
|
new WorkboxPlugin.GenerateSW(),
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".js"],
|
extensions: [".js"],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user