mirror of
https://github.com/mediacms-io/mediacms.git
synced 2024-11-21 15:53:21 +01:00
Frontent dev env (#247)
* Added frontend development files/environment * More items-categories related removals * Improvements in pages templates (inc. static pages) * Improvements in video player * Added empty home page message + cta * Updates in media, playlist and management pages * Improvements in material icons font loading * Replaced media & playlists links in frontend dev-env * frontend package version update * chnaged frontend dev url port * static files update * Changed default position of theme switcher * enabled frontend docker container
This commit is contained in:
parent
060bb45725
commit
aa6520daac
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
npm-debug.log
|
@ -1,18 +1,18 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
# frontend:
|
||||
# image: node:14
|
||||
# volumes:
|
||||
# - ${PWD}/frontend:/home/mediacms.io/mediacms/frontend/
|
||||
# working_dir: /home/mediacms.io/mediacms/frontend/
|
||||
# command: bash -c "npm install && npm run start"
|
||||
# env_file:
|
||||
# - ${PWD}/frontend/.env
|
||||
# ports:
|
||||
# - "8097:8097"
|
||||
# depends_on:
|
||||
# - web
|
||||
frontend:
|
||||
image: node:14
|
||||
volumes:
|
||||
- ${PWD}/frontend:/home/mediacms.io/mediacms/frontend/
|
||||
working_dir: /home/mediacms.io/mediacms/frontend/
|
||||
command: bash -c "npm install && npm run start"
|
||||
env_file:
|
||||
- ${PWD}/frontend/.env
|
||||
ports:
|
||||
- "8088:8088"
|
||||
depends_on:
|
||||
- web
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
@ -60,7 +60,7 @@ services:
|
||||
image: "redis:alpine"
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli","ping"]
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
retries: 3
|
||||
|
12
frontend/.babelrc
Executable file
12
frontend/.babelrc
Executable file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/react", ["@babel/env", {
|
||||
"modules": false,
|
||||
"useBuiltIns": "usage",
|
||||
"corejs": 3,
|
||||
"targets": {
|
||||
"browsers": ["defaults"]
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
12
frontend/.env
Normal file
12
frontend/.env
Normal file
@ -0,0 +1,12 @@
|
||||
MEDIACMS_ID=mediacms-frontend
|
||||
MEDIACMS_TITLE=MediaCMS Frontend
|
||||
|
||||
MEDIACMS_URL=http://localhost
|
||||
MEDIACMS_API=http://localhost/api/v1
|
||||
|
||||
MEDIACMS_USER_IS_ADMIN=true
|
||||
MEDIACMS_USER_IS_ANONYMOUS=false
|
||||
|
||||
MEDIACMS_USER_USERNAME=admin
|
||||
MEDIACMS_USER_NAME=Admin
|
||||
MEDIACMS_USER_THUMB=http://localhost/media/userlogos/user.jpg
|
131
frontend/.gitignore
vendored
Executable file
131
frontend/.gitignore
vendored
Executable file
@ -0,0 +1,131 @@
|
||||
.DS_Store
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
!modules/**/*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env.development
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
# dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# System files
|
||||
.fuse_hidden*
|
||||
|
||||
# Exports
|
||||
/build
|
||||
/dist
|
||||
|
||||
# Packages dev files
|
||||
# /packages/**/package-lock.json
|
||||
|
||||
# Other
|
||||
*playground*
|
1
frontend/.prettierignore
Normal file
1
frontend/.prettierignore
Normal file
@ -0,0 +1 @@
|
||||
config/templates/*.ejs
|
5
frontend/.prettierrc
Normal file
5
frontend/.prettierrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
}
|
3
frontend/.vscode/settings.json
vendored
Normal file
3
frontend/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"editor.formatOnSave": true
|
||||
}
|
29
frontend/README.md
Normal file
29
frontend/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
# MediaCMS Web Client (demo)
|
||||
|
||||
### **Requirements**
|
||||
|
||||
- nodejs: version >= 14.17.0
|
||||
|
||||
---
|
||||
|
||||
### **Installation**
|
||||
|
||||
npm install
|
||||
|
||||
---
|
||||
|
||||
### **Development**
|
||||
|
||||
npm run start
|
||||
|
||||
Open in browser: [http://localhost:8088](http://localhost:8088)
|
||||
|
||||
---
|
||||
|
||||
### **Build**
|
||||
|
||||
npm run dist
|
||||
|
||||
Generates the folder "**_frontend/dist_**".
|
||||
|
||||
Copy folders and files from "**_frontend/dist/static_**" into "**_static_**".
|
44
frontend/config/mediacms.config.html.js
Executable file
44
frontend/config/mediacms.config.html.js
Executable file
@ -0,0 +1,44 @@
|
||||
module.exports = {
|
||||
head: {
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ content: 'ie=edge', 'http-equiv': 'x-ua-compatible' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ name: 'theme-color', content: '#fafafa' },
|
||||
{ name: 'msapplication-TileColor', content: '#fafafa' },
|
||||
{ name: 'msapplication-config', content: 'favicons/browserconfig.xml' },
|
||||
],
|
||||
links: [
|
||||
/**
|
||||
* Manifest file link.
|
||||
*/
|
||||
{ rel: 'manifest', href: 'static/favicons/site.webmanifest' },
|
||||
/**
|
||||
* Favicon links.
|
||||
*/
|
||||
{ rel: 'apple-touch-icon', sizes: '180x180', href: 'static/favicons/apple-touch-icon.png' },
|
||||
{ rel: 'icon', type: 'image/png', sizes: '32x32', href: 'static/favicons/favicon-32x32.png' },
|
||||
{ rel: 'icon', type: 'image/png', sizes: '16x16', href: 'static/favicons/favicon-16x16.png' },
|
||||
{ rel: 'mask-icon', href: 'static/favicons/safari-pinned-tab.svg', color: '#fafafa' },
|
||||
{ rel: 'shortcut icon', href: 'static/favicons/favicon.ico' },
|
||||
/**
|
||||
* Stylesheet links
|
||||
*/
|
||||
{ rel: 'preload', href: 'static/css/_extra.css', as: 'style' },
|
||||
{ rel: 'stylesheet', href: 'static/css/_extra.css' },
|
||||
|
||||
// 'https://fonts.googleapis.com/icon?family=Material+Icons',
|
||||
{ rel: 'preload', href: 'static/lib/material-icons/material-icons.css', as: 'style' },
|
||||
{ rel: 'stylesheet', href: 'static/lib/material-icons/material-icons.css' },
|
||||
|
||||
// 'https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i,700,700i&display=swap
|
||||
{ rel: 'preload', href: 'static/lib/gfonts/gfonts.css', as: 'style' },
|
||||
{ rel: 'stylesheet', href: 'static/lib/gfonts/gfonts.css' },
|
||||
],
|
||||
scripts: [],
|
||||
},
|
||||
body: {
|
||||
scripts: [],
|
||||
snippet: '',
|
||||
},
|
||||
};
|
31
frontend/config/mediacms.config.js
Executable file
31
frontend/config/mediacms.config.js
Executable file
@ -0,0 +1,31 @@
|
||||
const path = require('path');
|
||||
|
||||
const rootDir = '..';
|
||||
const srcDir = rootDir + '/src';
|
||||
const configDir = srcDir + '/templates/config';
|
||||
const coreConfigDir = configDir + '/core';
|
||||
const installConfigDir = configDir + '/installation';
|
||||
|
||||
module.exports = {
|
||||
src: path.resolve(__dirname, srcDir),
|
||||
build: path.resolve(__dirname, rootDir),
|
||||
html: require('./mediacms.config.html.js'),
|
||||
pages: require('./mediacms.config.pages.js'),
|
||||
window: {
|
||||
MediaCMS: {
|
||||
api: require(coreConfigDir + '/api.config.js'),
|
||||
url: require(coreConfigDir + '/url.config.js'),
|
||||
user: require(coreConfigDir + '/user.config.js'),
|
||||
site: require(installConfigDir + '/site.config.js'),
|
||||
pages: require(installConfigDir + '/pages.config.js'),
|
||||
contents: require(installConfigDir + '/contents.config.js'),
|
||||
features: require(installConfigDir + '/features.config.js'),
|
||||
/*notifications: [
|
||||
'Message one text',
|
||||
'Message two text',
|
||||
'Message three text'
|
||||
],*/
|
||||
},
|
||||
},
|
||||
postcssConfigFile: path.resolve(__dirname, './postcss.config.js'),
|
||||
};
|
268
frontend/config/mediacms.config.pages.js
Normal file
268
frontend/config/mediacms.config.pages.js
Normal file
@ -0,0 +1,268 @@
|
||||
const templates = require('./mediacms.config.templates');
|
||||
|
||||
const DEV_SAMPLE_DATA = {
|
||||
profileId: process.env.MEDIACMS_USER_USERNAME,
|
||||
media: {
|
||||
videoId: process.env.MEDIACMS_VIDEO_ID,
|
||||
audioId: process.env.MEDIACMS_AUDIO_ID,
|
||||
imageId: process.env.MEDIACMS_IMAGE_ID,
|
||||
pdfId: process.env.MEDIACMS_PDF_ID,
|
||||
},
|
||||
playlistId: process.env.MEDIACMS_PLAYLIST_ID,
|
||||
};
|
||||
|
||||
const formatPage = (page) => {
|
||||
const pageContentId = 'page-' + page.id;
|
||||
const filename = page.filename ? page.filename : ('home' === page.id ? 'index' : page.id) + '.html';
|
||||
const render = page.renderer
|
||||
? page.renderer
|
||||
: page.component
|
||||
? templates.renderPageContent({ page: { id: pageContentId, component: page.component } })
|
||||
: undefined;
|
||||
const headLinks = [
|
||||
{ rel: 'preload', href: './static/lib/video-js/7.7.5/video.min.js', as: 'script' },
|
||||
...(page.headLinks ? page.headLinks : []),
|
||||
];
|
||||
const bodyScripts = [
|
||||
{ src: './static/lib/video-js/7.7.5/video.min.js' },
|
||||
...(page.bodyScripts ? page.bodyScripts : []),
|
||||
];
|
||||
|
||||
const ret = {
|
||||
buildExclude: !!page.buildExclude,
|
||||
title: page.title,
|
||||
filename,
|
||||
render,
|
||||
html: {
|
||||
head: {
|
||||
links: headLinks,
|
||||
},
|
||||
body: {
|
||||
scripts: bodyScripts,
|
||||
snippet: page.snippet || templates.htmlBodySnippet({ id: pageContentId }),
|
||||
},
|
||||
},
|
||||
window: { MediaCMS: page.global ? { ...page.global } : {} },
|
||||
};
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
const formatPageData = (page) => {
|
||||
return formatPage({
|
||||
...page,
|
||||
});
|
||||
};
|
||||
|
||||
const formatStaticPageData = (page) => {
|
||||
const pageContentId = 'page-' + page.id;
|
||||
return formatPage({
|
||||
...page,
|
||||
renderer: page.renderer
|
||||
? page.renderer
|
||||
: page.component
|
||||
? templates.renderPageStaticContent({ page: { id: pageContentId, component: page.component } })
|
||||
: undefined,
|
||||
});
|
||||
};
|
||||
|
||||
const PAGES = {
|
||||
base: {
|
||||
id: 'base',
|
||||
title: 'Layout base',
|
||||
renderer: templates.renderBase(),
|
||||
},
|
||||
index: { id: 'home', title: 'Home', component: 'HomePage' },
|
||||
search: { id: 'search', title: 'Search results', component: 'SearchPage' },
|
||||
latest: { id: 'latest', title: 'Recent uploads', component: 'LatestMediaPage' },
|
||||
featured: { id: 'featured', title: 'Featured', component: 'FeaturedMediaPage' },
|
||||
recommended: { id: 'recommended', title: 'Recommended', component: 'RecommendedMediaPage' },
|
||||
members: { id: 'members', title: 'Members', component: 'MembersPage' },
|
||||
history: { id: 'history', title: 'History', component: 'HistoryPage' },
|
||||
liked: { id: 'liked', title: 'Liked media', component: 'LikedMediaPage' },
|
||||
tags: { id: 'tags', title: 'Tags', component: 'TagsPage' },
|
||||
categories: { id: 'categories', title: 'Categories', component: 'CategoriesPage' },
|
||||
'manage-media': { id: 'manage-media', title: 'Manage media', component: 'ManageMediaPage' },
|
||||
'manage-users': { id: 'manage-users', title: 'Manage users', component: 'ManageUsersPage' },
|
||||
'manage-comments': { id: 'manage-comments', title: 'Manage comments', component: 'ManageCommentsPage' },
|
||||
'add-media': {
|
||||
id: 'add-media',
|
||||
title: 'Add media',
|
||||
renderer: templates.renderAddMediaPageContent(),
|
||||
snippet: templates.htmlBodySnippetAddMediaPage(),
|
||||
headLinks: [{ rel: 'preload', href: './static/lib/file-uploader/5.13.0/fine-uploader.min.js', as: 'script' }],
|
||||
bodyScripts: [{ src: './static/lib/file-uploader/5.13.0/fine-uploader.min.js' }],
|
||||
},
|
||||
embed: {
|
||||
id: 'embed',
|
||||
title: 'Embedded player',
|
||||
renderer: templates.renderEmbedPageContent({ page: { id: 'page-embed', component: 'EmbedPage' } }),
|
||||
snippet: templates.htmlBodySnippetEmbedPage({ id: 'page-embed' }),
|
||||
global: { mediaId: DEV_SAMPLE_DATA.media.videoId },
|
||||
},
|
||||
media: {
|
||||
id: 'media',
|
||||
title: 'Media',
|
||||
component: 'MediaPage',
|
||||
global: { mediaId: DEV_SAMPLE_DATA.media.videoId },
|
||||
},
|
||||
'media-video': {
|
||||
buildExclude: true,
|
||||
id: 'media-video',
|
||||
title: 'Media - Video',
|
||||
component: 'MediaVideoPage',
|
||||
global: { mediaId: DEV_SAMPLE_DATA.media.videoId },
|
||||
},
|
||||
'media-audio': {
|
||||
buildExclude: true,
|
||||
id: 'media-audio',
|
||||
title: 'Media - Audio',
|
||||
component: 'MediaAudioPage',
|
||||
global: { mediaId: DEV_SAMPLE_DATA.media.audioId },
|
||||
},
|
||||
'media-image': {
|
||||
buildExclude: true,
|
||||
id: 'media-image',
|
||||
title: 'Media - Image',
|
||||
component: 'MediaImagePage',
|
||||
global: { mediaId: DEV_SAMPLE_DATA.media.imageId },
|
||||
},
|
||||
'media-pdf': {
|
||||
buildExclude: true,
|
||||
id: 'media-pdf',
|
||||
title: 'Media - Pdf',
|
||||
component: 'MediaPdfPage',
|
||||
global: { mediaId: DEV_SAMPLE_DATA.media.pdfId },
|
||||
},
|
||||
playlist: {
|
||||
id: 'playlist',
|
||||
title: 'Playlist',
|
||||
component: 'PlaylistPage',
|
||||
global: { playlistId: DEV_SAMPLE_DATA.playlistId },
|
||||
},
|
||||
'profile-media': {
|
||||
id: 'profile-media',
|
||||
title: 'Profile - Media',
|
||||
component: 'ProfileMediaPage',
|
||||
global: { profileId: DEV_SAMPLE_DATA.profileId },
|
||||
},
|
||||
'profile-about': {
|
||||
id: 'profile-about',
|
||||
title: 'Profile - About',
|
||||
component: 'ProfileAboutPage',
|
||||
global: { profileId: DEV_SAMPLE_DATA.profileId },
|
||||
},
|
||||
'profile-playlists': {
|
||||
id: 'profile-playlists',
|
||||
title: 'Profile - Playlist',
|
||||
component: 'ProfilePlaylistsPage',
|
||||
global: { profileId: DEV_SAMPLE_DATA.profileId },
|
||||
},
|
||||
};
|
||||
|
||||
const STATIC_PAGES = {
|
||||
error: {
|
||||
buildExclude: true,
|
||||
id: 'error',
|
||||
title: 'Error',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.errorPage(),
|
||||
},
|
||||
about: {
|
||||
id: 'about',
|
||||
title: 'About',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.aboutPage(),
|
||||
},
|
||||
terms: {
|
||||
buildExclude: true,
|
||||
id: 'terms',
|
||||
title: 'Terms',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.termsPage(),
|
||||
},
|
||||
};
|
||||
|
||||
const DEV_ONLY_STATIC_PAGES = {
|
||||
'add-media-template': {
|
||||
buildExclude: true,
|
||||
id: 'add-media-template',
|
||||
title: 'Add media - Template',
|
||||
renderer: templates.renderAddMediaPageContent(),
|
||||
snippet: templates.static.addMediaPageTemplate(),
|
||||
headLinks: [{ rel: 'preload', href: './static/lib/file-uploader/5.13.0/fine-uploader.min.js', as: 'script' }],
|
||||
bodyScripts: [{ src: './static/lib/file-uploader/5.13.0/fine-uploader.min.js' }],
|
||||
},
|
||||
'edit-media': {
|
||||
buildExclude: true,
|
||||
id: 'edit-media',
|
||||
title: 'Edit media',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.editMediaPage(),
|
||||
},
|
||||
'edit-channel': {
|
||||
buildExclude: true,
|
||||
id: 'edit-channel',
|
||||
title: 'Edit channel',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.editChannelPage(),
|
||||
},
|
||||
'edit-profile': {
|
||||
buildExclude: true,
|
||||
id: 'edit-profile',
|
||||
title: 'Edit profile',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.editProfilePage(),
|
||||
},
|
||||
signin: {
|
||||
buildExclude: true,
|
||||
id: 'signin',
|
||||
title: 'Sign in',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.signinPage(),
|
||||
},
|
||||
signout: {
|
||||
buildExclude: true,
|
||||
id: 'signout',
|
||||
title: 'Sign out',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.signoutPage(),
|
||||
},
|
||||
register: {
|
||||
buildExclude: true,
|
||||
id: 'register',
|
||||
title: 'Register',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.registerPage(),
|
||||
},
|
||||
'reset-password': {
|
||||
buildExclude: true,
|
||||
id: 'reset-password',
|
||||
title: 'Reset password',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.resetPasswordPage(),
|
||||
},
|
||||
contact: {
|
||||
buildExclude: true,
|
||||
id: 'contact',
|
||||
title: 'Contact us',
|
||||
renderer: templates.renderBase(),
|
||||
snippet: templates.static.contactPage(),
|
||||
},
|
||||
};
|
||||
|
||||
const pages = {};
|
||||
|
||||
for (let k in PAGES) {
|
||||
pages[k] = formatPageData(PAGES[k]);
|
||||
}
|
||||
|
||||
for (let k in STATIC_PAGES) {
|
||||
pages[k] = formatStaticPageData(STATIC_PAGES[k]);
|
||||
}
|
||||
|
||||
for (let k in DEV_ONLY_STATIC_PAGES) {
|
||||
pages[k] = formatStaticPageData(DEV_ONLY_STATIC_PAGES[k]);
|
||||
}
|
||||
|
||||
module.exports = pages;
|
45
frontend/config/mediacms.config.templates.js
Normal file
45
frontend/config/mediacms.config.templates.js
Normal file
@ -0,0 +1,45 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const ejs = require('ejs');
|
||||
|
||||
const templatesPath = path.join(__dirname, './templates');
|
||||
const staticTemplatesPath = path.join(__dirname, './templates/static');
|
||||
|
||||
const compileTmpl = (filename) =>
|
||||
ejs.compile(fs.readFileSync(path.join(templatesPath, filename), 'utf8'), {
|
||||
root: [templatesPath],
|
||||
filename: path.join(templatesPath, filename),
|
||||
outputFunctionName: 'echo',
|
||||
});
|
||||
|
||||
const compileStaticTmpl = (filename) =>
|
||||
ejs.compile(fs.readFileSync(path.join(staticTemplatesPath, filename), 'utf8'), {
|
||||
root: [staticTemplatesPath],
|
||||
filename: path.join(staticTemplatesPath, filename),
|
||||
outputFunctionName: 'echo',
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
htmlBodySnippet: compileTmpl('htmlBodySnippet.ejs'),
|
||||
htmlBodySnippetEmbedPage: compileTmpl('htmlBodySnippetEmbedPage.ejs'),
|
||||
htmlBodySnippetAddMediaPage: compileTmpl('htmlBodySnippetAddMediaPage.ejs'),
|
||||
renderBase: compileTmpl('renderBase.ejs'),
|
||||
renderPageContent: compileTmpl('renderPageContent.ejs'),
|
||||
renderPageStaticContent: compileTmpl('renderPageStaticContent.ejs'),
|
||||
renderEmbedPageContent: compileTmpl('renderEmbedPageContent.ejs'),
|
||||
renderAddMediaPageContent: compileTmpl('renderAddMediaPageContent.ejs'),
|
||||
static: {
|
||||
errorPage: compileStaticTmpl('errorPage.html'),
|
||||
aboutPage: compileStaticTmpl('aboutPage.html'),
|
||||
termsPage: compileStaticTmpl('termsPage.html'),
|
||||
contactPage: compileStaticTmpl('contactPage.html'),
|
||||
signinPage: compileStaticTmpl('signinPage.html'),
|
||||
signoutPage: compileStaticTmpl('signoutPage.html'),
|
||||
registerPage: compileStaticTmpl('registerPage.html'),
|
||||
resetPasswordPage: compileStaticTmpl('resetPasswordPage.html'),
|
||||
editMediaPage: compileStaticTmpl('editMediaPage.html'),
|
||||
editChannelPage: compileStaticTmpl('editChannelPage.html'),
|
||||
editProfilePage: compileStaticTmpl('editProfilePage.html'),
|
||||
addMediaPageTemplate: compileStaticTmpl('addMediaPageTemplate.html'),
|
||||
},
|
||||
};
|
10
frontend/config/postcss.config.js
Executable file
10
frontend/config/postcss.config.js
Executable file
@ -0,0 +1,10 @@
|
||||
module.exports = (ctx) => {
|
||||
const ret = {
|
||||
map: ctx.env === 'development' ? ctx.map : false,
|
||||
plugins: {
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
||||
return ret;
|
||||
};
|
6
frontend/config/templates/htmlBodySnippet.ejs
Executable file
6
frontend/config/templates/htmlBodySnippet.ejs
Executable file
@ -0,0 +1,6 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<% if (id) { %><div id="<%= id %>"></div><% } %>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
65
frontend/config/templates/htmlBodySnippetAddMediaPage.ejs
Executable file
65
frontend/config/templates/htmlBodySnippetAddMediaPage.ejs
Executable file
@ -0,0 +1,65 @@
|
||||
<div id="add-media-page">
|
||||
|
||||
<div class="page-container">
|
||||
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
|
||||
<div class="page-main-wrap">
|
||||
|
||||
<main class="page-main">
|
||||
<div class="page-main-inner">
|
||||
|
||||
<div class="media-uploader-wrap">
|
||||
|
||||
<div class="media-uploader-top-wrap">
|
||||
|
||||
<div class="media-uploader-top-left-wrap">
|
||||
<h1>Upload media files</h1>
|
||||
</div>
|
||||
|
||||
<div class="media-uploader-top-right-wrap"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/template" id="qq-template"> <div class="media-uploader-bottom-wrap qq-uploader-selector"> <div class="media-uploader-bottom-left-wrap"> <div class="media-drag-drop-wrap"> <div class="media-drag-drop-inner" qq-drop-area-text="Drop files here"> <div class="media-drag-drop-content"> <div class="media-drag-drop-content-inner"> <span><i class="material-icons">cloud_upload</i></span> <span>Drag and drop files</span> <span>or</span> <span class="browse-files-btn-wrap"><span class="qq-upload-button-selector">Browse your files</span></span><div class="qq-upload-drop-area-selector media-dropzone" qq-hide-dropzone><span class="qq-upload-drop-area-text-selector"></span></div> </div></div></div></div></div><div class="media-uploader-bottom-right-wrap"> <ul class="media-upload-items-list qq-upload-list-selector"> <li> <div class="media-upload-item-main"> <div class="media-upload-item-thumb"> <img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale alt=""/> <span class="media-upload-item-spinner qq-upload-spinner-selector"><i class="material-icons">autorenew</i></span> <button type="button" class="qq-upload-retry-selector retry-media-upload-item" aria-label="Retry"><i class="material-icons">refresh</i> Retry</button> </div><div class="media-upload-item-details"> <div class="media-upload-item-name"> <span class="media-upload-item-filename qq-upload-file-selector"></span> <input class="media-upload-item-filename-input qq-edit-filename-selector" tab-index="0" type="text"/> </div><div class="media-upload-item-details-bottom"> <div class="media-upload-item-progress-bar-container qq-progress-bar-container-selector"> <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="media-upload-item-progress-bar qq-progress-bar-selector"></div></div><span class="media-upload-item-upload-size qq-upload-size-selector"></span> <span role="status" class="media-upload-item-status-text qq-upload-status-text-selector"></span> </div><div class="media-upload-item-top-actions"> <span class="filename-edit qq-edit-filename-icon-selector" aria-label="Edit filename">Edit filename <i class="material-icons">create</i></span> <button type="button" class="delete-media-upload-item qq-upload-delete-selector" aria-label="Delete">Delete <i class="material-icons">delete</i></button> <button type="button" class="cancel-media-upload-item qq-upload-cancel-selector" aria-label="Cancel">Cancel <i class="material-icons">cancel</i></button> </div><div class="media-upload-item-bottom-actions"> <button type="button" class="continue-media-upload-item qq-upload-continue-selector" aria-label="Continue"><i class="material-icons">play_circle_outline</i> Continue</button> <button type="button" class="pause-media-upload-item qq-upload-pause-selector" aria-label="Pause"><i class="material-icons">pause_circle_outline</i> Pause</button> </div></div></div></li></ul> <dialog class="qq-alert-dialog-selector"> <div class="qq-dialog-message-selector"></div><div class="qq-dialog-buttons"> <button type="button" class="qq-cancel-button-selector">Close</button> </div></dialog> <dialog class="qq-confirm-dialog-selector"> <div class="qq-dialog-message-selector"></div><div class="qq-dialog-buttons"> <button type="button" class="qq-cancel-button-selector">No</button> <button type="button" class="qq-ok-button-selector">Yes</button> </div></dialog> <dialog class="qq-prompt-dialog-selector"> <div class="qq-dialog-message-selector"></div><input type="text"> <div class="qq-dialog-buttons"> <button type="button" class="qq-cancel-button-selector">Cancel</button> <button type="button" class="qq-ok-button-selector">Ok</button> </div></dialog> </div></div></script>
|
||||
|
||||
<div class="media-uploader"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script type='text/javascript'>
|
||||
|
||||
function csrfToken(){var a,b=null;if(document.cookie&&""!==document.cookie){var c=document.cookie.split(";");for(a=0;a<c.length;){var d=c[a].trim();if("csrftoken="===d.substring(0,10)){b=decodeURIComponent(d.substring(10));break}a+=1}}return b};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
var default_concurrent_chunked_uploader = new qq.FineUploader({
|
||||
debug: true,
|
||||
element: document.querySelector('.media-uploader'),
|
||||
request: {
|
||||
endpoint: '/fu/upload/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': csrfToken('csrftoken'),
|
||||
},
|
||||
},
|
||||
retry: {
|
||||
enableAuto: true,
|
||||
},
|
||||
chunking: {
|
||||
enabled: true,
|
||||
concurrent: {
|
||||
enabled: true,
|
||||
},
|
||||
success: {
|
||||
endpoint: '/fu/upload/?done',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
3
frontend/config/templates/htmlBodySnippetEmbedPage.ejs
Executable file
3
frontend/config/templates/htmlBodySnippetEmbedPage.ejs
Executable file
@ -0,0 +1,3 @@
|
||||
<div class="page-main-wrap">
|
||||
<% if (id) { %><div id="<%= id %>"></div><% } %>
|
||||
</div>
|
5
frontend/config/templates/renderAddMediaPageContent.ejs
Executable file
5
frontend/config/templates/renderAddMediaPageContent.ejs
Executable file
@ -0,0 +1,5 @@
|
||||
import { renderPage } from './static/js/utils/renderer';
|
||||
|
||||
import './static/css/AddMediaPage.scss';
|
||||
|
||||
renderPage();
|
3
frontend/config/templates/renderBase.ejs
Executable file
3
frontend/config/templates/renderBase.ejs
Executable file
@ -0,0 +1,3 @@
|
||||
import { renderPage } from './static/js/utils/renderer';
|
||||
|
||||
renderPage();
|
15
frontend/config/templates/renderEmbedPageContent.ejs
Executable file
15
frontend/config/templates/renderEmbedPageContent.ejs
Executable file
@ -0,0 +1,15 @@
|
||||
<% if (page) { %>
|
||||
|
||||
import { renderEmbedPage } from './static/js/utils/renderer';
|
||||
|
||||
<% if (page.component) { %>
|
||||
|
||||
import { <%= page.component %> } from './static/js/pages/<%= page.component %>';
|
||||
|
||||
<% if (page.id) { %>
|
||||
renderEmbedPage( '<%= page.id %>', <%= page.component %> );
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
15
frontend/config/templates/renderPageContent.ejs
Executable file
15
frontend/config/templates/renderPageContent.ejs
Executable file
@ -0,0 +1,15 @@
|
||||
<% if (page) { %>
|
||||
|
||||
import { renderPage } from './static/js/utils/renderer';
|
||||
|
||||
<% if (page.component) { %>
|
||||
|
||||
import { <%= page.component %> } from './static/js/pages/<%= page.component %>';
|
||||
|
||||
<% if (page.id) { %>
|
||||
renderPage( '<%= page.id %>', <%= page.component %> );
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
15
frontend/config/templates/renderPageStaticContent.ejs
Executable file
15
frontend/config/templates/renderPageStaticContent.ejs
Executable file
@ -0,0 +1,15 @@
|
||||
<% if (page) { %>
|
||||
|
||||
import { renderPage } from './static/js/utils/renderer';
|
||||
|
||||
<% if (page.component) { %>
|
||||
|
||||
import { <%= page.component %> } from './static/js/static-pages/<%= page.component %>';
|
||||
|
||||
<% if (page.id) { %>
|
||||
renderPage( '<%= page.id %>', <%= page.component %> );
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
18
frontend/config/templates/static/aboutPage.html
Executable file
18
frontend/config/templates/static/aboutPage.html
Executable file
@ -0,0 +1,18 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="custom-page-wrapper">
|
||||
<h2>About</h2>
|
||||
<hr />
|
||||
<p>
|
||||
<a href="https://mediacms.io">MediaCMS</a> is a modern, fully featured open source video and media CMS. It is
|
||||
developed to meet the needs of modern web platforms for viewing and sharing media.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
144
frontend/config/templates/static/addMediaPageTemplate.html
Executable file
144
frontend/config/templates/static/addMediaPageTemplate.html
Executable file
@ -0,0 +1,144 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="media-uploader-wrap">
|
||||
<div class="media-uploader-top-wrap">
|
||||
<div class="media-uploader-top-left-wrap">
|
||||
<h1>Upload media files</h1>
|
||||
</div>
|
||||
<div class="media-uploader-top-right-wrap"></div>
|
||||
</div>
|
||||
<div class="media-uploader">
|
||||
<div class="media-uploader-bottom-wrap">
|
||||
<div class="media-uploader-bottom-left-wrap">
|
||||
<div class="media-drag-drop-wrap">
|
||||
<div class="media-drag-drop-inner">
|
||||
<div class="media-drag-drop-content">
|
||||
<div class="media-drag-drop-content-inner">
|
||||
<span><i class="material-icons">cloud_upload</i></span>
|
||||
<span>Drag and drop files</span>
|
||||
<span>or</span>
|
||||
<span class="browse-files-btn-wrap">
|
||||
<span
|
||||
class="qq-upload-button-selector"
|
||||
style="position: relative; overflow: hidden; direction: ltr"
|
||||
>Browse your files<input
|
||||
qq-button-id="9523a4a3-6688-40a5-b01d-7c72a79c7bcb"
|
||||
title="file input"
|
||||
multiple=""
|
||||
type="file"
|
||||
name="qqfile"
|
||||
style="
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
font-family: Arial;
|
||||
font-size: 118px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
"
|
||||
/></span>
|
||||
</span>
|
||||
<div class="qq-upload-drop-area-selector media-dropzone" qq-hide-dropzone>
|
||||
<span class="qq-upload-drop-area-text-selector"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-uploader-bottom-right-wrap">
|
||||
<ul class="media-upload-items-list qq-upload-list-selector">
|
||||
<li>
|
||||
<div class="media-upload-item-main">
|
||||
<div class="media-upload-item-thumb">
|
||||
<img class="qq-thumbnail-selector" alt="" />
|
||||
<span class="media-upload-item-spinner qq-upload-spinner-selector"
|
||||
><i class="material-icons">autorenew</i></span
|
||||
>
|
||||
<button type="button" class="qq-upload-retry-selector retry-media-upload-item" aria-label="Retry">
|
||||
<i class="material-icons">refresh</i> Retry
|
||||
</button>
|
||||
</div>
|
||||
<div class="media-upload-item-details">
|
||||
<div class="media-upload-item-name">
|
||||
<span class="media-upload-item-filename qq-upload-file-selector" title="">File #1</span>
|
||||
<input
|
||||
class="
|
||||
media-upload-item-filename-input
|
||||
qq-edit-filename-selector qq-edit-filename-icon-selector
|
||||
"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value="File #1"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-upload-item-details-bottom">
|
||||
<div class="media-upload-item-progress-bar-container qq-progress-bar-container-selector">
|
||||
<div
|
||||
role="progressbar"
|
||||
aria-valuenow="80"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
class="media-upload-item-progress-bar qq-progress-bar-selector"
|
||||
style="width: 80%"
|
||||
></div>
|
||||
</div>
|
||||
<span class="media-upload-item-upload-size qq-upload-size-selector">80% of 7.5MB</span>
|
||||
<span role="status" class="media-upload-item-status-text qq-upload-status-text-selector"
|
||||
>Retrying 3/3...</span
|
||||
>
|
||||
</div>
|
||||
<div class="media-upload-item-top-actions">
|
||||
<span class="filename-edit qq-edit-filename-icon-selector" aria-label="Edit filename"
|
||||
>Edit filename <i class="material-icons">create</i></span
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="delete-media-upload-item qq-upload-delete-selector"
|
||||
aria-label="Delete"
|
||||
>
|
||||
Delete <i class="material-icons">delete</i>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="cancel-media-upload-item qq-upload-cancel-selector"
|
||||
aria-label="Cancel"
|
||||
>
|
||||
Cancel <i class="material-icons">cancel</i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="media-upload-item-bottom-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="continue-media-upload-item qq-upload-continue-selector"
|
||||
aria-label="Continue"
|
||||
>
|
||||
<i class="material-icons">play_circle_outline</i> Continue
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="pause-media-upload-item qq-upload-pause-selector"
|
||||
aria-label="Pause"
|
||||
>
|
||||
<i class="material-icons">pause_circle_outline</i> Pause
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
27
frontend/config/templates/static/contactPage.html
Executable file
27
frontend/config/templates/static/contactPage.html
Executable file
@ -0,0 +1,27 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="user-action-form-wrap">
|
||||
<div class="user-action-form-inner">
|
||||
<h1>Contact us</h1>
|
||||
<form enctype="multipart/form-data" action="" method="post" class="post-form">
|
||||
<p>
|
||||
<label for="id_from_email">Your email:</label>
|
||||
<input type="email" name="from_email" required="" id="id_from_email" />
|
||||
</p>
|
||||
<p><label for="id_name">Your name:</label> <input type="text" name="name" id="id_name" /></p>
|
||||
<p>
|
||||
<label for="id_message">Please add your message here and submit:</label>
|
||||
<textarea name="message" cols="40" rows="10" required="" id="id_message"></textarea>
|
||||
</p>
|
||||
<button class="primaryAction" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
30
frontend/config/templates/static/editChannelPage.html
Executable file
30
frontend/config/templates/static/editChannelPage.html
Executable file
@ -0,0 +1,30 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="user-action-form-wrap">
|
||||
<div class="user-action-form-inner">
|
||||
<h1>Edit Channel</h1>
|
||||
|
||||
<form enctype="multipart/form-data" action="" method="post" class="post-form">
|
||||
<div id="div_id_banner_logo" class="control-group">
|
||||
<label for="id_banner_logo" class="control-label"> Banner logo </label>
|
||||
<div class="controls">
|
||||
Currently: <a href="#">*****</a>
|
||||
<input type="checkbox" name="banner_logo-clear" id="banner_logo-clear_id" />
|
||||
<label for="banner_logo-clear_id">Clear</label><br />
|
||||
Change:
|
||||
<input type="file" name="banner_logo" accept="image/*" class="clearablefileinput" id="id_banner_logo" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="primaryAction" type="submit">Update Channel</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
137
frontend/config/templates/static/editMediaPage.html
Normal file
137
frontend/config/templates/static/editMediaPage.html
Normal file
@ -0,0 +1,137 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="user-action-form-wrap">
|
||||
<div class="user-action-form-inner">
|
||||
<h1>Edit Media</h1>
|
||||
|
||||
<form enctype="multipart/form-data" action="" method="post" class="post-form">
|
||||
<div id="div_id_title" class="control-group">
|
||||
<label for="id_title" class="control-label"> Title </label>
|
||||
<div class="controls">
|
||||
<input
|
||||
type="text"
|
||||
name="title"
|
||||
value="Media title..."
|
||||
maxlength="100"
|
||||
class="textinput textInput"
|
||||
id="id_title"
|
||||
/>
|
||||
<p id="hint_id_title" class="help-block">media title</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_category" class="control-group">
|
||||
<label for="id_category" class="control-label"> Category </label>
|
||||
<div class="controls">
|
||||
<select name="category" class="selectmultiple" id="id_category" multiple="">
|
||||
<option value="1">Art</option>
|
||||
<option value="2">Documentary</option>
|
||||
<option value="3">Experimental</option>
|
||||
<option value="4">Film</option>
|
||||
<option value="5">Music</option>
|
||||
<option value="6">TV</option>
|
||||
</select>
|
||||
<p id="hint_id_category" class="help-block">Media can be part of one or more categories</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_new_tags" class="control-group">
|
||||
<label for="id_new_tags" class="control-label"> Tags </label>
|
||||
<div class="controls">
|
||||
<input type="text" name="new_tags" class="textinput textInput" id="id_new_tags" />
|
||||
<p id="hint_id_new_tags" class="help-block">a comma separated list of new tags.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_add_date" class="control-group">
|
||||
<label for="id_add_date" class="control-label"> Date produced </label>
|
||||
<div class="controls">
|
||||
<input type="text" name="add_date" value="2021-01-01 00:00:01" class="datetimeinput" id="id_add_date" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_uploaded_poster" class="control-group">
|
||||
<label for="id_uploaded_poster" class="control-label"> Upload image </label>
|
||||
<div class="controls">
|
||||
<input
|
||||
type="file"
|
||||
name="uploaded_poster"
|
||||
accept="image/*"
|
||||
class="clearablefileinput"
|
||||
id="id_uploaded_poster"
|
||||
/>
|
||||
<p id="hint_id_uploaded_poster" class="help-block">This image will characterize the media</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_description" class="control-group">
|
||||
<label for="id_description" class="control-label"> Description </label>
|
||||
<div class="controls">
|
||||
<textarea name="description" cols="40" rows="10" class="textarea" id="id_description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_state" class="control-group">
|
||||
<label for="id_state" class="control-label requiredField">
|
||||
State<span class="asteriskField">*</span>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select name="state" class="select" id="id_state">
|
||||
<option value="private">Private</option>
|
||||
<option value="public" selected="">Public</option>
|
||||
<option value="unlisted">Unlisted</option>
|
||||
</select>
|
||||
<p id="hint_id_state" class="help-block">state of Media</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_enable_comments" class="control-group">
|
||||
<div class="controls">
|
||||
<label for="id_enable_comments" class="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="enable_comments"
|
||||
class="checkboxinput"
|
||||
id="id_enable_comments"
|
||||
checked=""
|
||||
/>
|
||||
Enable comments
|
||||
</label>
|
||||
<p id="hint_id_enable_comments" class="help-block">Whether comments will be allowed for this media</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_thumbnail_time" class="control-group">
|
||||
<label for="id_thumbnail_time" class="control-label"> Thumbnail time </label>
|
||||
<div class="controls">
|
||||
<input
|
||||
type="number"
|
||||
name="thumbnail_time"
|
||||
value="132.5"
|
||||
step="any"
|
||||
class="numberinput"
|
||||
id="id_thumbnail_time"
|
||||
/>
|
||||
<p id="hint_id_thumbnail_time" class="help-block">Time on video that a thumbnail will be taken</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div_id_allow_download" class="control-group">
|
||||
<div class="controls">
|
||||
<label for="id_allow_download" class="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="allow_download"
|
||||
class="checkboxinput"
|
||||
id="id_allow_download"
|
||||
checked=""
|
||||
/>
|
||||
Allow download
|
||||
</label>
|
||||
<p id="hint_id_allow_download" class="help-block">Whether option to download media is shown</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="primaryAction" type="submit">Update Media</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
43
frontend/config/templates/static/editProfilePage.html
Executable file
43
frontend/config/templates/static/editProfilePage.html
Executable file
@ -0,0 +1,43 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="user-action-form-wrap">
|
||||
<div class="user-action-form-inner">
|
||||
<h1>Edit Profile</h1>
|
||||
<form enctype="multipart/form-data" action="" method="post" class="post-form">
|
||||
<p>
|
||||
<label for="id_name">Full name:</label>
|
||||
<input type="text" name="name" value="" maxlength="250" required="" id="id_name" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="id_description">About me:</label>
|
||||
<textarea name="description" cols="40" rows="10" id="id_description"></textarea>
|
||||
</p>
|
||||
<p>
|
||||
<label for="id_email">Email address:</label>
|
||||
<input type="email" name="email" value="" maxlength="254" id="id_email" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="id_logo">Logo:</label> Currently: <a href="#">*****</a>
|
||||
<input type="checkbox" name="logo-clear" id="logo-clear_id" />
|
||||
<label for="logo-clear_id">Clear</label><br />
|
||||
Change:
|
||||
<input type="file" name="logo" accept="image/*" id="id_logo" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="id_notification_on_comments"
|
||||
>Whether you will receive email notifications for comments added to your content:</label
|
||||
>
|
||||
<input type="checkbox" name="notification_on_comments" id="id_notification_on_comments" checked="" />
|
||||
</p>
|
||||
<button class="primaryAction" type="submit">Update Profile</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
11
frontend/config/templates/static/errorPage.html
Executable file
11
frontend/config/templates/static/errorPage.html
Executable file
@ -0,0 +1,11 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="error-page-wrap">Error</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
45
frontend/config/templates/static/registerPage.html
Executable file
45
frontend/config/templates/static/registerPage.html
Executable file
@ -0,0 +1,45 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="user-action-form-wrap">
|
||||
<div class="user-action-form-inner">
|
||||
<h1>Sign Up</h1>
|
||||
<p>Already have an account? Then please <a href="./signin.html">sign in</a>.</p>
|
||||
<form class="signup" id="signup_form" method="post" action="#">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="" />
|
||||
<p>
|
||||
<label for="id_email">E-mail:</label>
|
||||
<input type="email" name="email" id="id_email" required="" placeholder="E-mail address" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="id_username">Username:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="id_username"
|
||||
autofocus="autofocus"
|
||||
placeholder="Username"
|
||||
minlength="4"
|
||||
maxlength="150"
|
||||
required=""
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="id_name">Name:</label>
|
||||
<input type="text" name="name" id="id_name" maxlength="100" required="" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="id_password1">Password:</label>
|
||||
<input type="password" name="password1" id="id_password1" required="" placeholder="Password" />
|
||||
</p>
|
||||
<button type="submit">Sign Up »</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
28
frontend/config/templates/static/resetPasswordPage.html
Executable file
28
frontend/config/templates/static/resetPasswordPage.html
Executable file
@ -0,0 +1,28 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="user-action-form-wrap">
|
||||
<div class="user-action-form-inner">
|
||||
<h1>Password Reset</h1>
|
||||
<p>
|
||||
Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset
|
||||
it.
|
||||
</p>
|
||||
<form method="POST" action="#" class="password_reset">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="" />
|
||||
<p>
|
||||
<label for="id_email">E-mail:</label>
|
||||
<input type="email" name="email" size="30" id="id_email" required="" placeholder="E-mail address" />
|
||||
</p>
|
||||
<input type="submit" value="Reset My Password" />
|
||||
</form>
|
||||
<p>Please contact us if you have any trouble resetting your password.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
36
frontend/config/templates/static/signinPage.html
Executable file
36
frontend/config/templates/static/signinPage.html
Executable file
@ -0,0 +1,36 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="user-action-form-wrap">
|
||||
<div class="user-action-form-inner">
|
||||
<h1>Sign In</h1>
|
||||
<p>If you have not created an account yet, then please <a href="./register.html">sign up</a> first.</p>
|
||||
<form class="login" method="POST" action="#">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="" />
|
||||
<p>
|
||||
<label for="id_login">Login:</label>
|
||||
<input
|
||||
type="text"
|
||||
name="login"
|
||||
id="id_login"
|
||||
required=""
|
||||
autofocus="autofocus"
|
||||
placeholder="Username or e-mail"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="id_password">Password:</label>
|
||||
<input type="password" name="password" id="id_password" required="" placeholder="Password" />
|
||||
</p>
|
||||
<a class="button secondaryAction" href="./reset-password.html">Forgot Password?</a>
|
||||
<button class="primaryAction" type="submit">Sign In</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
20
frontend/config/templates/static/signoutPage.html
Executable file
20
frontend/config/templates/static/signoutPage.html
Executable file
@ -0,0 +1,20 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="user-action-form-wrap">
|
||||
<div class="user-action-form-inner">
|
||||
<h1>Sign Out</h1>
|
||||
<p>Are you sure you want to sign out?</p>
|
||||
<form method="post" action="#">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="" />
|
||||
<button type="submit">Sign Out</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
15
frontend/config/templates/static/termsPage.html
Executable file
15
frontend/config/templates/static/termsPage.html
Executable file
@ -0,0 +1,15 @@
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main">
|
||||
<div class="page-main-inner">
|
||||
<div class="custom-page-wrapper">
|
||||
<h2>Terms</h2>
|
||||
<hr />
|
||||
<p>Terms of service</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-sidebar-content-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-footer"></div>
|
39075
frontend/package-lock.json
generated
Normal file
39075
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
53
frontend/package.json
Executable file
53
frontend/package.json
Executable file
@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "mediacms-frontend",
|
||||
"version": "0.9.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"license": "",
|
||||
"keywords": [],
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "mediacms-scripts development --config=./config/mediacms.config.js --host=0.0.0.0 --port=8088",
|
||||
"dist": "mediacms-scripts rimraf ./dist && mediacms-scripts build --config=./config/mediacms.config.js --env=dist"
|
||||
},
|
||||
"browserslist": [
|
||||
"cover 99.5%"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.5",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@types/react": "^17.0.11",
|
||||
"@types/react-dom": "^17.0.7",
|
||||
"autoprefixer": "^10.2.6",
|
||||
"babel-loader": "^8.2.2",
|
||||
"compass-mixins": "^0.12.10",
|
||||
"copy-webpack-plugin": "^9.0.0",
|
||||
"core-js": "^3.14.0",
|
||||
"css-loader": "^5.2.6",
|
||||
"dotenv": "^10.0.0",
|
||||
"ejs": "^3.1.6",
|
||||
"ejs-compiled-loader": "^3.1.0",
|
||||
"mediacms-scripts": "file:packages/scripts",
|
||||
"postcss-loader": "^6.1.0",
|
||||
"prettier": "^2.3.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"sass": "^1.34.1",
|
||||
"sass-loader": "^12.1.0",
|
||||
"ts-loader": "^9.2.3",
|
||||
"typescript": "^4.3.2",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.38.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"flux": "^4.0.1",
|
||||
"mediacms-player": "file:packages/player",
|
||||
"normalize.css": "^8.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"sortablejs": "^1.13.0",
|
||||
"timeago.js": "^4.0.2",
|
||||
"url-parse": "^1.5.1"
|
||||
}
|
||||
}
|
3
frontend/packages/player/.babelrc
Executable file
3
frontend/packages/player/.babelrc
Executable file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env"]
|
||||
}
|
18
frontend/packages/player/.editorconfig
Executable file
18
frontend/packages/player/.editorconfig
Executable file
@ -0,0 +1,18 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
indent_size = 1
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[package.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = false
|
8
frontend/packages/player/.modernizrrc
Executable file
8
frontend/packages/player/.modernizrrc
Executable file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"minify": true,
|
||||
"options": [],
|
||||
"feature-detects": [
|
||||
"css/transforms",
|
||||
"test/storage/localstorage"
|
||||
]
|
||||
}
|
1
frontend/packages/player/README.md
Executable file
1
frontend/packages/player/README.md
Executable file
@ -0,0 +1 @@
|
||||
# mediacms-player
|
113
frontend/packages/player/config/includes/rollup_builds.js
Executable file
113
frontend/packages/player/config/includes/rollup_builds.js
Executable file
@ -0,0 +1,113 @@
|
||||
import gzip from 'rollup-plugin-gzip';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
import babel from 'rollup-plugin-babel';
|
||||
import cleanup from 'rollup-plugin-cleanup';
|
||||
// import { uglify } from "rollup-plugin-uglify";
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import visualizer from 'rollup-plugin-visualizer';
|
||||
import json from '@rollup/plugin-json';
|
||||
|
||||
export default function rollup_builds(input_file, output_folder, pkg) {
|
||||
const package_name = pkg.name;
|
||||
|
||||
const dependencies = pkg.dependencies;
|
||||
const dependencies_names = !!dependencies ? Object.keys(pkg.dependencies) : [];
|
||||
|
||||
const esm_format = 'es';
|
||||
const browser_format = 'umd';
|
||||
const commonjs_format = 'cjs';
|
||||
|
||||
const postcss_config = {
|
||||
extract: true,
|
||||
modules: false, // Avoid adding prefixes to classnames (etc).
|
||||
extensions: ['.css', '.sss', '.pcss', '.scss'],
|
||||
};
|
||||
|
||||
const postcss_plugin = postcss(postcss_config);
|
||||
const postcss_plugin_minimized = postcss({ ...postcss_config, minimize: true });
|
||||
|
||||
const commonjs_resolve_config = {
|
||||
// pass custom options to the resolve plugin
|
||||
customResolveOptions: { moduleDirectory: 'node_modules' },
|
||||
};
|
||||
|
||||
function beautify_plugin() {
|
||||
return cleanup(/*{
|
||||
maxEmptyLines: 1,
|
||||
sourcemap: false,
|
||||
}*/);
|
||||
}
|
||||
|
||||
function visualizer_plugin(name) {
|
||||
return visualizer({
|
||||
title: name,
|
||||
filename: output_folder + '/visualizer/' + name + '.html',
|
||||
});
|
||||
}
|
||||
|
||||
function es_build(filename, visualize, bundle) {
|
||||
const plugins = [postcss_plugin, json(), beautify_plugin()];
|
||||
|
||||
if (!!visualize) {
|
||||
plugins.push(visualizer_plugin(filename));
|
||||
}
|
||||
|
||||
return {
|
||||
input: input_file,
|
||||
external: !!bundle ? {} : dependencies_names,
|
||||
output: [{ format: esm_format, file: filename }],
|
||||
plugins: plugins,
|
||||
};
|
||||
}
|
||||
|
||||
function commonjs_build(filename, visualize, bundle) {
|
||||
const plugins = [postcss_plugin, json(), resolve(commonjs_resolve_config), beautify_plugin()];
|
||||
|
||||
if (!!visualize) {
|
||||
plugins.push(visualizer_plugin(filename));
|
||||
}
|
||||
|
||||
return {
|
||||
input: input_file,
|
||||
external: !!bundle ? {} : dependencies_names,
|
||||
output: [{ format: commonjs_format, file: filename }],
|
||||
plugins: plugins,
|
||||
};
|
||||
}
|
||||
|
||||
function browser_build(filename, visualize, minimize, compact) {
|
||||
const plugins = [
|
||||
!!minimize ? postcss_plugin_minimized : postcss_plugin,
|
||||
json(),
|
||||
babel(),
|
||||
resolve(),
|
||||
commonjs(),
|
||||
beautify_plugin(),
|
||||
];
|
||||
|
||||
if (!!minimize) {
|
||||
// plugins.push( uglify() );
|
||||
|
||||
if (!!compact) {
|
||||
plugins.push(gzip());
|
||||
}
|
||||
}
|
||||
|
||||
if (!!visualize) {
|
||||
plugins.push(visualizer_plugin(filename));
|
||||
}
|
||||
|
||||
return {
|
||||
input: input_file,
|
||||
output: { name: package_name, format: browser_format, file: filename },
|
||||
plugins: plugins,
|
||||
};
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
es: es_build,
|
||||
browser: browser_build,
|
||||
commonjs: commonjs_build,
|
||||
});
|
||||
}
|
11
frontend/packages/player/config/rollup.config.build.js
Executable file
11
frontend/packages/player/config/rollup.config.build.js
Executable file
@ -0,0 +1,11 @@
|
||||
import rollup_builds from './includes/rollup_builds';
|
||||
import pckg from '../package.json';
|
||||
|
||||
const dists = rollup_builds('./src/index.js', './out', pckg);
|
||||
|
||||
export default [
|
||||
dists.browser('./dist/mediacms-player.js'),
|
||||
// dists.browser("./dist/mediacms-player.js", true),
|
||||
// dists.browser("./dist/mediacms-player.min.js", true, true),
|
||||
// dists.browser("./dist/mediacms-player.min.js", true, true, true)
|
||||
];
|
6
frontend/packages/player/config/rollup.config.js
Executable file
6
frontend/packages/player/config/rollup.config.js
Executable file
@ -0,0 +1,6 @@
|
||||
import rollup_builds from './includes/rollup_builds';
|
||||
import pckg from '../package.json';
|
||||
|
||||
const dists = rollup_builds('./src/index.js', './out', pckg);
|
||||
|
||||
export default [dists.browser('./dist/mediacms-player.js')];
|
1239
frontend/packages/player/dist/mediacms-player.css
vendored
Normal file
1239
frontend/packages/player/dist/mediacms-player.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2584
frontend/packages/player/dist/mediacms-player.js
vendored
Normal file
2584
frontend/packages/player/dist/mediacms-player.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16686
frontend/packages/player/package-lock.json
generated
Normal file
16686
frontend/packages/player/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
62
frontend/packages/player/package.json
Executable file
62
frontend/packages/player/package.json
Executable file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "mediacms-player",
|
||||
"version": "0.9.0",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"license": "",
|
||||
"engines": {
|
||||
"node": ">=14.17.0"
|
||||
},
|
||||
"keywords": [
|
||||
"mediacms",
|
||||
"media player",
|
||||
"videojs"
|
||||
],
|
||||
"main": "./dist/mediacms-player.js",
|
||||
"module": "./src/",
|
||||
"browser": "./dist/mediacms-player.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "npx rollup -w -c config/rollup.config.js",
|
||||
"build": "npx rollup -c config/rollup.config.build.js",
|
||||
"clean:build": "node ./scripts/rmrf.js ./dist"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"video.js": "^7.12.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"mediacms-vjs-plugin": "file:../vjs-plugin"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.5",
|
||||
"@rollup/plugin-commonjs": "^19.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"ajv": "^8.6.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"core-js": "^3.14.0",
|
||||
"css-loader": "^5.2.6",
|
||||
"global": "^4.4.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"node-sass": "^6.0.0",
|
||||
"postcss": "^8.3.2",
|
||||
"rollup": "^2.51.2",
|
||||
"rollup-plugin-babel": "^4.3.3",
|
||||
"rollup-plugin-cleanup": "^3.2.1",
|
||||
"rollup-plugin-gzip": "^2.5.0",
|
||||
"rollup-plugin-postcss": "^4.0.0",
|
||||
"rollup-plugin-visualizer": "^5.5.0",
|
||||
"sass-loader": "^12.1.0",
|
||||
"style-loader": "^2.0.0",
|
||||
"trim-newlines": "^4.0.2"
|
||||
}
|
||||
}
|
21
frontend/packages/player/scripts/rmrf.js
Executable file
21
frontend/packages/player/scripts/rmrf.js
Executable file
@ -0,0 +1,21 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var rimraf = require('rimraf');
|
||||
|
||||
var cliArgs = process.argv.slice(2);
|
||||
|
||||
function rmdir_callback(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
var i, dir;
|
||||
|
||||
for (i = 0; i < cliArgs.length; i++) {
|
||||
dir = path.resolve(cliArgs[i]);
|
||||
|
||||
if (fs.existsSync(dir)) {
|
||||
rimraf.sync(dir, {}, rmdir_callback);
|
||||
}
|
||||
}
|
453
frontend/packages/player/src/MediaPlayer.js
Executable file
453
frontend/packages/player/src/MediaPlayer.js
Executable file
@ -0,0 +1,453 @@
|
||||
import 'mediacms-vjs-plugin/dist/mediacms-vjs-plugin.js';
|
||||
import 'mediacms-vjs-plugin/dist/mediacms-vjs-plugin.css';
|
||||
|
||||
function isString(v) {
|
||||
return 'string' === typeof v || v instanceof String;
|
||||
}
|
||||
|
||||
function isArray(v) {
|
||||
return !Array.isArray ? '[object Array]' === Object.prototype.toString.call(v) : Array.isArray(v);
|
||||
}
|
||||
|
||||
function isBoolean(v) {
|
||||
return 'boolean' === typeof v || v instanceof Boolean;
|
||||
}
|
||||
|
||||
function ifBooleanElse(bol, els) {
|
||||
return isBoolean(bol) ? bol : els;
|
||||
}
|
||||
|
||||
const defaults = {
|
||||
options: {
|
||||
sources: [],
|
||||
keyboardControls: !0,
|
||||
enabledTouchControls: !0,
|
||||
nativeDimensions: !1,
|
||||
suppressNotSupportedError: !0,
|
||||
poster: '',
|
||||
loop: !1,
|
||||
controls: !0,
|
||||
preload: 'auto',
|
||||
autoplay: !1,
|
||||
bigPlayButton: !0,
|
||||
liveui: !1,
|
||||
controlBar: {
|
||||
bottomBackground: !0,
|
||||
progress: !0,
|
||||
play: !0,
|
||||
next: !1,
|
||||
previous: !1,
|
||||
volume: !0,
|
||||
pictureInPicture: !0, // @link: https://docs.videojs.com/control-bar_picture-in-picture-toggle.js.html
|
||||
fullscreen: !0,
|
||||
theaterMode: !0,
|
||||
time: !0,
|
||||
},
|
||||
cornerLayers: {
|
||||
topLeft: null,
|
||||
topRight: null,
|
||||
bottomLeft: null,
|
||||
bottomRight: null,
|
||||
},
|
||||
videoPreviewThumb: {},
|
||||
subtitles: {
|
||||
on: false,
|
||||
default: null,
|
||||
languages: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter plugin options values.
|
||||
* @param {Object} opt Options object.
|
||||
* @return {Object} Filtered/Validated options object.
|
||||
*/
|
||||
function filterPlayerOptions(domPlayer, opt) {
|
||||
let k, x, j, i;
|
||||
|
||||
opt.sources = isArray(opt.sources) && opt.sources.length ? opt.sources : [];
|
||||
opt.loop = ifBooleanElse(opt.loop, defaults.options.loop);
|
||||
opt.controls = ifBooleanElse(opt.controls, defaults.options.controls);
|
||||
|
||||
if (opt.subtitles && opt.subtitles instanceof Object) {
|
||||
opt.subtitles.default = void 0 !== opt.subtitles.default ? opt.subtitles.default : defaults.options.subtitles.default;
|
||||
opt.subtitles.languages = isArray(opt.subtitles.languages)
|
||||
? opt.subtitles.languages
|
||||
: defaults.options.subtitles.languages;
|
||||
opt.subtitles.on = ifBooleanElse(opt.subtitles.on, defaults.options.subtitles.on);
|
||||
} else {
|
||||
opt.subtitles.default = defaults.options.subtitles;
|
||||
}
|
||||
|
||||
opt.autoplay =
|
||||
'any' === opt.autoplay || 'play' === opt.autoplay || 'muted' === opt.autoplay
|
||||
? opt.autoplay
|
||||
: ifBooleanElse(opt.autoplay, defaults.options.autoplay);
|
||||
|
||||
// console.log(opt.autoplay);
|
||||
|
||||
opt.bigPlayButton = ifBooleanElse(opt.bigPlayButton, defaults.options.bigPlayButton);
|
||||
opt.poster = isString(opt.poster) && '' !== opt.poster.trim() ? opt.poster : defaults.options.poster;
|
||||
opt.preload =
|
||||
isString(opt.preload) && -1 < ['auto', 'metadata', 'none'].indexOf(opt.preload.trim())
|
||||
? opt.preload
|
||||
: defaults.options.preload;
|
||||
|
||||
// Control bar options.
|
||||
if (opt.controlBar && opt.controlBar instanceof Object && Object.keys(opt.controlBar).length) {
|
||||
for (k in opt.controlBar) {
|
||||
if (opt.controlBar.hasOwnProperty(k)) {
|
||||
opt.controlBar[k] = ifBooleanElse(opt.controlBar[k], defaults.options.controlBar[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Corner layers.
|
||||
if (opt.cornerLayers && opt.cornerLayers instanceof Object && Object.keys(opt.cornerLayers).length) {
|
||||
for (k in opt.cornerLayers) {
|
||||
if (opt.cornerLayers.hasOwnProperty(k)) {
|
||||
if ('string' === typeof opt.cornerLayers[k]) {
|
||||
opt.cornerLayers[k] = '' !== opt.cornerLayers[k] ? opt.cornerLayers[k] : defaults.options.cornerLayers[k];
|
||||
} else if (Node.prototype.isPrototypeOf(opt.cornerLayers[k]) || !isNaN(opt.cornerLayers[k])) {
|
||||
opt.cornerLayers[k] = opt.cornerLayers[k];
|
||||
} else {
|
||||
opt.cornerLayers[k] = opt.cornerLayers[k] || defaults.options.cornerLayers[k];
|
||||
}
|
||||
} else {
|
||||
opt.cornerLayers[k] = defaults.options.cornerLayers[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
opt.previewSprite = 'object' === typeof opt.previewSprite ? opt.previewSprite : {};
|
||||
|
||||
// Include HTML sources.
|
||||
|
||||
let obj;
|
||||
let sources_el = domPlayer.querySelectorAll('source');
|
||||
|
||||
i = 0;
|
||||
while (i < sources_el.length) {
|
||||
if (void 0 !== sources_el[i].attributes.src) {
|
||||
obj = {
|
||||
src: sources_el[i].src,
|
||||
};
|
||||
|
||||
if (void 0 !== sources_el[i].attributes.type) {
|
||||
obj.type = sources_el[i].type;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
while (x < opt.sources.length && obj.src !== opt.sources[x].src) {
|
||||
x += 1;
|
||||
}
|
||||
|
||||
if (x >= opt.sources.length) {
|
||||
opt.sources.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Include HTML subtitle tracks.
|
||||
|
||||
let subs_el = domPlayer.querySelectorAll('track[kind="subtitles"]');
|
||||
|
||||
const subtitles_options = {
|
||||
on: opt.subtitles.on,
|
||||
default: null,
|
||||
languages: [],
|
||||
};
|
||||
|
||||
const languages = {};
|
||||
|
||||
function addSubtitle(track) {
|
||||
track.src = void 0 !== track.src && null !== track.src ? track.src.toString().trim() : '';
|
||||
track.srclang = void 0 !== track.srclang && null !== track.srclang ? track.srclang.toString().trim() : '';
|
||||
|
||||
if (track.src.length && track.srclang.length) {
|
||||
track.label = void 0 !== track.label && null !== track.label ? track.label.toString().trim() : track.srclang;
|
||||
|
||||
if (void 0 !== languages[track.srclang]) {
|
||||
languages[track.srclang].src = track.src;
|
||||
languages[track.srclang].label = track.label;
|
||||
} else {
|
||||
subtitles_options.languages.push({
|
||||
label: track.label,
|
||||
src: track.src,
|
||||
srclang: track.srclang,
|
||||
});
|
||||
|
||||
languages[track.srclang] = subtitles_options.languages[subtitles_options.languages.length - 1];
|
||||
}
|
||||
|
||||
if (void 0 !== track.default && null !== track.default) {
|
||||
track.default = track.default.toString().trim();
|
||||
|
||||
if (!track.default.length || '1' === track.default || 'true' === track.default) {
|
||||
subtitles_options.default = track.srclang;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < subs_el.length) {
|
||||
addSubtitle({
|
||||
src: subs_el[i].getAttribute('src'),
|
||||
srclang: subs_el[i].getAttribute('srclang'),
|
||||
default: subs_el[i].getAttribute('default'),
|
||||
label: subs_el[i].getAttribute('label'),
|
||||
});
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (opt.subtitles.languages.length) {
|
||||
i = 0;
|
||||
|
||||
while (i < opt.subtitles.languages.length) {
|
||||
addSubtitle({
|
||||
src: opt.subtitles.languages[i].src,
|
||||
srclang: opt.subtitles.languages[i].srclang,
|
||||
default: opt.subtitles.languages[i].default,
|
||||
label: opt.subtitles.languages[i].label,
|
||||
});
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== opt.subtitles.default && void 0 !== languages[opt.subtitles.default]) {
|
||||
subtitles_options.default = opt.subtitles.default;
|
||||
}
|
||||
|
||||
if (null === subtitles_options.default && opt.subtitles.languages.length) {
|
||||
subtitles_options.default = opt.subtitles.languages[0].srclang;
|
||||
}
|
||||
|
||||
opt.subtitles = subtitles_options;
|
||||
|
||||
return opt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct VideoJs options by player options.
|
||||
* @param {Object} opt Plugin options.
|
||||
* @param {Object} vjopt Initial VideoJs object.
|
||||
* @return {Object} Final VideoJs object.
|
||||
*/
|
||||
function constructVideojsOptions(opt, vjopt) {
|
||||
// {
|
||||
// /*autoplay: false,
|
||||
// controls: true,
|
||||
// preload: "auto", // preload: "metadata",
|
||||
// loop: false,
|
||||
// bigPlayButton: true,*/
|
||||
// // poster: "",
|
||||
// // width: "",
|
||||
// // height: "",
|
||||
// // children: {}
|
||||
// controlBar: {
|
||||
// children: [],
|
||||
// // children: {
|
||||
// // bottomGradientComponent: true,
|
||||
// // progressControl: true, // (hidden during live playback)
|
||||
// // leftControls: true,
|
||||
// // // playbackRateMenuButton: true, // (hidden, unless playback tech supports rate changes)
|
||||
// // // chaptersButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // // descriptionsButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // // subtitlesButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // // captionsButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // // audioTrackButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // }
|
||||
// // seekBar: false,
|
||||
// // loadProgressBar: false,
|
||||
// // mouseTimeDisplay: false,
|
||||
// // playProgressBar: false,
|
||||
// // liveDisplay: false, // (hidden during VOD playback)
|
||||
// // remainingTimeDisplay: false,
|
||||
// // customControlSpacer: false, // (has no UI)
|
||||
// // playbackRateMenuButton: true, // (hidden, unless playback tech supports rate changes)
|
||||
// // chaptersButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // descriptionsButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // subtitlesButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // captionsButton: true, // (hidden, unless there are relevant tracks)
|
||||
// // audioTrackButton: true, // (hidden, unless there are relevant tracks)
|
||||
// }
|
||||
// }
|
||||
|
||||
vjopt.sources = opt.sources;
|
||||
vjopt.loop = opt.loop;
|
||||
vjopt.controls = opt.controls;
|
||||
vjopt.autoplay = opt.autoplay;
|
||||
vjopt.bigPlayButton = opt.bigPlayButton;
|
||||
vjopt.poster = opt.poster;
|
||||
vjopt.preload = opt.preload;
|
||||
vjopt.suppressNotSupportedError = opt.suppressNotSupportedError;
|
||||
|
||||
// console.log( vjopt );
|
||||
// console.log( opt );
|
||||
|
||||
return vjopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper/container class of MediaCMS VideoJs player.
|
||||
* @param {DOM Node} domPlayer The video element in html.
|
||||
* @param {Object} pluginOptions Plugin (genral player's) options.
|
||||
* @param {Object} pluginState Plugin initial state values.
|
||||
* @param {Function} pluginStateUpdateCallback The function will be called on plugin's state values update.
|
||||
*/
|
||||
export function MediaPlayer(
|
||||
domPlayer,
|
||||
pluginOptions,
|
||||
pluginState,
|
||||
videoResolutions,
|
||||
videoPlaybackSpeeds,
|
||||
pluginStateUpdateCallback,
|
||||
onNextButtonClick,
|
||||
onPrevButtonClick
|
||||
) {
|
||||
if (!Node.prototype.isPrototypeOf(domPlayer)) {
|
||||
console.error('Invalid player DOM element', domPlayer); // TODO: Validate that element is <video> or <audio>.
|
||||
return null;
|
||||
}
|
||||
|
||||
function sourcesSrcs(urls) {
|
||||
const ret = [];
|
||||
let i = 0;
|
||||
while (i < urls.length) {
|
||||
if (!!urls[i]) {
|
||||
ret.push(urls[i]); // @todo: Validate url file extension.
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function sourcesFormats(formats) {
|
||||
const ret = [];
|
||||
let i = 0;
|
||||
while (i < formats.length) {
|
||||
if (!!formats[i]) {
|
||||
ret.push(formats[i]); // @todo: Validate format.
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
let k,
|
||||
i,
|
||||
pluginVideoResolutions = {},
|
||||
pluginVideoPlaybackSpeeds = {};
|
||||
|
||||
if (!!videoResolutions) {
|
||||
for (k in videoResolutions) {
|
||||
if (videoResolutions.hasOwnProperty(k)) {
|
||||
if (
|
||||
isArray(videoResolutions[k].url) &&
|
||||
videoResolutions[k].url.length &&
|
||||
isArray(videoResolutions[k].format) &&
|
||||
videoResolutions[k].format.length
|
||||
) {
|
||||
pluginVideoResolutions[k] = {
|
||||
title: k,
|
||||
src: sourcesSrcs(videoResolutions[k].url),
|
||||
format: sourcesFormats(videoResolutions[k].format),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!!videoPlaybackSpeeds) {
|
||||
k = 0;
|
||||
while (k < videoPlaybackSpeeds.length) {
|
||||
pluginVideoPlaybackSpeeds[k] = {
|
||||
title: 1 === videoPlaybackSpeeds[k] ? 'Normal' : videoPlaybackSpeeds[k],
|
||||
speed: videoPlaybackSpeeds[k].toString(),
|
||||
};
|
||||
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Filter options value.
|
||||
*/
|
||||
|
||||
// console.log( '####################' );
|
||||
// console.log( domPlayer );
|
||||
// console.log( defaults.options );
|
||||
// console.log( Object.keys(pluginOptions) );
|
||||
|
||||
pluginOptions = filterPlayerOptions(
|
||||
domPlayer,
|
||||
videojs.mergeOptions(
|
||||
defaults.options,
|
||||
pluginOptions && pluginOptions instanceof Object && Object.keys(pluginOptions).length ? pluginOptions : {}
|
||||
)
|
||||
);
|
||||
|
||||
// console.log( pluginOptions );
|
||||
// console.log( '####################' );
|
||||
|
||||
/*
|
||||
* Filter state value.
|
||||
*/
|
||||
|
||||
// console.log( '####################' );
|
||||
// console.log( pluginState );
|
||||
|
||||
// console.warn( pluginOptions.subtitles );
|
||||
// console.log( pluginState );
|
||||
if (null !== pluginOptions.subtitles.default && pluginOptions.subtitles.on) {
|
||||
pluginState.theSelectedSubtitleOption = pluginOptions.subtitles.default;
|
||||
}
|
||||
// console.log( pluginState );
|
||||
|
||||
// console.log( pluginState );
|
||||
// console.log( '####################' );
|
||||
|
||||
/*
|
||||
* Initialize videojs player.
|
||||
*/
|
||||
|
||||
const passOptions = constructVideojsOptions(pluginOptions, {
|
||||
controlBar: {
|
||||
children: [],
|
||||
},
|
||||
});
|
||||
|
||||
this.player = videojs(domPlayer, passOptions);
|
||||
|
||||
/*
|
||||
* Call plugin.
|
||||
*/
|
||||
|
||||
this.player.mediaCmsVjsPlugin(
|
||||
domPlayer,
|
||||
pluginOptions,
|
||||
pluginState,
|
||||
pluginVideoResolutions,
|
||||
pluginVideoPlaybackSpeeds,
|
||||
pluginStateUpdateCallback,
|
||||
onNextButtonClick,
|
||||
onPrevButtonClick
|
||||
);
|
||||
|
||||
/*
|
||||
* Public methods.
|
||||
*/
|
||||
|
||||
this.isEnded = this.player.mediaCmsVjsPlugin().isEnded;
|
||||
this.isFullscreen = this.player.mediaCmsVjsPlugin().isFullscreen;
|
||||
this.isTheaterMode = this.player.mediaCmsVjsPlugin().isTheaterMode;
|
||||
|
||||
if (void 0 !== typeof window) {
|
||||
window.HELP_IMPROVE_VIDEOJS = false;
|
||||
}
|
||||
}
|
3
frontend/packages/player/src/index.js
Executable file
3
frontend/packages/player/src/index.js
Executable file
@ -0,0 +1,3 @@
|
||||
import { MediaPlayer } from './MediaPlayer';
|
||||
|
||||
export default MediaPlayer;
|
36
frontend/packages/scripts/.eslintrc.js
Executable file
36
frontend/packages/scripts/.eslintrc.js
Executable file
@ -0,0 +1,36 @@
|
||||
module.exports = {
|
||||
"extends": ["eslint:recommended"],
|
||||
"env": { "es6": true, "browser": true, "node": true },
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"rules": {
|
||||
"indent": ["error", "tab"],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"quotes": ["error", "single"],
|
||||
"semi": ["error", "always"],
|
||||
'no-empty': ["error", { "allowEmptyCatch": true }],
|
||||
'no-constant-condition': ["error", { "checkLoops": false }],
|
||||
},
|
||||
"overrides": [{
|
||||
"plugins": [ "@typescript-eslint" ],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"files": ["**/*.ts", "**/*.tsx"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": { "jsx": true },
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
||||
"@typescript-eslint/no-var-requires": "off"
|
||||
},
|
||||
}]
|
||||
}
|
1
frontend/packages/scripts/README.md
Normal file
1
frontend/packages/scripts/README.md
Normal file
@ -0,0 +1 @@
|
||||
# mediacms-scripts
|
47
frontend/packages/scripts/cli.js
Executable file
47
frontend/packages/scripts/cli.js
Executable file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const spawn = require('cross-spawn');
|
||||
|
||||
('use strict');
|
||||
|
||||
// Makes the script crash on unhandled rejections instead of silently
|
||||
// ignoring them. In the future, promise rejections that are not handled will
|
||||
// terminate the Node.js process with a non-zero exit code.
|
||||
process.on('unhandledRejection', (err) => {
|
||||
throw err;
|
||||
});
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const scriptIndex = args.findIndex(
|
||||
(x) => x === 'build' || x === 'development' || x === 'analyzer' || x === 'rimraf' // TODO
|
||||
);
|
||||
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
|
||||
const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : [];
|
||||
|
||||
if (['build', 'development', 'analyzer', 'rimraf'].includes(script)) {
|
||||
const result = spawn.sync(
|
||||
process.execPath,
|
||||
nodeArgs.concat(require.resolve('./scripts/' + script)).concat(args.slice(scriptIndex + 1)),
|
||||
{ stdio: 'inherit' }
|
||||
);
|
||||
if (result.signal) {
|
||||
if (result.signal === 'SIGKILL') {
|
||||
console.log(
|
||||
'The build failed because the process exited too early. ' +
|
||||
'This probably means the system ran out of memory or someone called ' +
|
||||
'`kill -9` on the process.'
|
||||
);
|
||||
} else if (result.signal === 'SIGTERM') {
|
||||
console.log(
|
||||
'The build failed because the process exited too early. ' +
|
||||
'Someone might have called `kill` or `killall`, or the system could ' +
|
||||
'be shutting down.'
|
||||
);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(result.status);
|
||||
} else {
|
||||
console.log('Unknown script "' + script + '".');
|
||||
}
|
3
frontend/packages/scripts/config/build.config.js
Executable file
3
frontend/packages/scripts/config/build.config.js
Executable file
@ -0,0 +1,3 @@
|
||||
import { buildCommonjs } from './helpers/buildCommonjs.js';
|
||||
|
||||
export default buildCommonjs('./src/index.ts', '.')('./dist/webpack-dev-env.js');
|
24
frontend/packages/scripts/config/helpers/buildCommonjs.js
Executable file
24
frontend/packages/scripts/config/helpers/buildCommonjs.js
Executable file
@ -0,0 +1,24 @@
|
||||
import typescript from 'rollup-plugin-typescript2';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import visualizer from 'rollup-plugin-visualizer';
|
||||
import cleanup from 'rollup-plugin-cleanup';
|
||||
|
||||
export function buildCommonjs(input_file, output_folder) {
|
||||
return function (filename, visualize) {
|
||||
const plugins = [
|
||||
resolve({ customResolveOptions: { moduleDirectories: 'node_modules' } }),
|
||||
typescript(),
|
||||
cleanup({ comments: 'none' }),
|
||||
];
|
||||
|
||||
if (visualize) {
|
||||
plugins.push(visualizer({ title: filename, filename: output_folder + filename + '.html' }));
|
||||
}
|
||||
|
||||
return {
|
||||
input: input_file,
|
||||
output: [{ format: 'cjs', file: filename }],
|
||||
plugins: plugins,
|
||||
};
|
||||
};
|
||||
}
|
3
frontend/packages/scripts/config/visual.config.js
Executable file
3
frontend/packages/scripts/config/visual.config.js
Executable file
@ -0,0 +1,3 @@
|
||||
import { buildCommonjs } from './helpers/buildCommonjs.js';
|
||||
|
||||
export default buildCommonjs('./src/index.ts', './visualizer/')('./dist/webpack-dev-env.js', true);
|
3
frontend/packages/scripts/config/watch.config.js
Executable file
3
frontend/packages/scripts/config/watch.config.js
Executable file
@ -0,0 +1,3 @@
|
||||
import { buildCommonjs } from './helpers/buildCommonjs.js';
|
||||
|
||||
export default buildCommonjs('./src/index.ts', '.')('./dist/webpack-dev-env.js');
|
782
frontend/packages/scripts/dist/webpack-dev-env.js
vendored
Normal file
782
frontend/packages/scripts/dist/webpack-dev-env.js
vendored
Normal file
@ -0,0 +1,782 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var __assign = function() {
|
||||
__assign = Object.assign || function __assign(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
function __spreadArray(to, from, pack) {
|
||||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
||||
if (ar || !(i in from)) {
|
||||
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
||||
ar[i] = from[i];
|
||||
}
|
||||
}
|
||||
return to.concat(ar || from);
|
||||
}
|
||||
|
||||
function bodySnippet(id) {
|
||||
return '<div id="' + id + '"></div>';
|
||||
}
|
||||
var homePage = {
|
||||
staticPage: true,
|
||||
buildExclude: false,
|
||||
title: 'Home',
|
||||
filename: 'index.html',
|
||||
html: {
|
||||
head: {},
|
||||
body: {
|
||||
scripts: [],
|
||||
snippet: bodySnippet('page-home'),
|
||||
}
|
||||
},
|
||||
window: {},
|
||||
render: 'import { renderPage } from \'./js/helpers\'; import { HomePage } from \'./js/pages/HomePage\'; renderPage( \'page-home\', HomePage );',
|
||||
};
|
||||
var errorPage = {
|
||||
staticPage: true,
|
||||
buildExclude: false,
|
||||
title: 'Error',
|
||||
filename: 'error.html',
|
||||
html: {
|
||||
head: {},
|
||||
body: {
|
||||
scripts: [],
|
||||
snippet: bodySnippet('page-error'),
|
||||
}
|
||||
},
|
||||
window: {},
|
||||
render: 'import { renderPage } from \'./js/helpers\'; import { ErrorPage } from \'./js/pages/ErrorPage\'; renderPage( \'page-error\', ErrorPage );',
|
||||
};
|
||||
var pages = {
|
||||
home: homePage,
|
||||
error: errorPage,
|
||||
};
|
||||
var htmlHead = {
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ content: 'ie=edge', 'http-equiv': 'x-ua-compatible' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
],
|
||||
links: [],
|
||||
scripts: [],
|
||||
};
|
||||
var htmlBody = {
|
||||
scripts: [],
|
||||
snippet: '',
|
||||
};
|
||||
var html = {
|
||||
head: htmlHead,
|
||||
body: htmlBody,
|
||||
};
|
||||
var config$3 = {
|
||||
src: '',
|
||||
build: '',
|
||||
pages: pages,
|
||||
html: html,
|
||||
window: {},
|
||||
postcssConfigFile: '',
|
||||
};
|
||||
|
||||
/*const chunksCacheGroups_0 = {
|
||||
commons: {
|
||||
test: /[\\/]src[\\/]/,
|
||||
name: "_commons",
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
};*/
|
||||
/*const chunksCacheGroups_1 = {
|
||||
commons: {
|
||||
test: /[\\/]src[\\/]/,
|
||||
name: "_commons",
|
||||
// priority: -10,
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
// test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
|
||||
// test: /[\\/]node_modules[\\/](!MediaCmsPlayer)[\\/]/,
|
||||
name: "_vendors",
|
||||
// priority: -20,
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
// reuseExistingChunk: true,
|
||||
},
|
||||
};*/
|
||||
/*const chunksCacheGroups_2 = {
|
||||
commons: {
|
||||
minChunks: 2,
|
||||
// maxInitialRequests: 8, // @note: Tested values from 0 to 10, and changes applied with values 0, 4, 5, 6, 7, 8.
|
||||
// minSize: 0,
|
||||
name: "_commons",
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
};*/
|
||||
/*const chunksCacheGroups_3 = {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: "_commons",
|
||||
priority: 1,
|
||||
chunks: "initial",
|
||||
},
|
||||
};*/
|
||||
var config$2 = {
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
optimization: {
|
||||
runtimeChunk: false,
|
||||
/*splitChunks: {
|
||||
// minSize: 1000000,
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
},*/
|
||||
/*splitChunks: {
|
||||
// minSize: 1000000,
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: chunksCacheGroups_0,
|
||||
},*/
|
||||
/*splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: chunksCacheGroups_1,
|
||||
},*/
|
||||
/*splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: chunksCacheGroups_2,
|
||||
},*/
|
||||
/*splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: chunksCacheGroups_3,
|
||||
},*/
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: "_commons",
|
||||
priority: 1,
|
||||
chunks: "initial",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/*const chunksCacheGroups_0 = {
|
||||
commons: {
|
||||
test: /[\\/]src[\\/]/,
|
||||
name: "_commons",
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
};
|
||||
|
||||
const chunksCacheGroups_1 = {
|
||||
commons: {
|
||||
test: /[\\/]src[\\/]/,
|
||||
name: "_commons",
|
||||
// priority: -10,
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
// test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
|
||||
// test: /[\\/]node_modules[\\/](!MediaCmsPlayer)[\\/]/,
|
||||
name: "_vendors",
|
||||
// priority: -20,
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
// reuseExistingChunk: true,
|
||||
},
|
||||
};
|
||||
|
||||
const chunksCacheGroups_2 = {
|
||||
commons: {
|
||||
minChunks: 2,
|
||||
// maxInitialRequests: 8, // @note: Tested values from 0 to 10, and changes applied with values 0, 4, 5, 6, 7, 8.
|
||||
// minSize: 0,
|
||||
name: "_commons",
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
};
|
||||
|
||||
const chunksCacheGroups_3 = {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: "_commons",
|
||||
priority: 1,
|
||||
chunks: "initial",
|
||||
},
|
||||
};*/
|
||||
var config$1 = {
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
minimize: true,
|
||||
runtimeChunk: false,
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: "_commons",
|
||||
priority: 1,
|
||||
chunks: "initial",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @see {link: https://github.com/seeyoulater/html-beautify-webpack-plugin/blob/master/index.js}
|
||||
*/
|
||||
var prettify = require('html-prettify');
|
||||
var HtmlWebpackPlugin$1 = require('html-webpack-plugin');
|
||||
require('webpack/lib/WebpackError.js');
|
||||
function htmlPluginDataFunction(pluginData, options, callback) {
|
||||
pluginData.html = prettify(options.replace.reduce(function (res, item) { return res.replace(item instanceof RegExp ? new RegExp(item, 'gi') : item, ''); }, pluginData.html) /*,
|
||||
options.config*/);
|
||||
callback(null, pluginData);
|
||||
}
|
||||
var MyHtmlBeautifyWebpackPlugin = /** @class */ (function () {
|
||||
function MyHtmlBeautifyWebpackPlugin() {
|
||||
}
|
||||
MyHtmlBeautifyWebpackPlugin.prototype.apply = function (compiler) {
|
||||
var options = {
|
||||
config: {
|
||||
indent_size: 4,
|
||||
indent_with_tabs: false,
|
||||
html: {
|
||||
end_with_newline: true,
|
||||
indent_inner_html: true,
|
||||
preserve_newlines: true,
|
||||
max_preserve_newlines: 0,
|
||||
}
|
||||
},
|
||||
replace: []
|
||||
};
|
||||
function tapAsyncCallback(pluginData, callback) {
|
||||
return htmlPluginDataFunction(pluginData, options, callback);
|
||||
}
|
||||
function tapHookCallback(compilation) {
|
||||
return HtmlWebpackPlugin$1.getHooks(compilation).beforeEmit.tapAsync('MyHtmlBeautifyWebpackPlugin', tapAsyncCallback);
|
||||
}
|
||||
compiler.hooks.compilation.tap('MyHtmlBeautifyWebpackPlugin', tapHookCallback);
|
||||
};
|
||||
return MyHtmlBeautifyWebpackPlugin;
|
||||
}());
|
||||
|
||||
var fs = require('fs');
|
||||
var path$1 = require('path');
|
||||
var ejs = require('ejs');
|
||||
var templatePath = path$1.join(__dirname, '../templates');
|
||||
var sitemapTemplatePath = path$1.join(templatePath, 'sitemap.ejs');
|
||||
var sitemapTemplate = ejs.compile(fs.readFileSync(sitemapTemplatePath, 'utf8'), { root: [templatePath], filename: sitemapTemplatePath, outputFunctionName: 'echo' });
|
||||
function pagesConfig(pagesKeys) {
|
||||
var pages = {};
|
||||
if (-1 === pagesKeys.indexOf('sitemap')) {
|
||||
pages.sitemap = {
|
||||
staticPage: true,
|
||||
buildExclude: true,
|
||||
title: 'Sitemap',
|
||||
filename: 'sitemap.html',
|
||||
html: {
|
||||
head: {},
|
||||
body: {
|
||||
scripts: [],
|
||||
snippet: sitemapTemplate({ pages: __spreadArray(__spreadArray([], pagesKeys), Object.keys(pages)) }),
|
||||
},
|
||||
},
|
||||
window: {},
|
||||
render: ''
|
||||
};
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
|
||||
var merge = require('lodash.merge');
|
||||
function validateBoolean(value, defaultValue) {
|
||||
if (defaultValue === void 0) { defaultValue = false; }
|
||||
if (true === value || false === value) {
|
||||
return value;
|
||||
}
|
||||
if (0 === value || 1 === value) {
|
||||
return !!value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
function validateString(value, defaultValue) {
|
||||
if (defaultValue === void 0) { defaultValue = ''; }
|
||||
return value ? value : defaultValue;
|
||||
}
|
||||
function getArrayType(sourcesArr, pageArr) {
|
||||
if (pageArr === void 0) { pageArr = []; }
|
||||
if ((!sourcesArr || !sourcesArr.length) && (!pageArr || !pageArr.length)) {
|
||||
return [];
|
||||
}
|
||||
if (sourcesArr && sourcesArr.length && pageArr && pageArr.length) {
|
||||
return sourcesArr.concat(pageArr);
|
||||
}
|
||||
if (sourcesArr && sourcesArr.length) {
|
||||
return sourcesArr;
|
||||
}
|
||||
return pageArr;
|
||||
}
|
||||
function formatPagesConfig(sources, pages) {
|
||||
var ret = {};
|
||||
for (var pk in pages) {
|
||||
ret[pk] = {
|
||||
staticPage: validateBoolean(pages[pk].staticPage, false),
|
||||
buildExclude: validateBoolean(pages[pk].buildExclude, false),
|
||||
title: validateString(pages[pk].title, sources.title),
|
||||
filename: validateString(pages[pk].filename, sources.filename),
|
||||
html: {
|
||||
head: {
|
||||
meta: getArrayType(sources.html.head.meta, pages[pk].html.head.meta),
|
||||
links: getArrayType(sources.html.head.links, pages[pk].html.head.links),
|
||||
scripts: getArrayType(sources.html.head.scripts, pages[pk].html.head.scripts),
|
||||
},
|
||||
body: {
|
||||
scripts: getArrayType(sources.html.body.scripts, pages[pk].html.body.scripts),
|
||||
snippet: validateString(pages[pk].html.body.snippet, sources.html.body.snippet),
|
||||
},
|
||||
},
|
||||
window: merge({}, sources.window, pages[pk].window),
|
||||
render: validateString(sources.render, pages[pk].render),
|
||||
};
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
var path = require('path');
|
||||
var NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
|
||||
// Webpack plugins.
|
||||
var DefinePlugin = require('webpack').DefinePlugin;
|
||||
var LimitChunkCountPlugin = require('webpack').optimize.LimitChunkCountPlugin;
|
||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
var VirtualModulesPlugin = require('webpack-virtual-modules');
|
||||
var MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
var ProgressBarPlugin = require('progress-bar-webpack-plugin');
|
||||
var CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
var CopyPlugin = require("copy-webpack-plugin");
|
||||
var dotenv = require('dotenv').config({ path: path.resolve(__dirname + '../../../../.env') });
|
||||
function webpackEntry(env, srcDir, pages) {
|
||||
var ret = {};
|
||||
for (var p in pages) {
|
||||
if ('development' === env || !pages[p].buildExclude) {
|
||||
ret[p] = path.resolve(srcDir + '/' + p + '.js');
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function webpackOutput(env, destinationDir, buildDir, chunkhash, hash) {
|
||||
var ret = {
|
||||
path: destinationDir,
|
||||
filename: '',
|
||||
};
|
||||
var prefix = 'development' === env ? '' : buildDir;
|
||||
var tmp;
|
||||
if (undefined !== chunkhash) {
|
||||
tmp = chunkhash.trim();
|
||||
if ('' === tmp) {
|
||||
throw Error('Invalid chunkhash argument value: ' + chunkhash);
|
||||
}
|
||||
ret.filename = (prefix || '') + '[name]-[chunkhash].js';
|
||||
}
|
||||
else if (undefined !== hash) {
|
||||
tmp = hash.trim();
|
||||
if ('' === tmp) {
|
||||
throw Error('Invalid hash argument value: ' + hash);
|
||||
}
|
||||
ret.filename = (prefix || '') + '[name]-[hash].js';
|
||||
}
|
||||
else {
|
||||
ret.filename = (prefix || '') + '[name].js';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function webpackAlias() {
|
||||
return {
|
||||
// modernizr$: path.resolve(__dirname, "../../.modernizrrc"), // TODO: Enable this?
|
||||
};
|
||||
}
|
||||
function webpackRules(env, srcDir, postcssConfigFile) {
|
||||
return [{
|
||||
test: /\.(jsx|js)?$/,
|
||||
use: 'babel-loader'
|
||||
},
|
||||
{
|
||||
test: /\.(tsx|ts)?$/,
|
||||
use: 'ts-loader',
|
||||
// exclude: /node_modules/,
|
||||
// options: {
|
||||
// compilerOptions: {
|
||||
// "sourceMap": !isProduction,
|
||||
// },
|
||||
// },
|
||||
},
|
||||
{
|
||||
test: /\.ejs$/,
|
||||
use: {
|
||||
loader: 'ejs-compiled-loader',
|
||||
options: {
|
||||
// beautify: true,
|
||||
htmlmin: true,
|
||||
// htmlminOptions: {
|
||||
// removeComments: true,
|
||||
// collapseWhitespace: true,
|
||||
// preserveLineBreaks: true
|
||||
// }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(sa|sc|c)ss$/,
|
||||
use: [
|
||||
{ loader: MiniCssExtractPlugin.loader },
|
||||
// { loader: 'development' === env ? MiniCssExtractPlugin.loader : 'style-loader' }, // Use inline <style> tag.
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{ loader: 'postcss-loader', options: { postcssOptions: { config: postcssConfigFile } } },
|
||||
{ loader: 'sass-loader' },
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.module\.(sa|sc|c)ss$/,
|
||||
use: [
|
||||
{ loader: MiniCssExtractPlugin.loader },
|
||||
// { loader: 'development' === env ? MiniCssExtractPlugin.loader : 'style-loader' }, // Use inline <style> tag.
|
||||
{ loader: 'css-loader', options: { importLoaders: 1, modules: true, onlyLocals: false } },
|
||||
{ loader: 'postcss-loader', options: { postcssOptions: { config: postcssConfigFile } } },
|
||||
{ loader: 'sass-loader' },
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)(\?\S*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 1024,
|
||||
fallback: 'file-loader',
|
||||
name: function (file) {
|
||||
return '.' + path.join(file.replace(srcDir, ''), '..').replace(/\\/g, '/') + '/[name].[ext]';
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
||||
/*issuer: {
|
||||
test: /\.jsx?$/
|
||||
},*/
|
||||
use: ['babel-loader', '@svgr/webpack', 'url-loader']
|
||||
},
|
||||
{
|
||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
||||
loader: 'url-loader'
|
||||
},
|
||||
{
|
||||
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: function (file) {
|
||||
return '.' + path.join(file.replace(srcDir, ''), '..').replace(/\\/g, '/') + '/[name].[ext]';
|
||||
},
|
||||
}
|
||||
}]
|
||||
},
|
||||
{
|
||||
test: /\.modernizrrc.js$/,
|
||||
use: 'modernizr-loader',
|
||||
},
|
||||
{
|
||||
test: /\.modernizrrc(\.json)?$/,
|
||||
use: ['modernizr-loader', 'json-loader'],
|
||||
}];
|
||||
}
|
||||
function webpackPlugins(env, srcDir, pages, cssSrc) {
|
||||
var ret = [
|
||||
new DefinePlugin({ "process.env": JSON.stringify(dotenv.parsed) }),
|
||||
new NodePolyfillPlugin(),
|
||||
new MyHtmlBeautifyWebpackPlugin(),
|
||||
];
|
||||
if ('development' !== env) {
|
||||
ret.push(new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: path.resolve(__dirname, '../../../src/static/lib'),
|
||||
to: path.resolve(__dirname, '../../../' + env + '/static/lib'),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, '../../../src/static/images'),
|
||||
to: path.resolve(__dirname, '../../../' + env + '/static/images'),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, '../../../src/static/favicons'),
|
||||
to: path.resolve(__dirname, '../../../' + env + '/static/favicons'),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, '../../../src/static/css/_extra.css'),
|
||||
to: path.resolve(__dirname, '../../../' + env + '/static/css/_extra.css'),
|
||||
},
|
||||
],
|
||||
}));
|
||||
}
|
||||
var virtualPages = {};
|
||||
var file;
|
||||
for (var k in pages) {
|
||||
if ('production' !== env || !pages[k].buildExclude) {
|
||||
file = path.resolve(srcDir + '/' + k + '.js');
|
||||
if ((void 0 !== pages[k].staticPage && pages[k].staticPage) || void 0 === pages[k].render) {
|
||||
virtualPages[file] = '';
|
||||
}
|
||||
else {
|
||||
virtualPages[file] = pages[k].render;
|
||||
}
|
||||
}
|
||||
if ('development' === env) {
|
||||
// Export pages HTML files.
|
||||
ret.push(new HtmlWebpackPlugin(__assign({ template: path.resolve(__dirname, '../templates/index.ejs'), hash: false, chunks: [k] }, pages[k])));
|
||||
}
|
||||
}
|
||||
ret.push(new VirtualModulesPlugin(virtualPages));
|
||||
ret.push(new MiniCssExtractPlugin({
|
||||
ignoreOrder: true,
|
||||
// filename: ! is_build ? '[name].css' : '[name].[hash].css',
|
||||
// chunkFilename: ! is_build ? '[id].css' : '[id].[hash].css',
|
||||
filename: cssSrc + '[name].css',
|
||||
// chunkFilename: "../css/[id].css",
|
||||
}));
|
||||
if ('development' !== env) {
|
||||
ret.push(new LimitChunkCountPlugin({ maxChunks: 1 }));
|
||||
ret.push(new ProgressBarPlugin({
|
||||
clear: false,
|
||||
}));
|
||||
}
|
||||
if ('production' === env) {
|
||||
ret.push(new CssMinimizerPlugin({
|
||||
cache: true,
|
||||
minimizerOptions: {
|
||||
preset: [
|
||||
'default',
|
||||
{
|
||||
discardComments: { removeAll: true },
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function generateConfig(env, config) {
|
||||
var srcDir = config.src;
|
||||
var buildDir = config.build + '/' + env + ('development' === env ? '' : '/static');
|
||||
var cssbuild = './css/';
|
||||
var jsbuild = './js/';
|
||||
var configPages = config.pages;
|
||||
var configPagesKeys = config.pages ? Object.keys(configPages) : [];
|
||||
var defPages = pagesConfig(configPagesKeys);
|
||||
var pages = formatPagesConfig({ title: '', filename: '', render: '', html: config.html, window: config.window }, __assign(__assign({}, configPages), defPages));
|
||||
var ret = {
|
||||
entry: webpackEntry(env, srcDir, pages),
|
||||
output: 'development' === env ? webpackOutput(env, srcDir, void 0, void 0, void 0) : webpackOutput(env, buildDir, jsbuild, void 0, void 0),
|
||||
plugins: webpackPlugins(env, srcDir, pages, cssbuild),
|
||||
module: {
|
||||
rules: webpackRules(env, srcDir, config.postcssConfigFile),
|
||||
},
|
||||
resolve: {
|
||||
alias: webpackAlias(),
|
||||
extensions: ['.tsx', '.ts', '.jsx', '.js'],
|
||||
},
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
var isAbsolutePath$2 = require('path').isAbsolute;
|
||||
var webpack$2 = require('webpack');
|
||||
var webpackFormatMessages$1 = require('webpack-format-messages');
|
||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
var defaultOptions$2 = {
|
||||
env: 'production',
|
||||
host: '127.0.0.1',
|
||||
port: 8888,
|
||||
mode: 'static',
|
||||
config: config$3,
|
||||
};
|
||||
function analyzer(analyzerOptions) {
|
||||
if (analyzerOptions === void 0) { analyzerOptions = defaultOptions$2; }
|
||||
var options = __assign(__assign({}, defaultOptions$2), analyzerOptions);
|
||||
options.config = __assign(__assign({}, defaultOptions$2.config), analyzerOptions.config);
|
||||
var config = generateConfig(options.env, options.config);
|
||||
if (!isAbsolutePath$2(options.config.src)) {
|
||||
throw Error('"src" is not an absolute path');
|
||||
}
|
||||
if (!isAbsolutePath$2(options.config.build)) {
|
||||
throw Error('"build" is not an absolute path');
|
||||
}
|
||||
if (!isAbsolutePath$2(options.config.postcssConfigFile)) {
|
||||
throw Error('"postcssConfigFile" is not an absolute path');
|
||||
}
|
||||
var analyzerConfig = {
|
||||
analyzerMode: options.mode,
|
||||
analyzerHost: options.host,
|
||||
analyzerPort: options.port,
|
||||
generateStatsFile: 'server' !== options.mode,
|
||||
startAnalyzer: 'server' === options.mode,
|
||||
statsFilename: 'analyzer-stats.json',
|
||||
reportFilename: 'analyzer-report.html',
|
||||
};
|
||||
var compiler = 'dist' === options.env ? webpack$2(__assign(__assign({}, config$1), config)) : webpack$2(__assign(__assign({}, config$2), config));
|
||||
var analyzer = new BundleAnalyzerPlugin(analyzerConfig);
|
||||
analyzer.apply(compiler);
|
||||
compiler.run(function (err, stats) {
|
||||
if (err)
|
||||
throw err;
|
||||
var messages = webpackFormatMessages$1(stats);
|
||||
if (!messages.errors.length && !messages.warnings.length) {
|
||||
console.log('Compiled successfully!', '\n');
|
||||
}
|
||||
if (messages.errors.length) {
|
||||
console.log('Failed to compile.', '\n');
|
||||
for (var _i = 0, _a = messages.errors; _i < _a.length; _i++) {
|
||||
var m = _a[_i];
|
||||
console.log(m);
|
||||
}
|
||||
}
|
||||
else if (messages.warnings.length) {
|
||||
console.log('Compiled with warnings.', '\n');
|
||||
for (var _b = 0, _c = messages.warnings; _b < _c.length; _b++) {
|
||||
var m = _c[_b];
|
||||
console.log(m);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var isAbsolutePath$1 = require('path').isAbsolute;
|
||||
var webpack$1 = require('webpack');
|
||||
var webpackFormatMessages = require('webpack-format-messages');
|
||||
var defaultOptions$1 = {
|
||||
env: 'production',
|
||||
config: config$3,
|
||||
};
|
||||
function build(buildOptions) {
|
||||
if (buildOptions === void 0) { buildOptions = defaultOptions$1; }
|
||||
var options = __assign(__assign({}, defaultOptions$1), buildOptions);
|
||||
options.config = __assign(__assign({}, defaultOptions$1.config), buildOptions.config);
|
||||
if (!isAbsolutePath$1(options.config.src)) {
|
||||
throw Error('"src" is not an absolute path');
|
||||
}
|
||||
if (!isAbsolutePath$1(options.config.build)) {
|
||||
throw Error('"build" is not an absolute path');
|
||||
}
|
||||
if (!isAbsolutePath$1(options.config.postcssConfigFile)) {
|
||||
throw Error('"postcssConfigFile" is not an absolute path');
|
||||
}
|
||||
var config = generateConfig(options.env, options.config);
|
||||
var compiler = 'dist' === options.env ? webpack$1(__assign(__assign({}, config$1), config)) : webpack$1(__assign(__assign({}, config$2), config));
|
||||
compiler.run(function (err, stats) {
|
||||
if (err)
|
||||
throw err;
|
||||
var messages = webpackFormatMessages(stats);
|
||||
if (!messages.errors.length && !messages.warnings.length) {
|
||||
console.log('Compiled successfully!', '\n');
|
||||
}
|
||||
if (messages.errors.length) {
|
||||
console.log('Failed to compile.', '\n');
|
||||
for (var _i = 0, _a = messages.errors; _i < _a.length; _i++) {
|
||||
var m = _a[_i];
|
||||
console.log(m);
|
||||
}
|
||||
}
|
||||
else if (messages.warnings.length) {
|
||||
console.log('Compiled with warnings.', '\n');
|
||||
for (var _b = 0, _c = messages.warnings; _b < _c.length; _b++) {
|
||||
var m = _c[_b];
|
||||
console.log(m);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var config = {
|
||||
mode: 'development',
|
||||
// devtool: 'eval',
|
||||
// devtool: 'source-map',
|
||||
// devtool: 'eval-cheap-source-map',
|
||||
optimization: {
|
||||
minimize: false
|
||||
}
|
||||
};
|
||||
|
||||
function configFunc(contentBase) {
|
||||
return {
|
||||
watchOptions: {
|
||||
poll: true,
|
||||
},
|
||||
contentBase: contentBase,
|
||||
compress: true,
|
||||
hot: true
|
||||
};
|
||||
}
|
||||
|
||||
var isAbsolutePath = require('path').isAbsolute;
|
||||
var webpack = require('webpack');
|
||||
var WebpackDevServer = require('webpack-dev-server');
|
||||
var defaultOptions = {
|
||||
env: 'development',
|
||||
host: '0.0.0.0',
|
||||
port: 8080,
|
||||
config: config$3,
|
||||
};
|
||||
function dev(devOptions) {
|
||||
if (devOptions === void 0) { devOptions = defaultOptions; }
|
||||
var options = __assign(__assign({}, defaultOptions), devOptions);
|
||||
options.config = __assign(__assign({}, defaultOptions.config), devOptions.config);
|
||||
var config$1 = generateConfig(options.env, options.config);
|
||||
if (!isAbsolutePath(options.config.src)) {
|
||||
throw Error('"src" is not an absolute path');
|
||||
}
|
||||
if (!isAbsolutePath(options.config.build)) {
|
||||
throw Error('"build" is not an absolute path');
|
||||
}
|
||||
if (!isAbsolutePath(options.config.postcssConfigFile)) {
|
||||
throw Error('"postcssConfigFile" is not an absolute path');
|
||||
}
|
||||
var compilerConfig = __assign(__assign({}, config), config$1);
|
||||
var serverOptions = configFunc(options.config.src);
|
||||
WebpackDevServer.addDevServerEntrypoints(compilerConfig, serverOptions);
|
||||
var compiler = webpack(compilerConfig);
|
||||
var server = new WebpackDevServer(compiler, serverOptions);
|
||||
server.listen(options.port, options.host, function (err) {
|
||||
if (err)
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
exports.analyzer = analyzer;
|
||||
exports.build = build;
|
||||
exports.dev = dev;
|
99
frontend/packages/scripts/lib/.webpack/build.config.ts
Executable file
99
frontend/packages/scripts/lib/.webpack/build.config.ts
Executable file
@ -0,0 +1,99 @@
|
||||
import { Configuration } from 'webpack';
|
||||
|
||||
/*const chunksCacheGroups_0 = {
|
||||
commons: {
|
||||
test: /[\\/]src[\\/]/,
|
||||
name: "_commons",
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
};*/
|
||||
|
||||
/*const chunksCacheGroups_1 = {
|
||||
commons: {
|
||||
test: /[\\/]src[\\/]/,
|
||||
name: "_commons",
|
||||
// priority: -10,
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
// test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
|
||||
// test: /[\\/]node_modules[\\/](!MediaCmsPlayer)[\\/]/,
|
||||
name: "_vendors",
|
||||
// priority: -20,
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
// reuseExistingChunk: true,
|
||||
},
|
||||
};*/
|
||||
|
||||
/*const chunksCacheGroups_2 = {
|
||||
commons: {
|
||||
minChunks: 2,
|
||||
// maxInitialRequests: 8, // @note: Tested values from 0 to 10, and changes applied with values 0, 4, 5, 6, 7, 8.
|
||||
// minSize: 0,
|
||||
name: "_commons",
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
};*/
|
||||
|
||||
/*const chunksCacheGroups_3 = {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: "_commons",
|
||||
priority: 1,
|
||||
chunks: "initial",
|
||||
},
|
||||
};*/
|
||||
|
||||
export const config: Configuration = {
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
optimization: {
|
||||
runtimeChunk: false,
|
||||
/*splitChunks: {
|
||||
// minSize: 1000000,
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
},*/
|
||||
/*splitChunks: {
|
||||
// minSize: 1000000,
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: chunksCacheGroups_0,
|
||||
},*/
|
||||
/*splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: chunksCacheGroups_1,
|
||||
},*/
|
||||
/*splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: chunksCacheGroups_2,
|
||||
},*/
|
||||
/*splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: chunksCacheGroups_3,
|
||||
},*/
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: '_commons',
|
||||
priority: 1,
|
||||
chunks: 'initial',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
12
frontend/packages/scripts/lib/.webpack/dev-server.config.ts
Executable file
12
frontend/packages/scripts/lib/.webpack/dev-server.config.ts
Executable file
@ -0,0 +1,12 @@
|
||||
import { Configuration } from 'webpack-dev-server';
|
||||
|
||||
export function configFunc(contentBase: string): Configuration {
|
||||
return {
|
||||
watchOptions: {
|
||||
poll: true,
|
||||
},
|
||||
contentBase: contentBase,
|
||||
compress: true,
|
||||
hot: true,
|
||||
};
|
||||
}
|
11
frontend/packages/scripts/lib/.webpack/dev.config.ts
Executable file
11
frontend/packages/scripts/lib/.webpack/dev.config.ts
Executable file
@ -0,0 +1,11 @@
|
||||
import { Configuration } from 'webpack';
|
||||
|
||||
export const config: Configuration = {
|
||||
mode: 'development',
|
||||
// devtool: 'eval',
|
||||
// devtool: 'source-map',
|
||||
// devtool: 'eval-cheap-source-map',
|
||||
optimization: {
|
||||
minimize: false,
|
||||
},
|
||||
};
|
73
frontend/packages/scripts/lib/.webpack/dist.config.ts
Executable file
73
frontend/packages/scripts/lib/.webpack/dist.config.ts
Executable file
@ -0,0 +1,73 @@
|
||||
import { Configuration } from 'webpack';
|
||||
|
||||
/*const chunksCacheGroups_0 = {
|
||||
commons: {
|
||||
test: /[\\/]src[\\/]/,
|
||||
name: "_commons",
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
};
|
||||
|
||||
const chunksCacheGroups_1 = {
|
||||
commons: {
|
||||
test: /[\\/]src[\\/]/,
|
||||
name: "_commons",
|
||||
// priority: -10,
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
// test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
|
||||
// test: /[\\/]node_modules[\\/](!MediaCmsPlayer)[\\/]/,
|
||||
name: "_vendors",
|
||||
// priority: -20,
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
// reuseExistingChunk: true,
|
||||
},
|
||||
};
|
||||
|
||||
const chunksCacheGroups_2 = {
|
||||
commons: {
|
||||
minChunks: 2,
|
||||
// maxInitialRequests: 8, // @note: Tested values from 0 to 10, and changes applied with values 0, 4, 5, 6, 7, 8.
|
||||
// minSize: 0,
|
||||
name: "_commons",
|
||||
chunks: "all",
|
||||
enforce: true,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
};
|
||||
|
||||
const chunksCacheGroups_3 = {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: "_commons",
|
||||
priority: 1,
|
||||
chunks: "initial",
|
||||
},
|
||||
};*/
|
||||
|
||||
export const config: Configuration = {
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
minimize: true,
|
||||
runtimeChunk: false,
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
automaticNameDelimiter: '-',
|
||||
cacheGroups: {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: '_commons',
|
||||
priority: 1,
|
||||
chunks: 'initial',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
114
frontend/packages/scripts/lib/config.ts
Executable file
114
frontend/packages/scripts/lib/config.ts
Executable file
@ -0,0 +1,114 @@
|
||||
function bodySnippet(id:string) {
|
||||
return '<div id="' + id + '"></div>';
|
||||
}
|
||||
|
||||
interface ConfigHtmlHead{
|
||||
meta?: { [key: string]: string }[],
|
||||
links?: { [key: string]: string }[],
|
||||
scripts?: { [key: string]: string }[],
|
||||
}
|
||||
|
||||
interface ConfigHtmlBody{
|
||||
scripts: { [key: string]: string }[],
|
||||
snippet: string,
|
||||
}
|
||||
|
||||
export interface ConfigHtml{
|
||||
head: ConfigHtmlHead,
|
||||
body: ConfigHtmlBody,
|
||||
}
|
||||
|
||||
export interface ConfigPages{
|
||||
[key: string]: ConfigPage
|
||||
}
|
||||
|
||||
export interface ConfigWindow{
|
||||
[key: string ]: unknown
|
||||
}
|
||||
|
||||
export interface ConfigType {
|
||||
src: string,
|
||||
build: string,
|
||||
html: ConfigHtml,
|
||||
pages: ConfigPages,
|
||||
window: ConfigWindow,
|
||||
postcssConfigFile: string,
|
||||
}
|
||||
|
||||
export interface ConfigPage{
|
||||
staticPage: boolean,
|
||||
buildExclude: boolean,
|
||||
title: string,
|
||||
filename: string,
|
||||
html: ConfigHtml,
|
||||
window: ConfigWindow,
|
||||
render: string,
|
||||
}
|
||||
|
||||
const homePage: ConfigPage = {
|
||||
staticPage: true,
|
||||
buildExclude: false,
|
||||
title: 'Home',
|
||||
filename: 'index.html',
|
||||
html: {
|
||||
head: {},
|
||||
body: {
|
||||
scripts: [],
|
||||
snippet: bodySnippet('page-home'),
|
||||
}
|
||||
},
|
||||
window: {},
|
||||
render: 'import { renderPage } from \'./js/helpers\'; import { HomePage } from \'./js/pages/HomePage\'; renderPage( \'page-home\', HomePage );',
|
||||
};
|
||||
|
||||
const errorPage: ConfigPage = {
|
||||
staticPage: true,
|
||||
buildExclude: false,
|
||||
title: 'Error',
|
||||
filename: 'error.html',
|
||||
html: {
|
||||
head: {},
|
||||
body: {
|
||||
scripts: [],
|
||||
snippet: bodySnippet('page-error'),
|
||||
}
|
||||
},
|
||||
window: {},
|
||||
render: 'import { renderPage } from \'./js/helpers\'; import { ErrorPage } from \'./js/pages/ErrorPage\'; renderPage( \'page-error\', ErrorPage );',
|
||||
};
|
||||
|
||||
const pages: { [key: string]: ConfigPage } = {
|
||||
home: homePage,
|
||||
error: errorPage,
|
||||
};
|
||||
|
||||
const htmlHead: ConfigHtmlHead = {
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ content: 'ie=edge', 'http-equiv': 'x-ua-compatible' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
],
|
||||
links: [],
|
||||
scripts: [],
|
||||
};
|
||||
|
||||
const htmlBody: ConfigHtmlBody = {
|
||||
scripts: [],
|
||||
snippet: '',
|
||||
};
|
||||
|
||||
const html: ConfigHtml = {
|
||||
head: htmlHead,
|
||||
body: htmlBody,
|
||||
};
|
||||
|
||||
export const config : ConfigType = {
|
||||
src: '',
|
||||
build: '',
|
||||
pages,
|
||||
html,
|
||||
window: {},
|
||||
postcssConfigFile: '',
|
||||
};
|
||||
|
||||
export default config;
|
21
frontend/packages/scripts/lib/interfaces/OptionsTypes.ts
Executable file
21
frontend/packages/scripts/lib/interfaces/OptionsTypes.ts
Executable file
@ -0,0 +1,21 @@
|
||||
import { ConfigType } from '../config';
|
||||
|
||||
export interface DevOptionsType {
|
||||
env: string,
|
||||
host: string,
|
||||
port: number,
|
||||
config: ConfigType,
|
||||
}
|
||||
|
||||
export interface BuildOptionsType {
|
||||
env: string,
|
||||
config: ConfigType,
|
||||
}
|
||||
|
||||
export interface AnalyzerOptionsType {
|
||||
env: string,
|
||||
host: string,
|
||||
port: number,
|
||||
mode: string,
|
||||
config: ConfigType,
|
||||
}
|
69
frontend/packages/scripts/lib/webpack-helpers/formatPagesConfig.ts
Executable file
69
frontend/packages/scripts/lib/webpack-helpers/formatPagesConfig.ts
Executable file
@ -0,0 +1,69 @@
|
||||
const merge = require('lodash.merge');
|
||||
|
||||
import { ConfigHtml, ConfigPages, ConfigWindow } from '../config';
|
||||
|
||||
function validateBoolean(value?: boolean | 0 | 1, defaultValue = false): boolean {
|
||||
|
||||
if (true === value || false === value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (0 === value || 1 === value) {
|
||||
return !!value;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
function validateString(value?: string, defaultValue = ''): string {
|
||||
return value ? value : defaultValue;
|
||||
}
|
||||
|
||||
function getArrayType(sourcesArr?: Array<{ [key: string]: string }>, pageArr: Array<{ [key: string]: string }> = []): Array<{ [key: string]: string }> {
|
||||
|
||||
if ((!sourcesArr || !sourcesArr.length) && (!pageArr || !pageArr.length)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (sourcesArr && sourcesArr.length && pageArr && pageArr.length) {
|
||||
return sourcesArr.concat(pageArr);
|
||||
}
|
||||
|
||||
if (sourcesArr && sourcesArr.length) {
|
||||
return sourcesArr;
|
||||
}
|
||||
|
||||
return pageArr;
|
||||
}
|
||||
|
||||
function formatPagesConfig(sources: { title: string, filename: string, render: string, html: ConfigHtml, window: ConfigWindow }, pages: ConfigPages): ConfigPages {
|
||||
|
||||
const ret: ConfigPages = {};
|
||||
|
||||
for (const pk in pages) {
|
||||
|
||||
ret[pk] = {
|
||||
staticPage: validateBoolean(pages[pk].staticPage, false),
|
||||
buildExclude: validateBoolean(pages[pk].buildExclude, false),
|
||||
title: validateString(pages[pk].title, sources.title),
|
||||
filename: validateString(pages[pk].filename, sources.filename),
|
||||
html: {
|
||||
head: {
|
||||
meta: getArrayType(sources.html.head.meta, pages[pk].html.head.meta),
|
||||
links: getArrayType(sources.html.head.links, pages[pk].html.head.links),
|
||||
scripts: getArrayType(sources.html.head.scripts, pages[pk].html.head.scripts),
|
||||
},
|
||||
body: {
|
||||
scripts: getArrayType(sources.html.body.scripts, pages[pk].html.body.scripts),
|
||||
snippet: validateString(pages[pk].html.body.snippet, sources.html.body.snippet),
|
||||
},
|
||||
},
|
||||
window: merge({}, sources.window, pages[pk].window),
|
||||
render: validateString(sources.render, pages[pk].render),
|
||||
};
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
export default formatPagesConfig;
|
308
frontend/packages/scripts/lib/webpack-helpers/generateConfig.ts
Executable file
308
frontend/packages/scripts/lib/webpack-helpers/generateConfig.ts
Executable file
@ -0,0 +1,308 @@
|
||||
const path = require('path');
|
||||
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
|
||||
|
||||
// Webpack plugins.
|
||||
const { DefinePlugin } = require('webpack');
|
||||
const { LimitChunkCountPlugin } = require('webpack').optimize;
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const VirtualModulesPlugin = require('webpack-virtual-modules');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
|
||||
var dotenv = require('dotenv').config({ path: path.resolve(__dirname + '../../../../.env') });
|
||||
|
||||
import MyHtmlBeautifyWebpackPlugin from '../webpack-plugins/MyHtmlBeautifyWebpackPlugin';
|
||||
|
||||
import { ConfigType, ConfigPages } from '../config';
|
||||
|
||||
import defaultPages from './pagesConfig';
|
||||
|
||||
import formatPagesConfig from './formatPagesConfig';
|
||||
|
||||
function webpackEntry(env: string, srcDir: string, pages: ConfigPages) {
|
||||
|
||||
const ret: { [key: string]: string } = {};
|
||||
|
||||
for (const p in pages) {
|
||||
|
||||
if ('development' === env || !pages[p].buildExclude) {
|
||||
ret[p] = path.resolve(srcDir + '/' + p + '.js');
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function webpackOutput(env: string, destinationDir: string, buildDir?: string, chunkhash?: string, hash?: string) {
|
||||
|
||||
const ret = {
|
||||
path: destinationDir,
|
||||
filename: '',
|
||||
};
|
||||
|
||||
const prefix = 'development' === env ? '' : buildDir;
|
||||
|
||||
let tmp;
|
||||
|
||||
if (undefined !== chunkhash) {
|
||||
|
||||
tmp = chunkhash.trim();
|
||||
|
||||
if ('' === tmp) {
|
||||
throw Error('Invalid chunkhash argument value: ' + chunkhash);
|
||||
}
|
||||
|
||||
ret.filename = (prefix || '') + '[name]-[chunkhash].js';
|
||||
}
|
||||
else if (undefined !== hash) {
|
||||
|
||||
tmp = hash.trim();
|
||||
|
||||
if ('' === tmp) {
|
||||
throw Error('Invalid hash argument value: ' + hash);
|
||||
}
|
||||
|
||||
ret.filename = (prefix || '') + '[name]-[hash].js';
|
||||
}
|
||||
else {
|
||||
ret.filename = (prefix || '') + '[name].js';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function webpackAlias() {
|
||||
|
||||
return {
|
||||
// modernizr$: path.resolve(__dirname, "../../.modernizrrc"), // TODO: Enable this?
|
||||
};
|
||||
}
|
||||
|
||||
function webpackRules(env: string, srcDir: string, postcssConfigFile: string): any[] {
|
||||
|
||||
return [{
|
||||
test: /\.(jsx|js)?$/,
|
||||
use: 'babel-loader'
|
||||
},
|
||||
{
|
||||
test: /\.(tsx|ts)?$/,
|
||||
use: 'ts-loader',
|
||||
// exclude: /node_modules/,
|
||||
// options: {
|
||||
// compilerOptions: {
|
||||
// "sourceMap": !isProduction,
|
||||
// },
|
||||
// },
|
||||
},
|
||||
{
|
||||
test: /\.ejs$/,
|
||||
use: {
|
||||
loader: 'ejs-compiled-loader',
|
||||
options: {
|
||||
// beautify: true,
|
||||
htmlmin: true,
|
||||
// htmlminOptions: {
|
||||
// removeComments: true,
|
||||
// collapseWhitespace: true,
|
||||
// preserveLineBreaks: true
|
||||
// }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(sa|sc|c)ss$/,
|
||||
use: [
|
||||
{ loader: MiniCssExtractPlugin.loader },
|
||||
// { loader: 'development' === env ? MiniCssExtractPlugin.loader : 'style-loader' }, // Use inline <style> tag.
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{ loader: 'postcss-loader', options: { postcssOptions: { config: postcssConfigFile } } },
|
||||
{ loader: 'sass-loader' },
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.module\.(sa|sc|c)ss$/,
|
||||
use: [
|
||||
{ loader: MiniCssExtractPlugin.loader },
|
||||
// { loader: 'development' === env ? MiniCssExtractPlugin.loader : 'style-loader' }, // Use inline <style> tag.
|
||||
{ loader: 'css-loader', options: { importLoaders: 1, modules: true, onlyLocals: false } },
|
||||
{ loader: 'postcss-loader', options: { postcssOptions: { config: postcssConfigFile } } },
|
||||
{ loader: 'sass-loader' },
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)(\?\S*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 1024,
|
||||
fallback: 'file-loader',
|
||||
name: (file: string) => {
|
||||
return '.' + path.join(file.replace(srcDir, ''), '..').replace(/\\/g, '/') + '/[name].[ext]';
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
||||
/*issuer: {
|
||||
test: /\.jsx?$/
|
||||
},*/
|
||||
use: ['babel-loader', '@svgr/webpack', 'url-loader']
|
||||
},
|
||||
{
|
||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
||||
loader: 'url-loader'
|
||||
},
|
||||
{
|
||||
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: (file: string) => {
|
||||
return '.' + path.join(file.replace(srcDir, ''), '..').replace(/\\/g, '/') + '/[name].[ext]';
|
||||
},
|
||||
}
|
||||
}]
|
||||
},
|
||||
{
|
||||
test: /\.modernizrrc.js$/,
|
||||
use: 'modernizr-loader',
|
||||
},
|
||||
{
|
||||
test: /\.modernizrrc(\.json)?$/,
|
||||
use: ['modernizr-loader', 'json-loader'],
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
function webpackPlugins(env: string, srcDir: string, pages: ConfigPages, cssSrc: string) {
|
||||
|
||||
const ret = [
|
||||
new DefinePlugin({ "process.env": JSON.stringify(dotenv.parsed) }),
|
||||
new NodePolyfillPlugin(),
|
||||
new MyHtmlBeautifyWebpackPlugin(),
|
||||
];
|
||||
|
||||
if ('development' !== env) {
|
||||
ret.push(
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: path.resolve(__dirname, '../../../src/static/lib'),
|
||||
to: path.resolve(__dirname, '../../../' + env + '/static/lib'),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, '../../../src/static/images'),
|
||||
to: path.resolve(__dirname, '../../../' + env + '/static/images'),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, '../../../src/static/favicons'),
|
||||
to: path.resolve(__dirname, '../../../' + env + '/static/favicons'),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, '../../../src/static/css/_extra.css'),
|
||||
to: path.resolve(__dirname, '../../../' + env + '/static/css/_extra.css'),
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const virtualPages: { [key: string]: string } = {};
|
||||
|
||||
let file: string;
|
||||
|
||||
for (const k in pages) {
|
||||
|
||||
if ('production' !== env || !pages[k].buildExclude) {
|
||||
|
||||
file = path.resolve(srcDir + '/' + k + '.js');
|
||||
|
||||
if ((void 0 !== pages[k].staticPage && pages[k].staticPage) || void 0 === pages[k].render) {
|
||||
virtualPages[file] = '';
|
||||
} else {
|
||||
virtualPages[file] = pages[k].render;
|
||||
}
|
||||
}
|
||||
|
||||
if ('development' === env) {
|
||||
// Export pages HTML files.
|
||||
ret.push(new HtmlWebpackPlugin({
|
||||
template: path.resolve(__dirname, '../templates/index.ejs'),
|
||||
hash: false,
|
||||
chunks: [k],
|
||||
...pages[k],
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
ret.push(new VirtualModulesPlugin(virtualPages));
|
||||
|
||||
ret.push(new MiniCssExtractPlugin({
|
||||
ignoreOrder: true, // TODO: Remove it...
|
||||
// filename: ! is_build ? '[name].css' : '[name].[hash].css',
|
||||
// chunkFilename: ! is_build ? '[id].css' : '[id].[hash].css',
|
||||
filename: cssSrc + '[name].css',
|
||||
// chunkFilename: "../css/[id].css",
|
||||
}));
|
||||
|
||||
if ('development' !== env) {
|
||||
ret.push(new LimitChunkCountPlugin({ maxChunks: 1 }));
|
||||
ret.push(
|
||||
new ProgressBarPlugin({
|
||||
clear: false,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if ('production' === env) {
|
||||
ret.push(new CssMinimizerPlugin({
|
||||
cache: true, // TODO: Ignore in Webpack 5. Use https://webpack.js.org/configuration/other-options/#cache.
|
||||
minimizerOptions: {
|
||||
preset: [
|
||||
'default',
|
||||
{
|
||||
discardComments: { removeAll: true },
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
export default function generateConfig(env: string, config: ConfigType) {
|
||||
|
||||
const srcDir = config.src;
|
||||
const buildDir = config.build + '/' + env + ('development' === env ? '' : '/static');
|
||||
|
||||
const cssbuild = './css/';
|
||||
const jsbuild = './js/';
|
||||
|
||||
const configPages = config.pages;
|
||||
const configPagesKeys = config.pages ? Object.keys(configPages) : [];
|
||||
const defPages = defaultPages(configPagesKeys);
|
||||
|
||||
const pages = formatPagesConfig(
|
||||
{ title: '', filename: '', render: '', html: config.html, window: config.window },
|
||||
{ ...configPages, ...defPages }
|
||||
);
|
||||
|
||||
const ret = {
|
||||
entry: webpackEntry(env, srcDir, pages),
|
||||
output: 'development' === env ? webpackOutput(env, srcDir, void 0, void 0, void 0) : webpackOutput(env, buildDir, jsbuild, void 0, void 0),
|
||||
plugins: webpackPlugins(env, srcDir, pages, cssbuild),
|
||||
module: {
|
||||
rules: webpackRules(env, srcDir, config.postcssConfigFile),
|
||||
},
|
||||
resolve: {
|
||||
alias: webpackAlias(),
|
||||
extensions: ['.tsx', '.ts', '.jsx', '.js'],
|
||||
},
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
37
frontend/packages/scripts/lib/webpack-helpers/pagesConfig.ts
Executable file
37
frontend/packages/scripts/lib/webpack-helpers/pagesConfig.ts
Executable file
@ -0,0 +1,37 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ejs = require('ejs');
|
||||
|
||||
const templatePath = path.join(__dirname, '../templates');
|
||||
const sitemapTemplatePath = path.join(templatePath, 'sitemap.ejs');
|
||||
|
||||
const sitemapTemplate = ejs.compile(fs.readFileSync(sitemapTemplatePath, 'utf8'), { root: [templatePath], filename: sitemapTemplatePath, outputFunctionName: 'echo' });
|
||||
|
||||
import { ConfigPages } from '../config';
|
||||
|
||||
export default function pagesConfig(pagesKeys: string[]): ConfigPages {
|
||||
|
||||
const pages: ConfigPages = {};
|
||||
|
||||
if (-1 === pagesKeys.indexOf('sitemap')) {
|
||||
|
||||
pages.sitemap = {
|
||||
staticPage: true,
|
||||
buildExclude: true,
|
||||
title: 'Sitemap',
|
||||
filename: 'sitemap.html',
|
||||
html: {
|
||||
head: {},
|
||||
body: {
|
||||
scripts: [],
|
||||
snippet: sitemapTemplate({ pages: [...pagesKeys, ...Object.keys(pages)] }),
|
||||
},
|
||||
},
|
||||
window: {},
|
||||
render: ''
|
||||
};
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
74
frontend/packages/scripts/lib/webpack-plugins/MyHtmlBeautifyWebpackPlugin.ts
Executable file
74
frontend/packages/scripts/lib/webpack-plugins/MyHtmlBeautifyWebpackPlugin.ts
Executable file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @see {link: https://github.com/seeyoulater/html-beautify-webpack-plugin/blob/master/index.js}
|
||||
*/
|
||||
|
||||
const prettify = require('html-prettify');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
const WebpackError = require( 'webpack/lib/WebpackError.js' );
|
||||
|
||||
import { Compiler, Compilation } from 'webpack';
|
||||
|
||||
interface OptionsConfigHtml {
|
||||
end_with_newline: boolean,
|
||||
indent_inner_html: boolean,
|
||||
preserve_newlines: boolean,
|
||||
max_preserve_newlines: number,
|
||||
}
|
||||
|
||||
interface OptionsConfig {
|
||||
indent_size: number,
|
||||
indent_with_tabs: boolean,
|
||||
html: OptionsConfigHtml
|
||||
}
|
||||
|
||||
interface Options{
|
||||
config: OptionsConfig,
|
||||
replace: Array<string|RegExp>
|
||||
}
|
||||
|
||||
interface HtmlWebpackPluginArgs{
|
||||
html: string,
|
||||
plugin: typeof HtmlWebpackPlugin,
|
||||
outputName: string
|
||||
}
|
||||
|
||||
function htmlPluginDataFunction (pluginData: HtmlWebpackPluginArgs, options: Options, callback: (err:typeof WebpackError, arg1: HtmlWebpackPluginArgs) => void) {
|
||||
|
||||
pluginData.html = prettify(
|
||||
options.replace.reduce( (res:string, item: string | RegExp) => res.replace( item instanceof RegExp ? new RegExp(item, 'gi') : item, '' ), pluginData.html )/*,
|
||||
options.config*/
|
||||
);
|
||||
|
||||
callback(null, pluginData);
|
||||
}
|
||||
|
||||
export default class MyHtmlBeautifyWebpackPlugin {
|
||||
|
||||
apply(compiler: Compiler): void {
|
||||
|
||||
const options: Options = {
|
||||
config: { // TODO: Remove it.
|
||||
indent_size: 4,
|
||||
indent_with_tabs: false,
|
||||
html: {
|
||||
end_with_newline: true,
|
||||
indent_inner_html: true,
|
||||
preserve_newlines: true,
|
||||
max_preserve_newlines: 0,
|
||||
}
|
||||
},
|
||||
replace: []
|
||||
};
|
||||
|
||||
function tapAsyncCallback(pluginData: HtmlWebpackPluginArgs, callback: (err:typeof WebpackError, arg1: HtmlWebpackPluginArgs) => void ){
|
||||
return htmlPluginDataFunction (pluginData, options, callback);
|
||||
}
|
||||
|
||||
function tapHookCallback(compilation: Compilation){
|
||||
return HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync( 'MyHtmlBeautifyWebpackPlugin', tapAsyncCallback );
|
||||
}
|
||||
|
||||
compiler.hooks.compilation.tap( 'MyHtmlBeautifyWebpackPlugin', tapHookCallback );
|
||||
}
|
||||
}
|
10148
frontend/packages/scripts/package-lock.json
generated
Normal file
10148
frontend/packages/scripts/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
86
frontend/packages/scripts/package.json
Normal file
86
frontend/packages/scripts/package.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"name": "mediacms-scripts",
|
||||
"version": "0.9.0",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"license": "",
|
||||
"engines": {
|
||||
"node": ">=14.17.0"
|
||||
},
|
||||
"files": [
|
||||
"scripts",
|
||||
"cli.js"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "npx rollup -w -c ./config/watch.config.js",
|
||||
"build": "npx rollup -c ./config/build.config.js",
|
||||
"visual": "npx rollup -c ./config/visual.config.js"
|
||||
},
|
||||
"bin": {
|
||||
"mediacms-scripts": "./cli.js"
|
||||
},
|
||||
"types": "",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.14.5",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@types/react": "^17.0.11",
|
||||
"@types/react-dom": "^17.0.7",
|
||||
"axios": "^0.21.1",
|
||||
"babel-core": "^6.26.3",
|
||||
"copy-webpack-plugin": "^9.0.0",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"dotenv": "^10.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.51.2",
|
||||
"rollup-plugin-cleanup": "^3.2.1",
|
||||
"rollup-plugin-typescript2": "^0.30.0",
|
||||
"rollup-plugin-visualizer": "^5.5.0",
|
||||
"serialize-javascript": "^5.0.1",
|
||||
"source-map-loader": "^3.0.0",
|
||||
"ts-loader": "^9.2.3",
|
||||
"typescript": "^4.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"@types/webpack-bundle-analyzer": "^4.4.0",
|
||||
"@types/webpack-dev-server": "^3.11.4",
|
||||
"autoprefixer": "^10.2.6",
|
||||
"babel-loader": "^8.2.2",
|
||||
"css-loader": "^5.2.6",
|
||||
"css-minimizer-webpack-plugin": "^3.0.1",
|
||||
"ejs": "^3.1.6",
|
||||
"ejs-compiled-loader": "^3.1.0",
|
||||
"ejs-loader": "^0.5.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-prettify": "^1.0.3",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"json-loader": "^0.5.7",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"mini-css-extract-plugin": "^1.6.0",
|
||||
"node-polyfill-webpack-plugin": "^1.1.2",
|
||||
"node-sass": "^6.0.0",
|
||||
"postcss": "^8.3.2",
|
||||
"postcss-import": "^14.0.2",
|
||||
"postcss-loader": "^6.1.0",
|
||||
"postcss-modules": "^4.1.3",
|
||||
"postcss-nested": "^5.0.5",
|
||||
"postcss-scss": "^3.0.5",
|
||||
"progress-bar-webpack-plugin": "^2.1.0",
|
||||
"sass-loader": "^12.1.0",
|
||||
"style-loader": "^2.0.0",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.38.1",
|
||||
"webpack-bundle-analyzer": "^4.4.2",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"webpack-format-messages": "^2.0.6",
|
||||
"webpack-virtual-modules": "^0.4.3"
|
||||
},
|
||||
"peerDependenciesMeta": {},
|
||||
"browserslist": {}
|
||||
}
|
5
frontend/packages/scripts/scripts/analyzer.js
Normal file
5
frontend/packages/scripts/scripts/analyzer.js
Normal file
@ -0,0 +1,5 @@
|
||||
const { analyzer } = require('../dist/webpack-dev-env.js');
|
||||
const parseCliArgs = require('./utils/parseCliArgs.js');
|
||||
const { validateAnalyzerOptions } = require('./utils/validateOptions.js');
|
||||
const options = validateAnalyzerOptions(parseCliArgs(process.argv.slice(2)));
|
||||
analyzer(options);
|
5
frontend/packages/scripts/scripts/build.js
Normal file
5
frontend/packages/scripts/scripts/build.js
Normal file
@ -0,0 +1,5 @@
|
||||
const { build } = require('../dist/webpack-dev-env.js');
|
||||
const parseCliArgs = require('./utils/parseCliArgs.js');
|
||||
const { validateBuildOptions } = require('./utils/validateOptions.js');
|
||||
const options = validateBuildOptions(parseCliArgs(process.argv.slice(2)));
|
||||
build(options);
|
5
frontend/packages/scripts/scripts/development.js
Normal file
5
frontend/packages/scripts/scripts/development.js
Normal file
@ -0,0 +1,5 @@
|
||||
const { dev } = require('../dist/webpack-dev-env.js');
|
||||
const parseCliArgs = require('./utils/parseCliArgs.js');
|
||||
const { validateDevOptions } = require('./utils/validateOptions.js');
|
||||
const options = validateDevOptions(parseCliArgs(process.argv.slice(2)));
|
||||
dev(options);
|
20
frontend/packages/scripts/scripts/mkdir.js
Executable file
20
frontend/packages/scripts/scripts/mkdir.js
Executable file
@ -0,0 +1,20 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var cliArgs = process.argv.slice(2);
|
||||
|
||||
function mkdir_callback(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
var i, dir;
|
||||
|
||||
for (i = 0; i < cliArgs.length; i++) {
|
||||
dir = path.resolve(cliArgs[i]);
|
||||
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, mkdir_callback);
|
||||
}
|
||||
}
|
21
frontend/packages/scripts/scripts/rimraf.js
Normal file
21
frontend/packages/scripts/scripts/rimraf.js
Normal file
@ -0,0 +1,21 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var rimraf = require('rimraf');
|
||||
|
||||
var cliArgs = process.argv.slice(2);
|
||||
|
||||
function rmdir_callback(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
var i, dir;
|
||||
|
||||
for (i = 0; i < cliArgs.length; i++) {
|
||||
dir = path.resolve(cliArgs[i]);
|
||||
|
||||
if (fs.existsSync(dir)) {
|
||||
rimraf.sync(dir, {}, rmdir_callback);
|
||||
}
|
||||
}
|
21
frontend/packages/scripts/scripts/utils/parseCliArgs.js
Normal file
21
frontend/packages/scripts/scripts/utils/parseCliArgs.js
Normal file
@ -0,0 +1,21 @@
|
||||
function parseCliArgsFn(cliArgs) {
|
||||
const ret = {};
|
||||
|
||||
let arr;
|
||||
|
||||
for (let arg of cliArgs) {
|
||||
arr = arg.split('--');
|
||||
|
||||
if (2 === arr.length) {
|
||||
arr = arr[1].split('=');
|
||||
|
||||
if (2 === arr.length) {
|
||||
ret[arr[0]] = arr[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
module.exports = parseCliArgsFn;
|
94
frontend/packages/scripts/scripts/utils/validateOptions.js
Normal file
94
frontend/packages/scripts/scripts/utils/validateOptions.js
Normal file
@ -0,0 +1,94 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function validateDevOptions(options) {
|
||||
if (void 0 !== options.config) {
|
||||
if ('string' !== typeof options.config) {
|
||||
throw Error('Invalid configuration file: ' + options.config);
|
||||
}
|
||||
|
||||
options.config = path.resolve(options.config);
|
||||
|
||||
if (!fs.existsSync(options.config)) {
|
||||
throw Error('Invalid configuration file: ' + options.config);
|
||||
}
|
||||
|
||||
options.config = require(path.resolve(options.config));
|
||||
}
|
||||
|
||||
if (void 0 !== options.env) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
if (void 0 !== options.host) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
if (void 0 !== options.port) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function validateBuildOptions(options) {
|
||||
if (void 0 !== options.config) {
|
||||
if ('string' !== typeof options.config) {
|
||||
throw Error('Invalid configuration file: ' + options.config);
|
||||
}
|
||||
|
||||
options.config = path.resolve(options.config);
|
||||
|
||||
if (!fs.existsSync(options.config)) {
|
||||
throw Error('Invalid configuration file: ' + options.config);
|
||||
}
|
||||
|
||||
options.config = require(path.resolve(options.config));
|
||||
}
|
||||
|
||||
if (void 0 !== options.env) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function validateAnalyzerOptions(options) {
|
||||
if (void 0 !== options.config) {
|
||||
if ('string' !== typeof options.config) {
|
||||
throw Error('Invalid configuration file: ' + options.config);
|
||||
}
|
||||
|
||||
options.config = path.resolve(options.config);
|
||||
|
||||
if (!fs.existsSync(options.config)) {
|
||||
throw Error('Invalid configuration file: ' + options.config);
|
||||
}
|
||||
|
||||
options.config = require(path.resolve(options.config));
|
||||
}
|
||||
|
||||
if (void 0 !== options.env) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
if (void 0 !== options.host) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
if (void 0 !== options.port) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
if (void 0 !== options.mode) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
validateDevOptions,
|
||||
validateBuildOptions,
|
||||
validateAnalyzerOptions,
|
||||
};
|
84
frontend/packages/scripts/src/analyzer.ts
Executable file
84
frontend/packages/scripts/src/analyzer.ts
Executable file
@ -0,0 +1,84 @@
|
||||
const isAbsolutePath = require('path').isAbsolute;
|
||||
|
||||
const webpack = require('webpack');
|
||||
const webpackFormatMessages = require('webpack-format-messages');
|
||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||
|
||||
import { config as defaultConfig } from '../lib/config';
|
||||
|
||||
import { AnalyzerOptionsType } from '../lib/interfaces/OptionsTypes';
|
||||
|
||||
import { config as buildWebpackConfig } from '../lib/.webpack/build.config';
|
||||
import { config as distWebpackConfig } from '../lib/.webpack/dist.config';
|
||||
|
||||
import generateConfig from '../lib/webpack-helpers/generateConfig';
|
||||
|
||||
const defaultOptions: AnalyzerOptionsType = {
|
||||
env: 'production',
|
||||
host: '127.0.0.1',
|
||||
port: 8888,
|
||||
mode: 'static',
|
||||
config: defaultConfig,
|
||||
};
|
||||
|
||||
export function analyzer(analyzerOptions: AnalyzerOptionsType = defaultOptions): void {
|
||||
const options: AnalyzerOptionsType = { ...defaultOptions, ...analyzerOptions };
|
||||
|
||||
options.config = { ...defaultOptions.config, ...analyzerOptions.config };
|
||||
|
||||
const config = generateConfig(options.env, options.config);
|
||||
|
||||
if (!isAbsolutePath(options.config.src)) {
|
||||
throw Error('"src" is not an absolute path');
|
||||
}
|
||||
|
||||
if (!isAbsolutePath(options.config.build)) {
|
||||
throw Error('"build" is not an absolute path');
|
||||
}
|
||||
|
||||
if (!isAbsolutePath(options.config.postcssConfigFile)) {
|
||||
throw Error('"postcssConfigFile" is not an absolute path');
|
||||
}
|
||||
|
||||
const analyzerConfig = {
|
||||
analyzerMode: options.mode,
|
||||
analyzerHost: options.host,
|
||||
analyzerPort: options.port,
|
||||
generateStatsFile: 'server' !== options.mode,
|
||||
startAnalyzer: 'server' === options.mode,
|
||||
statsFilename: 'analyzer-stats.json',
|
||||
reportFilename: 'analyzer-report.html',
|
||||
};
|
||||
|
||||
const compiler =
|
||||
'dist' === options.env
|
||||
? webpack({ ...distWebpackConfig, ...config })
|
||||
: webpack({ ...buildWebpackConfig, ...config });
|
||||
const analyzer = new BundleAnalyzerPlugin(analyzerConfig);
|
||||
|
||||
analyzer.apply(compiler);
|
||||
|
||||
compiler.run((err?: Error, stats?: any) => {
|
||||
if (err) throw err;
|
||||
|
||||
const messages = webpackFormatMessages(stats);
|
||||
|
||||
if (!messages.errors.length && !messages.warnings.length) {
|
||||
console.log('Compiled successfully!', '\n');
|
||||
}
|
||||
|
||||
if (messages.errors.length) {
|
||||
console.log('Failed to compile.', '\n');
|
||||
|
||||
for (const m of messages.errors) {
|
||||
console.log(m);
|
||||
}
|
||||
} else if (messages.warnings.length) {
|
||||
console.log('Compiled with warnings.', '\n');
|
||||
|
||||
for (const m of messages.warnings) {
|
||||
console.log(m);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
67
frontend/packages/scripts/src/build.ts
Executable file
67
frontend/packages/scripts/src/build.ts
Executable file
@ -0,0 +1,67 @@
|
||||
const isAbsolutePath = require('path').isAbsolute;
|
||||
|
||||
const webpack = require('webpack');
|
||||
const webpackFormatMessages = require('webpack-format-messages');
|
||||
|
||||
import { config as defaultConfig } from '../lib/config';
|
||||
|
||||
import { BuildOptionsType } from '../lib/interfaces/OptionsTypes';
|
||||
|
||||
import { config as buildWebpackConfig } from '../lib/.webpack/build.config';
|
||||
import { config as distWebpackConfig } from '../lib/.webpack/dist.config';
|
||||
|
||||
import generateConfig from '../lib/webpack-helpers/generateConfig';
|
||||
|
||||
const defaultOptions: BuildOptionsType = {
|
||||
env: 'production',
|
||||
config: defaultConfig,
|
||||
};
|
||||
|
||||
export function build(buildOptions: BuildOptionsType = defaultOptions): void {
|
||||
const options: BuildOptionsType = { ...defaultOptions, ...buildOptions };
|
||||
|
||||
options.config = { ...defaultOptions.config, ...buildOptions.config };
|
||||
|
||||
if (!isAbsolutePath(options.config.src)) {
|
||||
throw Error('"src" is not an absolute path');
|
||||
}
|
||||
|
||||
if (!isAbsolutePath(options.config.build)) {
|
||||
throw Error('"build" is not an absolute path');
|
||||
}
|
||||
|
||||
if (!isAbsolutePath(options.config.postcssConfigFile)) {
|
||||
throw Error('"postcssConfigFile" is not an absolute path');
|
||||
}
|
||||
|
||||
const config = generateConfig(options.env, options.config);
|
||||
|
||||
const compiler =
|
||||
'dist' === options.env
|
||||
? webpack({ ...distWebpackConfig, ...config })
|
||||
: webpack({ ...buildWebpackConfig, ...config });
|
||||
|
||||
compiler.run((err?: Error, stats?: any) => {
|
||||
if (err) throw err;
|
||||
|
||||
const messages = webpackFormatMessages(stats);
|
||||
|
||||
if (!messages.errors.length && !messages.warnings.length) {
|
||||
console.log('Compiled successfully!', '\n');
|
||||
}
|
||||
|
||||
if (messages.errors.length) {
|
||||
console.log('Failed to compile.', '\n');
|
||||
|
||||
for (const m of messages.errors) {
|
||||
console.log(m);
|
||||
}
|
||||
} else if (messages.warnings.length) {
|
||||
console.log('Compiled with warnings.', '\n');
|
||||
|
||||
for (const m of messages.warnings) {
|
||||
console.log(m);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
52
frontend/packages/scripts/src/dev.ts
Executable file
52
frontend/packages/scripts/src/dev.ts
Executable file
@ -0,0 +1,52 @@
|
||||
const isAbsolutePath = require('path').isAbsolute;
|
||||
|
||||
const webpack = require('webpack');
|
||||
const WebpackDevServer = require('webpack-dev-server');
|
||||
|
||||
import { config as defaultConfig } from '../lib/config';
|
||||
|
||||
import { DevOptionsType } from '../lib/interfaces/OptionsTypes';
|
||||
|
||||
import { config as webpackDefaultConfig } from '../lib/.webpack/dev.config';
|
||||
import { configFunc as webpackDefaultServerConfig } from '../lib/.webpack/dev-server.config';
|
||||
|
||||
import generateConfig from '../lib/webpack-helpers/generateConfig';
|
||||
|
||||
const defaultOptions: DevOptionsType = {
|
||||
env: 'development',
|
||||
host: '0.0.0.0',
|
||||
port: 8080,
|
||||
config: defaultConfig,
|
||||
};
|
||||
|
||||
export function dev(devOptions: DevOptionsType = defaultOptions): void {
|
||||
const options: DevOptionsType = { ...defaultOptions, ...devOptions };
|
||||
|
||||
options.config = { ...defaultOptions.config, ...devOptions.config };
|
||||
|
||||
const config = generateConfig(options.env, options.config);
|
||||
|
||||
if (!isAbsolutePath(options.config.src)) {
|
||||
throw Error('"src" is not an absolute path');
|
||||
}
|
||||
|
||||
if (!isAbsolutePath(options.config.build)) {
|
||||
throw Error('"build" is not an absolute path');
|
||||
}
|
||||
|
||||
if (!isAbsolutePath(options.config.postcssConfigFile)) {
|
||||
throw Error('"postcssConfigFile" is not an absolute path');
|
||||
}
|
||||
|
||||
const compilerConfig = { ...webpackDefaultConfig, ...config };
|
||||
const serverOptions = webpackDefaultServerConfig(options.config.src);
|
||||
|
||||
WebpackDevServer.addDevServerEntrypoints(compilerConfig, serverOptions);
|
||||
|
||||
const compiler = webpack(compilerConfig);
|
||||
const server = new WebpackDevServer(compiler, serverOptions);
|
||||
|
||||
server.listen(options.port, options.host, (err?: Error) => {
|
||||
if (err) throw err;
|
||||
});
|
||||
}
|
3
frontend/packages/scripts/src/index.ts
Executable file
3
frontend/packages/scripts/src/index.ts
Executable file
@ -0,0 +1,3 @@
|
||||
export * from './analyzer';
|
||||
export * from './build';
|
||||
export * from './dev';
|
6
frontend/packages/scripts/templates/index.ejs
Executable file
6
frontend/packages/scripts/templates/index.ejs
Executable file
@ -0,0 +1,6 @@
|
||||
<%- include ./partials/variables %>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<%= htmlWebpackPlugin.options.lang %>">
|
||||
<%- include ./partials/head %>
|
||||
<%- include ./partials/body %>
|
||||
</html>
|
92
frontend/packages/scripts/templates/partials/body.ejs
Executable file
92
frontend/packages/scripts/templates/partials/body.ejs
Executable file
@ -0,0 +1,92 @@
|
||||
<% var item, key %>
|
||||
|
||||
<body>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.unsupportedBrowser) { %>
|
||||
<!-- Unsupported browser -->
|
||||
<style>.unsupported-browser { display: none; }</style>
|
||||
<div class="unsupported-browser">
|
||||
Sorry, your browser is not supported. Please upgrade to the latest version or switch your browser to use this
|
||||
site. See <a href="http://outdatedbrowser.com/">outdatedbrowser.com</a> for options.
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.appMountId) { %>
|
||||
<!-- App mount (single) -->
|
||||
<div id="<%= htmlWebpackPlugin.options.appMountId %>">
|
||||
<% if (htmlWebpackPlugin.options.appMountHtmlSnippet) { %>
|
||||
<%= htmlWebpackPlugin.options.appMountHtmlSnippet %>
|
||||
<% } %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<% if (Array.isArray(htmlWebpackPlugin.options.appMountIds) && htmlWebpackPlugin.options.appMountIds.length ) { %>
|
||||
<!-- App mount ids (multiple) -->
|
||||
<% for (item of htmlWebpackPlugin.options.appMountIds) { %>
|
||||
<div id="<%= item %>"></div>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.html.body.snippet && '' !== htmlWebpackPlugin.options.html.body.snippet ) { %>
|
||||
<!-- Body snippet -->
|
||||
<%- htmlWebpackPlugin.options.html.body.snippet %>
|
||||
<% } %>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.window && Object.keys( htmlWebpackPlugin.options.window ).length) { %>
|
||||
<!-- Global object -->
|
||||
<script type="text/javascript">
|
||||
<% for (key in htmlWebpackPlugin.options.window) { %>
|
||||
window['<%= key %>'] = <%- JSON.stringify( htmlWebpackPlugin.options.window[key] ) %>;
|
||||
<% } %>
|
||||
</script>
|
||||
<% } %>
|
||||
|
||||
<% if (Array.isArray(htmlWebpackPlugin.options.html.body.scripts) && htmlWebpackPlugin.options.html.body.scripts.length ) { %>
|
||||
<!-- Scripts -->
|
||||
<% for (item of htmlWebpackPlugin.options.html.body.scripts) {
|
||||
%><script<% for (key in item) { %> <%= key %>="<%= item[key] %>"<% } %>></script><%
|
||||
}
|
||||
} %>
|
||||
|
||||
<% if ( Array.isArray(htmlWebpackPlugin.files.chunks) && htmlWebpackPlugin.files.chunks.length ) { %>
|
||||
<!-- Chunks -->
|
||||
<% for (key in htmlWebpackPlugin.files.chunks) {
|
||||
if (htmlWebpackPlugin.files.jsIntegrity) { %>
|
||||
<script
|
||||
src="<%= htmlWebpackPlugin.files.chunks[key].entry %>"
|
||||
type="text/javascript"
|
||||
integrity="<%= htmlWebpackPlugin.files.jsIntegrity[htmlWebpackPlugin.files.js.indexOf(htmlWebpackPlugin.files.chunks[key].entry)] %>"
|
||||
crossorigin="<%= webpackConfig.output.crossOriginLoading %>"></script>
|
||||
<% } else { %>
|
||||
<script src="<%= htmlWebpackPlugin.files.chunks[key].entry %>" type="text/javascript"></script>
|
||||
<% }
|
||||
}
|
||||
} %>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.googleAnalytics) { %>
|
||||
|
||||
<!-- Google analytics script -->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
window.GoogleAnalyticsObject='ga';window.ga=function(){ga.q.push(arguments)};ga.q=[];ga.l=+new Date;
|
||||
|
||||
<% if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
||||
ga('create','<%= htmlWebpackPlugin.options.googleAnalytics.trackingId %>','auto');
|
||||
<% } else {
|
||||
throw new Error("html-webpack-template requires googleAnalytics.trackingId config");
|
||||
} %>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.googleAnalytics.pageViewOnLoad) { %>
|
||||
ga('send','pageview');
|
||||
<% } %>
|
||||
|
||||
</script>
|
||||
|
||||
<script async defer src="https://www.google-analytics.com/analytics.js" type="text/javascript"></script>
|
||||
|
||||
<% } %>
|
||||
|
||||
<!---->
|
||||
|
||||
</body>
|
32
frontend/packages/scripts/templates/partials/head.ejs
Executable file
32
frontend/packages/scripts/templates/partials/head.ejs
Executable file
@ -0,0 +1,32 @@
|
||||
<% var item, key %>
|
||||
|
||||
<head>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.title) { %>
|
||||
<!-- Title -->
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<% } %>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.baseUrl) { %>
|
||||
<!-- Base -->
|
||||
<base href="<%= htmlWebpackPlugin.options.baseUrl %>">
|
||||
<% } %>
|
||||
|
||||
<% if (Array.isArray(htmlWebpackPlugin.options.html.head.meta) && htmlWebpackPlugin.options.html.head.meta.length ) { %>
|
||||
<!-- Meta -->
|
||||
<% for (item of htmlWebpackPlugin.options.html.head.meta) { %><meta<% for (key in item) { %> <%= key %>="<%= item[key] %>"<% } %> /><% }
|
||||
} %>
|
||||
|
||||
<% if (Array.isArray(htmlWebpackPlugin.options.html.head.links) && htmlWebpackPlugin.options.html.head.links.length ) { %>
|
||||
<!-- Links -->
|
||||
<% for (item of htmlWebpackPlugin.options.html.head.links) { %><link<% for (key in item) { %> <%= key %>="<%= item[key] %>"<% } %> /><% }
|
||||
} %>
|
||||
|
||||
<% if (Array.isArray(htmlWebpackPlugin.options.html.head.scripts) && htmlWebpackPlugin.options.html.head.scripts.length ) { %>
|
||||
<!-- Scripts -->
|
||||
<% for (item of htmlWebpackPlugin.options.html.head.scripts) { %>
|
||||
<script<% for (key in item) { %> <%= key %>="<%= item[key] %>"<% } %>></script><%
|
||||
}
|
||||
} %>
|
||||
|
||||
</head>
|
25
frontend/packages/scripts/templates/partials/variables.ejs
Executable file
25
frontend/packages/scripts/templates/partials/variables.ejs
Executable file
@ -0,0 +1,25 @@
|
||||
<% htmlWebpackPlugin.options.appMountId = htmlWebpackPlugin.options.appMountId || null %>
|
||||
<% htmlWebpackPlugin.options.appMountIds = htmlWebpackPlugin.options.appMountIds || [] %>
|
||||
|
||||
<% htmlWebpackPlugin.options.files = htmlWebpackPlugin.options.files || [] %>
|
||||
<% htmlWebpackPlugin.options.files.chunks = htmlWebpackPlugin.options.files.chunks || [] %>
|
||||
<% htmlWebpackPlugin.options.files.jsIntegrity = htmlWebpackPlugin.options.files.jsIntegrity || false %>
|
||||
|
||||
<% htmlWebpackPlugin.options.unsupportedBrowser = htmlWebpackPlugin.options.unsupportedBrowser || false %>
|
||||
|
||||
<% htmlWebpackPlugin.options.lang = htmlWebpackPlugin.options.lang || "en" %>
|
||||
|
||||
<% htmlWebpackPlugin.options.html = htmlWebpackPlugin.options.html || {} %>
|
||||
|
||||
<% htmlWebpackPlugin.options.html.head = htmlWebpackPlugin.options.html.head || {} %>
|
||||
<% htmlWebpackPlugin.options.html.head.meta = htmlWebpackPlugin.options.html.head.meta || [] %>
|
||||
<% htmlWebpackPlugin.options.html.head.links = htmlWebpackPlugin.options.html.head.links || [] %>
|
||||
<% htmlWebpackPlugin.options.html.head.scripts = htmlWebpackPlugin.options.html.head.scripts || [] %>
|
||||
|
||||
<% htmlWebpackPlugin.options.html.body = htmlWebpackPlugin.options.html.body || {} %>
|
||||
<% htmlWebpackPlugin.options.html.body.scripts = htmlWebpackPlugin.options.html.body.scripts || [] %>
|
||||
<% htmlWebpackPlugin.options.html.body.snippet = htmlWebpackPlugin.options.html.body.snippet || '' %>
|
||||
|
||||
<% htmlWebpackPlugin.options.window = htmlWebpackPlugin.options.window || {} %>
|
||||
|
||||
<% htmlWebpackPlugin.options.googleAnalytics = htmlWebpackPlugin.options.googleAnalytics || false %>
|
23
frontend/packages/scripts/templates/sitemap.ejs
Executable file
23
frontend/packages/scripts/templates/sitemap.ejs
Executable file
@ -0,0 +1,23 @@
|
||||
<% pages = pages || [] %>
|
||||
|
||||
<% if (pages.length) { %>
|
||||
|
||||
<div id="app-header"></div>
|
||||
<div id="app-sidebar"></div>
|
||||
|
||||
<div class="page-main-wrap">
|
||||
<div class="page-main-inner">
|
||||
<div class="custom-page-wrapper">
|
||||
<h2>Sitemap</h2>
|
||||
<hr>
|
||||
<h3>Pages</h3>
|
||||
<ol>
|
||||
<% for (p of pages) { %>
|
||||
<li><a href="./<%= p %>.html"><%= p %></a></li>
|
||||
<% } %>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% } %>
|
71
frontend/packages/scripts/tsconfig.json
Executable file
71
frontend/packages/scripts/tsconfig.json
Executable file
@ -0,0 +1,71 @@
|
||||
{
|
||||
"include":["lib/**/*", "src/**/*"],
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
"allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
"jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
//"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "declarationDir": "./dist/types",
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "./dist", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
}
|
||||
}
|
3
frontend/packages/vjs-plugin-font-icons/.babelrc
Executable file
3
frontend/packages/vjs-plugin-font-icons/.babelrc
Executable file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env"]
|
||||
}
|
32
frontend/packages/vjs-plugin-font-icons/.gitignore
vendored
Executable file
32
frontend/packages/vjs-plugin-font-icons/.gitignore
vendored
Executable file
@ -0,0 +1,32 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
|
||||
*.DS_Store
|
||||
|
||||
# Exports
|
||||
/build
|
45
frontend/packages/vjs-plugin-font-icons/.jshintrc
Executable file
45
frontend/packages/vjs-plugin-font-icons/.jshintrc
Executable file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"evil" : true,
|
||||
"validthis": true,
|
||||
"node" : true,
|
||||
"debug" : true,
|
||||
"boss" : true,
|
||||
"expr" : true,
|
||||
"eqnull" : true,
|
||||
"quotmark" : "single",
|
||||
"sub" : true,
|
||||
"trailing" : true,
|
||||
"undef" : true,
|
||||
"laxbreak" : true,
|
||||
"esnext" : true,
|
||||
"eqeqeq" : true,
|
||||
"predef" : [
|
||||
"_V_",
|
||||
"goog",
|
||||
"console",
|
||||
|
||||
"require",
|
||||
"define",
|
||||
"module",
|
||||
"exports",
|
||||
"process",
|
||||
|
||||
"q",
|
||||
"asyncTest",
|
||||
"deepEqual",
|
||||
"equal",
|
||||
"expect",
|
||||
"module",
|
||||
"notDeepEqual",
|
||||
"notEqual",
|
||||
"notStrictEqual",
|
||||
"ok",
|
||||
"QUnit",
|
||||
"raises",
|
||||
"start",
|
||||
"stop",
|
||||
"strictEqual",
|
||||
"test",
|
||||
"sinon"
|
||||
]
|
||||
}
|
1
frontend/packages/vjs-plugin-font-icons/.nvmrc
Executable file
1
frontend/packages/vjs-plugin-font-icons/.nvmrc
Executable file
@ -0,0 +1 @@
|
||||
lts/*
|
14
frontend/packages/vjs-plugin-font-icons/.travis.yml
Executable file
14
frontend/packages/vjs-plugin-font-icons/.travis.yml
Executable file
@ -0,0 +1,14 @@
|
||||
dist: xenial
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- lts/*
|
||||
|
||||
install:
|
||||
- npm install -g grunt
|
||||
- npm install
|
||||
|
||||
script:
|
||||
- grunt
|
||||
|
||||
cache: npm
|
8
frontend/packages/vjs-plugin-font-icons/Gruntfile.js
Executable file
8
frontend/packages/vjs-plugin-font-icons/Gruntfile.js
Executable file
@ -0,0 +1,8 @@
|
||||
require('@babel/register');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
require('time-grunt')(grunt);
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
require('./lib/grunt.js')(grunt);
|
||||
};
|
201
frontend/packages/vjs-plugin-font-icons/LICENSE
Executable file
201
frontend/packages/vjs-plugin-font-icons/LICENSE
Executable file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
16
frontend/packages/vjs-plugin-font-icons/README.md
Executable file
16
frontend/packages/vjs-plugin-font-icons/README.md
Executable file
@ -0,0 +1,16 @@
|
||||
# mediacms-vjs-plugin-font-icons
|
||||
|
||||
> This project is cloned from _video.js_ [font icons repository](https://github.com/videojs/font) to cover the needs of "**mediacms-vjs-plugin**"
|
||||
|
||||
Compared to the original repository:
|
||||
|
||||
- Added folder "**scripts**"
|
||||
- Added folder "**mediacms**"
|
||||
- Added npm cli command "**build**" which generates "_build_" and "_dist_" folders
|
||||
- Added npm cli command **"clean:builds"** which removes _"build"_ and _"dist"_ folders
|
||||
- Added "_rimraf_" package
|
||||
- Updated dependency packages
|
||||
|
||||
The final css file, is generated inside "_dist_" folder
|
||||
|
||||
- **dist/mediacms-vjs-icons.css**
|
24
frontend/packages/vjs-plugin-font-icons/custom-icons/audio-description.svg
Executable file
24
frontend/packages/vjs-plugin-font-icons/custom-icons/audio-description.svg
Executable file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="512px" height="512px" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>AD</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="AD" sketch:type="MSArtboardGroup" fill="#000000">
|
||||
<g id="g24" sketch:type="MSLayerGroup" transform="translate(226.904216, 162.124958)">
|
||||
<path d="M0.385466989,219.226204 L0.385466989,0.867948105 C50.7660025,-0.149278544 89.4938709,-2.16027378 118.016886,17.9940357 C145.39121,37.3362698 166.750707,74.9591545 162.906445,123.318579 C158.839382,174.474203 121.571663,217.457893 73.1311827,221.793795 C49.0460488,223.949377 1.1583283,221.793795 1.1583283,221.793795 C1.1583283,221.793795 0.318395733,220.441758 0.385466989,219.226204 M49.1404882,164.421786 C80.5703101,165.681697 102.34881,147.788744 105.636072,119.036417 C110.038491,80.5268177 84.4473371,55.4838492 47.5943801,58.2399576 L47.5943801,161.852062 C47.5585317,163.318404 48.1702678,164.071194 49.1404882,164.421786" id="path26" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<g id="g28" sketch:type="MSLayerGroup" transform="translate(383.779991, 168.926023)">
|
||||
<path d="M0,212.402042 C13.3360014,216.111401 17.386874,201.342635 23.2151349,190.99422 C35.936702,168.422877 45.5086182,139.400143 45.6604922,106.220214 C45.8813648,58.6259492 27.3172746,23.7033002 10.059532,0.0383859113 L1.54919183,0.0383859113 C0.96289654,3.91152436 3.77564916,7.35260805 5.41542574,10.3142944 C18.5814362,34.0755999 30.7818519,66.8674044 30.9556975,104.507776 C31.1545985,147.683822 16.7932549,183.786198 0,212.402042" id="path30" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<g id="g32" sketch:type="MSLayerGroup" transform="translate(425.153705, 168.926023)">
|
||||
<path d="M0,212.402042 C13.3360014,216.111401 17.3841758,201.340502 23.2151349,190.99422 C35.936702,168.422877 45.5066909,139.400143 45.6604922,106.220214 C45.8813648,58.6259492 27.3172746,23.7033002 10.059532,0.0383859113 L1.54919183,0.0383859113 C0.96289654,3.91152436 3.77487823,7.35346107 5.41542574,10.3142944 C18.5814362,34.0755999 30.7822374,66.8674044 30.9556975,104.507776 C31.1545985,147.683822 16.7932549,183.786198 0,212.402042" id="path34" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<g id="g36" sketch:type="MSLayerGroup" transform="translate(466.260868, 168.926023)">
|
||||
<path d="M0,212.402042 C13.3360014,216.111401 17.3841758,201.340502 23.2151349,190.99422 C35.936702,168.422877 45.5066909,139.400143 45.6604922,106.220214 C45.8813648,58.6259492 27.3172746,23.7033002 10.059532,0.0383859113 L1.54919183,0.0383859113 C0.96289654,3.91152436 3.77487823,7.35303456 5.41542574,10.3142944 C18.5814362,34.0755999 30.7818519,66.8674044 30.9556975,104.507776 C31.1545985,147.683822 16.7932549,183.786198 0,212.402042" id="path38" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
<path d="M4.4765625,383.005158 L72.5800993,383.005158 L91.1530552,354.521486 L155.321745,354.386058 C155.321745,354.386058 155.386889,373.799083 155.386889,383.005158 L204.142681,383.005158 L204.142681,160.308263 L145.326586,160.308263 C139.673713,169.845383 4.4765625,383.005158 4.4765625,383.005158 L4.4765625,383.005158 Z M157.144233,237.722611 L157.144233,308.881058 L116.6914,308.610203 L157.144233,237.722611 L157.144233,237.722611 Z" id="path22" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
@ -0,0 +1 @@
|
||||
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1343 12v264h-157q-86 0-116 36t-30 108v189h293l-39 296h-254v759h-306v-759h-255v-296h255v-218q0-186 104-288.5t277-102.5q147 0 228 12z"/></svg>
|
After Width: | Height: | Size: 243 B |
@ -0,0 +1 @@
|
||||
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M799 796q0 36 32 70.5t77.5 68 90.5 73.5 77 104 32 142q0 90-48 173-72 122-211 179.5t-298 57.5q-132 0-246.5-41.5t-171.5-137.5q-37-60-37-131 0-81 44.5-150t118.5-115q131-82 404-100-32-42-47.5-74t-15.5-73q0-36 21-85-46 4-68 4-148 0-249.5-96.5t-101.5-244.5q0-82 36-159t99-131q77-66 182.5-98t217.5-32h418l-138 88h-131q74 63 112 133t38 160q0 72-24.5 129.5t-59 93-69.5 65-59.5 61.5-24.5 66zm-146-96q38 0 78-16.5t66-43.5q53-57 53-159 0-58-17-125t-48.5-129.5-84.5-103.5-117-41q-42 0-82.5 19.5t-65.5 52.5q-47 59-47 160 0 46 10 97.5t31.5 103 52 92.5 75 67 96.5 26zm2 873q58 0 111.5-13t99-39 73-73 27.5-109q0-25-7-49t-14.5-42-27-41.5-29.5-35-38.5-34.5-36.5-29-41.5-30-36.5-26q-16-2-48-2-53 0-105 7t-107.5 25-97 46-68.5 74.5-27 105.5q0 70 35 123.5t91.5 83 119 44 127.5 14.5zm810-876h213v108h-213v219h-105v-219h-212v-108h212v-217h105v217z"/></svg>
|
After Width: | Height: | Size: 933 B |
@ -0,0 +1 @@
|
||||
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M477 625v991h-330v-991h330zm21-306q1 73-50.5 122t-135.5 49h-2q-82 0-132-49t-50-122q0-74 51.5-122.5t134.5-48.5 133 48.5 51 122.5zm1166 729v568h-329v-530q0-105-40.5-164.5t-126.5-59.5q-63 0-105.5 34.5t-63.5 85.5q-11 30-11 81v553h-329q2-399 2-647t-1-296l-1-48h329v144h-2q20-32 41-56t56.5-52 87-43.5 114.5-15.5q171 0 275 113.5t104 332.5z"/></svg>
|
After Width: | Height: | Size: 443 B |
@ -0,0 +1 @@
|
||||
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1664 896q0 209-103 385.5t-279.5 279.5-385.5 103q-111 0-218-32 59-93 78-164 9-34 54-211 20 39 73 67.5t114 28.5q121 0 216-68.5t147-188.5 52-270q0-114-59.5-214t-172.5-163-255-63q-105 0-196 29t-154.5 77-109 110.5-67 129.5-21.5 134q0 104 40 183t117 111q30 12 38-20 2-7 8-31t8-30q6-23-11-43-51-61-51-151 0-151 104.5-259.5t273.5-108.5q151 0 235.5 82t84.5 213q0 170-68.5 289t-175.5 119q-61 0-98-43.5t-23-104.5q8-35 26.5-93.5t30-103 11.5-75.5q0-50-27-83t-77-33q-62 0-105 57t-43 142q0 73 25 122l-99 418q-17 70-13 177-206-91-333-281t-127-423q0-209 103-385.5t279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/></svg>
|
After Width: | Height: | Size: 713 B |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user