This commit is contained in:
2024-03-29 14:22:19 +07:00
commit f5e6fd57cd
129 changed files with 10715 additions and 0 deletions

2
.browserslistrc Normal file
View File

@@ -0,0 +1,2 @@
last 2 major versions
Firefox ESR

9
.editorconfig Normal file
View File

@@ -0,0 +1,9 @@
root = true
[*{js,pug,scss,json}]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
quote_type = single

0
.eslintignore Normal file
View File

197
.eslintrc.js Normal file
View File

@@ -0,0 +1,197 @@
module.exports = {
root: true,
env: {
browser: true,
es6: true,
node: true
},
parser: 'babel-eslint',
parserOptions: {
ecmaFeatures: {
legacyDecorators: true
}
},
globals: {
$: true,
jQuery: true,
Plugin: true,
__webpack_require__: true
},
rules: {
// recommended
'for-direction': 2,
'getter-return': 2,
'no-compare-neg-zero': 2,
'no-cond-assign': [2, 'always'],
'no-console': [1, {
allow: ['warn', 'error']
}],
'no-constant-condition': 2,
'no-control-regex': 1,
'no-debugger': 1,
'no-dupe-args': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty': 1,
'no-empty-character-class': 1,
'no-ex-assign': 2,
'no-extra-boolean-cast': 1,
'no-extra-semi': 2,
'no-func-assign': 2,
'no-inner-declarations': 2,
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-obj-calls': 2,
'no-regex-spaces': 1,
'no-sparse-arrays': 2,
'no-unexpected-multiline': 2,
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unsafe-negation': 2,
'use-isnan': 1,
'valid-typeof': [2, {
"requireStringLiterals": true
}],
'no-case-declarations': 2,
'no-empty-pattern': 2,
'no-fallthrough': 2,
'no-global-assign': 2,
'no-octal': 2,
'no-redeclare': [2, {
'builtinGlobals': true
}],
'no-self-assign': 2,
'no-unused-labels': 1,
'no-useless-escape': 1,
'no-delete-var': 2,
'no-undef': 2,
'no-unused-vars': 1,
'no-mixed-spaces-and-tabs': 1,
'constructor-super': 2,
'no-class-assign': 2,
'no-const-assign': 2,
'no-dupe-class-members': 2,
'no-new-symbol': 2,
'no-this-before-super': 2,
'require-yield': 2,
// error
'no-async-promise-executor': 2,
'no-misleading-character-class': 2,
'require-atomic-updates': 2,
'accessor-pairs': 2,
'block-scoped-var': 2,
'curly': 2,
'dot-location': [2, 'property'],
'eqeqeq': [2, 'always'],
'no-caller': 2,
'no-eq-null': 2,
'no-eval': 2,
'no-implied-eval': 2,
'no-iterator': 2,
'no-labels': 2,
'no-lone-blocks': 2,
'no-loop-func': 2,
'no-multi-str': 2,
'no-new-func': 2,
'no-new-wrappers': 2,
'no-octal-escape': 2,
'no-param-reassign': 2,
'no-proto': 2,
'no-return-assign': [2, 'always'],
'no-return-await': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-with': 2,
'vars-on-top': 2,
'wrap-iife': [2, 'inside', {
functionPrototypeMethods: true
}],
'no-label-var': 2,
'no-use-before-define': 2,
// Warning
'no-await-in-loop': 1,
'array-callback-return': 1,
'class-methods-use-this': 1,
'consistent-return': [1, {
treatUndefinedAsUnspecified: true
}],
'dot-notation': [0, {
allowKeywords: false
}],
'guard-for-in': 1,
'no-alert': 1,
'no-div-regex': 1,
'no-else-return': 1,
'no-empty-function': 1,
'no-extra-bind': 1,
'no-extra-label': 1,
'no-floating-decimal': 1,
'no-multi-spaces': [1, {
ignoreEOLComments: true,
exceptions: {
Property: false,
BinaryExpression: true,
VariableDeclarator: true,
ImportDeclaration: true
}
}],
'no-script-url': 1,
'no-useless-call': 1,
'no-useless-concat': 1,
'no-useless-return': 1,
'no-void': 1,
'require-await': 1,
'no-undef-init': 1,
'no-undefined': 1,
// Stylist
'block-spacing': 1,
'brace-style': 1,
'comma-spacing': 1,
'comma-style': 1,
'computed-property-spacing': 1,
'func-call-spacing': 1,
'indent': [1, 2, {
SwitchCase: 1,
MemberExpression: 'off'
}],
'key-spacing': 1,
'keyword-spacing': 1,
'lines-between-class-members': 1,
'max-len': [1, {
code: 80,
ignoreRegExpLiterals: true,
ignoreTemplateLiterals: true,
ignoreStrings: true
}],
'no-lonely-if': 1,
'no-multi-assign': 1,
'no-multiple-empty-lines': [1, {
max: 2,
maxEOF: 1,
maxBOF: 0
}],
'no-trailing-spaces': 1,
'no-unneeded-ternary': [1, {
defaultAssignment: false
}],
'no-whitespace-before-property': 1,
'quotes': [1, 'single', {
allowTemplateLiterals: true
}],
'semi-spacing': 1,
'semi': 1,
'space-infix-ops': 1,
'switch-colon-spacing': 1,
'no-duplicate-imports': [1, {
includeExports: true
}],
'no-useless-computed-key': 1,
'no-var': 1,
'object-shorthand': 1,
'prefer-template': 1,
'template-curly-spacing': 1
}
}

4
.gitattributes vendored Normal file
View File

@@ -0,0 +1,4 @@
*.json text eol=lf
*.js text eol=lf
*.pug text eol=lf
*.scss text eol=lf

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
.git
npm-debug.log
.publish
.vscode
static
dist
node_modules
src/locales/*.json
package-lock.json
yarn.lock
.idea/

112
README.md Normal file
View File

@@ -0,0 +1,112 @@
WEB TEMPLATE
===================
Web template use es6, pug, scss
## 1. Installation
```bash
npm i
```
## 2. Configuration
- Every configuration is stored in `./gulpfile.js/config/**`
## 3. Constructor
```bash
src/
| assets/
| | # All files and folders (except site folder) will be copied to /dist
| | favicon/
| | # All content in this folder will be copied direct to /dist
| |
| |
| scrips/
| | _lib/
| | | # Store custom libraries,
| | | # which cannot be downloaded through npm
| | |
| | |
| | |
| | *.js # These files is the entry file to compile with webpack
| |
| |
| styles/
| | _*/
| | | # Every files in folders have start name, is _,
| | | # won't be compiled.
| | | # It only use to store many libraries or variables
| | |
| | |
| | $*/
| | | # Every files in folders have start name, is $,
| | | # won't be compiled.
| | | # It only use to merge into apps.css
| | |
| | |
| | ... # Others will be compiled to /dist/css/
| |
| |
| views/
| _*/
| | # Every files in folders have start name, is _,
| | # won't be compiled.
| | # It only use to store many reusable components
| |
| |
| $*/
| | # Every files in folders have start name, is $,
| | # won't be compiled.
| | # It only use to store many main/page components
| |
| |
| ... # Others will be compiled to /dist/
|
|
gulpfile.js/
| .... # Manage build tasks and configuration
|
|
server/
| .... # Manage server side render views
|
|
dist/
| # Store compiled html, css, js (production build)
|
|
static/
| # Store compiled css, js (work on dev)
|
|
.browserslistrc
.eslintrc.js
.gitignore
.gitattributes
index.html
package.json
README.md
```
## 4. Tasks
- `npm start`: Shorthand for `npm run dev`
- `npm run dev`: Build Project + Watch + Node Server
- `npm run build`: Build Project (min)
- `npm run serve`: Run production local server
## 5. Pug global variables
- `$translator`: object variable get value from `app/locales/#{lang}.json`
- `$localeName`: variable get value equal name of current using locale json
## 6. JS Dynamic import path (chunks files)
At `src/views/_layouts/layout.pug`, there is a script with variable `staticJsAssetsPath`, update that variable to server js path, and it will load correctly chunks files
## 7. Single language mode
Just remove folder `src/locales`
## 8. Site favicon
Use this online tool: https://realfavicongenerator.net/ to get the site favicon package and put it in `app/assets/site`

13
babel.config.json Normal file
View File

@@ -0,0 +1,13 @@
{
"presets": ["@babel/preset-env"],
"plugins": [
["@babel/plugin-transform-runtime", {
"helpers": true,
"regenerator": true,
"version": "^7.7.4"
}],
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": false }],
"@babel/plugin-proposal-private-methods"
]
}

View File

@@ -0,0 +1,20 @@
process.env.NODE_ENV = 'production';
const compression = require('compression');
const { output } = require('./directories');
const server = require('./server');
module.exports = {
server: output,
port: server.PROD_PORT,
ui: {
port: server.PROD_DASHBOARD_PORT,
},
open: 'local',
ghostMode: false,
logPrefix: 'SYNC',
middleware: [
compression(),
],
};

View File

@@ -0,0 +1,12 @@
const server = require('./server');
module.exports = {
port: server.DEV_PORT,
proxy: `http://localhost:${server.STATIC_PORT}`,
ui: {
port: server.DASHBOARD_PORT,
},
open: true,
ghostMode: false,
logPrefix: 'SYNC',
};

View File

@@ -0,0 +1,77 @@
const { addPath } = require('../utils');
const isProduction = process.env.NODE_ENV === 'production';
const ignoreTemplate = ['$*/**/*', '_*/**/*'];
const nodeModules = 'node_modules/';
exports.nodeModules = nodeModules;
const src = 'src/';
exports.src = src;
const dest = 'static/';
const dist = 'dist/';
const output = isProduction ? dist : dest;
exports.output = output;
const srcLocales = `${src}locales/`;
exports.srcLocales = srcLocales;
const srcAsset = `${src}assets/`;
exports.srcAsset = srcAsset;
const filesCopy = addPath(srcAsset, '**', 'favicon/**');
const filesFavicon = addPath(srcAsset, 'favicon/**');
const filesAssets = filesCopy
.concat(filesFavicon)
.concat(isProduction ? 'index.html' : []);
exports.filesAssets = filesAssets;
const srcScript = `${src}scripts/`;
exports.srcScript = srcScript;
const filesJs = addPath(srcScript, '**/*.js', ignoreTemplate);
exports.filesJs = filesJs;
const filesJsES6 = `${srcScript}*.js`;
exports.filesJsES6 = filesJsES6;
const outputScript = `${output}js/`;
exports.outputScript = outputScript;
const outputChunkScripts = `${outputScript}chunks/`;
exports.outputChunkScripts = outputChunkScripts;
const filesChunkJs = addPath(outputChunkScripts, '*.js', '*.backup.js');
exports.filesChunkJs = filesChunkJs;
const srcStyle = `${src}styles/`;
exports.srcStyle = srcStyle;
const filesScssBuilt = addPath(
srcStyle,
'**/*.scss',
['$*/**/*.scss', '_*/**/*.scss'],
);
exports.filesScssBuilt = filesScssBuilt;
const filesScssPartial = addPath(
srcStyle,
['$*/**/*.scss', '_*/**/*.scss'],
);
exports.filesScssPartial = filesScssPartial;
const outputStyle = `${output}css/`;
exports.outputStyle = outputStyle;
const filesCssBuilt = addPath(outputStyle, '*.css', '*-rtl.css');
exports.filesCssBuilt = filesCssBuilt;
const srcView = `${src}views/`;
exports.srcView = srcView;
const filesPugBuilt = addPath(srcView, '**/*.pug', ['$*/**/*', '_*/**/*']);
exports.filesPugBuilt = filesPugBuilt;
const filesPug = addPath(srcView, '**/*.pug');
exports.filesPug = filesPug;

View File

@@ -0,0 +1,8 @@
const { srcScript } = require('./directories');
const libPath = `${srcScript}_libs/`;
module.exports = [
`${libPath}modernizr-custom-3.6.0.js`,
`node_modules/detectizr/dist/detectizr.js`,
];

View File

@@ -0,0 +1,6 @@
module.exports = {
script: 'server/index.js',
watch: [
'server/',
],
};

View File

@@ -0,0 +1,4 @@
module.exports = {
pretty: true,
doctype: 'html',
};

View File

@@ -0,0 +1,11 @@
module.exports = {
rtl: {
suffix: '-rtl',
},
min: {
suffix: '.min',
},
backup: {
suffix: '.backup',
},
};

View File

@@ -0,0 +1,3 @@
module.exports = {
outputStyle: 'expanded',
};

View File

@@ -0,0 +1,20 @@
const PORT = 4999;
module.exports = {
PROD_PORT: 8080,
STATIC_PORT: PORT,
get DEV_PORT() {
return this.STATIC_PORT + 1;
},
get DASHBOARD_PORT() {
return this.STATIC_PORT - 1;
},
get PROD_DASHBOARD_PORT() {
return this.PROD_PORT - 1;
},
DEFAULT_LANG: 'en',
};

View File

@@ -0,0 +1,9 @@
// Change this value to false if you don't wanna use cache
const { DEFAULT_LANG } = require('./server');
module.exports = {
css: `dist/css/styles.min.css?v=${Date.now()}`,
'css-rtl': `dist/css/styles-rtl.min.css?v=${Date.now()}`,
js: `dist/js/scripts.min.js?v=${Date.now()}`,
redirect: `<meta http-equiv="refresh" content="0;url=./${DEFAULT_LANG}/sitemap.html">`,
};

View File

@@ -0,0 +1,51 @@
/* eslint-disable-next-line */
const { resolve, join } = require('path');
const { ProvidePlugin } = require('webpack');
const { srcScript, output, outputScript } = require('./directories');
const nodeEnv = process.env.NODE_ENV;
const isDevelopment = nodeEnv === 'development';
module.exports = {
mode: 'none',
context: join(__dirname, '../../', output),
output: {
path: join(__dirname, '../../', outputScript),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
],
},
resolve: {
alias: {
'@': resolve(srcScript),
},
},
plugins: [
new ProvidePlugin({
Plugin: ['@/cores/plugin', 'default'],
jQuery: 'jquery', // replace by using external jquery
$: ['jquery'],
}),
],
optimization: {
nodeEnv,
chunkIds: 'total-size',
concatenateModules: true,
flagIncludedChunks: true,
moduleIds: 'size',
sideEffects: true,
splitChunks: false,
},
devtool: isDevelopment && 'source-map',
};

11
gulpfile.js/index.js Normal file
View File

@@ -0,0 +1,11 @@
const requireDir = require('require-dir');
const task = process.argv[2];
process.env.NODE_ENV = ~['build'].indexOf(task) ? 'production' : 'development';
const tasks = requireDir('./tasks');
Object.keys(tasks).forEach((name) => {
exports[name] = tasks[name];
});

View File

@@ -0,0 +1,15 @@
const { src, dest } = require('gulp');
const rename = require('gulp-rename');
const { filesChunkJs, outputChunkScripts } = require('../config/directories');
const { backup } = require('../config/rename');
function backupChunkScripts() {
return src(filesChunkJs)
.pipe(rename(backup))
.pipe(dest(outputChunkScripts));
}
backupChunkScripts.displayName = 'backup:chunk-scripts';
module.exports = backupChunkScripts;

View File

@@ -0,0 +1,20 @@
const { series } = require('gulp');
const buildLocales = require('./build--locales');
const copyAssets = require('./copy--assets');
const lintScripts = require('./lint--scripts');
const buildScriptsES6 = require('./build--scripts-es6');
const buildScriptsExternal = require('./build--scripts-external');
const buildStyles = require('./build--styles');
const buildStylesRtl = require('./build--styles-rtl');
const buildAssets = series(
buildLocales,
copyAssets,
lintScripts,
buildScriptsES6,
buildScriptsExternal,
buildStyles,
buildStylesRtl,
);
module.exports = buildAssets;

View File

@@ -0,0 +1,37 @@
const { src, dest, parallel } = require('gulp');
const merge = require('gulp-merge-json');
const { srcLocales } = require('../config/directories');
const { getFolders } = require('../utils');
const { handleError } = require('../utils/errors');
function generateBuildTmpFn(folder) {
function buildLocale() {
return src(`${srcLocales}/${folder}/**/*.json`)
.pipe(merge({
fileName: `${folder}.json`,
jsonSpace: ' ',
}))
.on('error', handleError)
.pipe(dest(srcLocales));
}
buildLocale.displayName = `build:locale:${folder}`;
return buildLocale;
}
function buildLocales(cb) {
const folders = getFolders(srcLocales);
if (folders[0]) {
process.env.MULTI_LANGUAGE = folders;
return parallel(...folders.map(generateBuildTmpFn))(cb);
}
return cb();
}
buildLocales.displayName = 'build:locales';
module.exports = buildLocales;

View File

@@ -0,0 +1,24 @@
const { src, dest } = require('gulp');
const gulpWebpack = require('webpack-stream');
const webpack = require('webpack');
const vinylNamed = require('vinyl-named');
const { filesJsES6, outputScript } = require('../config/directories');
const option = require('../config/webpack');
const { list, handleError } = require('../utils/errors');
function buildScriptsES6(cb) {
if (!list.isJSValid) {
return cb();
}
return src(filesJsES6)
.pipe(vinylNamed())
.pipe(gulpWebpack(option, webpack))
.on('error', handleError)
.pipe(dest(outputScript));
}
buildScriptsES6.displayName = 'build:scripts-es6';
module.exports = buildScriptsES6;

View File

@@ -0,0 +1,22 @@
const { src, dest } = require('gulp');
const concat = require('gulp-concat');
const jsExternalPaths = require('../config/externals-js');
const { outputScript } = require('../config/directories');
const { handleError } = require('../utils/errors');
const isDevelopment = process.env.NODE_ENV !== 'production';
/**
* Building libraries scripts
*/
function buildScriptsExternal () {
return src(jsExternalPaths, { sourcemaps: isDevelopment })
.pipe(concat('externals.js'))
.on('error', handleError)
.pipe(dest(outputScript, { sourcemaps: isDevelopment && '.' }));
}
buildScriptsExternal.displayName = 'build:scripts-external';
module.exports = buildScriptsExternal;

View File

@@ -0,0 +1,27 @@
const { src, dest, lastRun } = require('gulp');
const rtlcss = require('gulp-rtlcss');
const rename = require('gulp-rename');
const {
outputStyle,
filesCssBuilt,
} = require('../config/directories');
const { rtl: renameOpts } = require('../config/rename');
const browserSync = require('../utils/browser-sync');
const { handleError } = require('../utils/errors');
function buildStylesRtl() {
return src(filesCssBuilt, {
since: lastRun(buildStylesRtl),
})
.pipe(rtlcss())
.on('error', handleError)
.pipe(rename(renameOpts))
.on('error', handleError)
.pipe(dest(outputStyle))
.pipe(browserSync.stream());
}
buildStylesRtl.displayName = 'build:styles-rtl';
module.exports = buildStylesRtl;

View File

@@ -0,0 +1,35 @@
const { src, dest } = require('gulp');
// const sass = require('sass');
// const gulpSass = require('gulp-sass');
const sass = require('gulp-sass')(require('sass'));
const cached = require('gulp-cached');
const sassUnicode = require('gulp-sass-unicode');
const autoprefixer = require('gulp-autoprefixer');
// const header = require('gulp-header');
// gulpSass.compiler = sass;
const {
filesScssBuilt,
outputStyle,
} = require('../config/directories');
const sassOpts = require('../config/sass');
const browserSync = require('../utils/browser-sync');
const { handleError } = require('../utils/errors');
function buildStyles() {
return src(filesScssBuilt)
.pipe(cached('scss'))
.pipe(sass(sassOpts))
.on('error', handleError)
.pipe(sassUnicode())
.on('error', handleError)
.pipe(autoprefixer())
.on('error', handleError)
.pipe(dest(outputStyle))
.pipe(browserSync.stream());
}
buildStyles.displayName = 'build:styles';
module.exports = buildStyles;

View File

@@ -0,0 +1,20 @@
const gulp = require('gulp');
const htmlReplace = require('gulp-html-replace');
const useminOpts = require('../config/usemin');
const { output } = require('../config/directories');
const { handleError } = require('../utils/errors');
function buildViewsMin() {
return gulp
.src(`${output}**/*.html`)
.pipe(htmlReplace(useminOpts, {
resolvePaths: true,
}))
.on('error', handleError)
.pipe(gulp.dest(output));
}
buildViewsMin.displayName = 'build:views-min';
module.exports = buildViewsMin;

View File

@@ -0,0 +1,47 @@
const { src, dest, parallel } = require('gulp');
const pug = require('gulp-pug');
const { srcLocales, filesPugBuilt, output } = require('../config/directories');
const options = require('../config/pug');
const { handleError } = require('../utils/errors');
function generateBuildTmpFn(lang) {
let outputPath = output;
const pugOpts = {
...options,
locals: {
$translator: {},
$localeName: lang,
},
};
if (lang) {
outputPath = `${output + lang}/`;
/* eslint-disable-next-line */
pugOpts.locals.$translator = require(`../../${srcLocales + lang}.json`);
}
function buildView() {
return src(filesPugBuilt)
.pipe(pug(pugOpts))
.on('error', handleError)
.pipe(dest(outputPath));
}
buildView.displayName = `build:views:${lang || 'single-lang'}`;
return buildView;
}
function buildViews(cb) {
const folders = process.env.MULTI_LANGUAGE;
if (folders) {
return parallel(...folders.split(',').map(generateBuildTmpFn))(cb);
}
return generateBuildTmpFn()();
}
buildViews.displayName = 'build:views';
module.exports = buildViews;

View File

@@ -0,0 +1,27 @@
const { src, dest } = require('gulp');
const concat = require('gulp-concat');
const rename = require('gulp-rename');
const uglify = require('gulp-uglify');
const { outputScript } = require('../config/directories');
const { handleError } = require('../utils/errors');
const { min } = require('../config/rename');
function bundleScripts() {
return src([`${outputScript}externals.js`, `${outputScript}*.js`])
.pipe(concat('scripts.js'))
.on('error', handleError)
.pipe(dest(outputScript))
.pipe(rename(min))
.pipe(uglify({
mangle: {
keep_fnames: true,
},
}))
.on('error', handleError)
.pipe(dest(outputScript));
}
bundleScripts.displayName = 'bundle:scripts';
module.exports = bundleScripts;

View File

@@ -0,0 +1,25 @@
const { src, dest } = require('gulp');
const concat = require('gulp-concat');
const { outputStyle } = require('../config/directories');
const { handleError } = require('../utils/errors');
function bundleStyles(isRTL) {
const suffix = isRTL ? '-rtl' : '';
const libsCss = `${outputStyle}$libs${suffix}.css`;
const appsCss = `${outputStyle}apps${suffix}.css`;
const concatCss = `styles${suffix}.css`;
function bundleStyle() {
return src([libsCss, appsCss])
.pipe(concat(concatCss))
.on('error', handleError)
.pipe(dest(outputStyle));
}
bundleStyle.displayName = `bundle:styles:${isRTL ? 'rtl' : 'origin'}`;
return bundleStyle;
}
module.exports = bundleStyles;

View File

@@ -0,0 +1,9 @@
const del = require('del');
const { output } = require('../config/directories');
const cleanOutput = () => del(output);
cleanOutput.displayName = 'clean:output';
module.exports = cleanOutput;

View File

@@ -0,0 +1,14 @@
const del = require('del');
const { outputScript } = require('../config/directories');
const cleanTempScripts = () => del([
`${outputScript}*.js`,
`${outputScript}*.map`,
`!${outputScript}scripts.js`,
`!${outputScript}scripts.min.js`,
]);
cleanTempScripts.displayName = 'clean:temp-scripts';
module.exports = cleanTempScripts;

View File

@@ -0,0 +1,14 @@
const del = require('del');
const { outputStyle } = require('../config/directories');
const cleanTempStyles = () => del([
`${outputStyle}$libs.css`,
`${outputStyle}$libs-rtl.css`,
`${outputStyle}apps.css`,
`${outputStyle}apps-rtl.css`,
]);
cleanTempStyles.displayName = 'clean:temp-styles';
module.exports = cleanTempStyles;

View File

@@ -0,0 +1,12 @@
const { src, dest, lastRun } = require('gulp');
const { filesAssets, output } = require('../config/directories');
function copyAssets() {
return src(filesAssets, {
since: lastRun(copyAssets),
}).pipe(dest(output));
}
copyAssets.displayName = 'copy:assets';
module.exports = copyAssets;

View File

@@ -0,0 +1,26 @@
const { src } = require('gulp');
const eslint = require('gulp-eslint');
const cached = require('gulp-cached');
const { filesJs } = require('../config/directories');
const { handleESLintError } = require('../utils/errors');
const stream = require('../utils/browser-sync');
function lintScripts() {
const gulpInstance = src(filesJs)
.pipe(cached('eslint'))
.pipe(eslint())
.pipe(eslint.results(handleESLintError));
if (stream.isStreaming) {
return gulpInstance;
}
return gulpInstance
.pipe(eslint.format())
.pipe(eslint.failOnError());
}
lintScripts.displayName = 'lint:scripts';
module.exports = lintScripts;

View File

@@ -0,0 +1,20 @@
const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');
const { filesChunkJs, outputChunkScripts } = require('../config/directories');
const { handleError } = require('../utils/errors');
function minifyChunkScripts() {
return src(filesChunkJs)
.pipe(uglify({
mangle: {
keep_fnames: true,
},
}))
.on('error', handleError)
.pipe(dest(outputChunkScripts));
}
minifyChunkScripts.displayName = 'minify:chunk-scripts';
module.exports = minifyChunkScripts;

View File

@@ -0,0 +1,19 @@
const { src, dest } = require('gulp');
const rename = require('gulp-rename');
const cleanCss = require('gulp-clean-css');
const { outputStyle } = require('../config/directories');
const { min } = require('../config/rename');
const { handleError } = require('../utils/errors');
function minifyStyles() {
return src(`${outputStyle}**/*.css`)
.pipe(rename(min))
.pipe(cleanCss())
.on('error', handleError)
.pipe(dest(outputStyle));
}
minifyStyles.displayName = 'minify:styles';
module.exports = minifyStyles;

View File

@@ -0,0 +1,64 @@
const notify = require('gulp-notify');
const stripIndent = require('strip-indent');
const { pluralText } = require('../utils');
const errors = require('../utils/errors');
const { log } = console;
notify.logLevel(0);
function printResults(cb) {
const errList = errors.list;
const {
totalError, totalWarning, totalIssue, data,
} = errList;
const errorString = `${totalError} ${pluralText('error', totalError)}`;
const warningString = `${totalWarning} ${pluralText('warning', totalWarning)}`;
const resultString = `The project has ${errorString} & ${warningString}`;
const resultStr = resultString; // Improve Performance Node
const dashChar = ''.padEnd(resultStr.length + 4, '=');
log(stripIndent(`
${dashChar}
${resultStr}
${dashChar}
`));
if (!totalIssue) {
return cb();
}
const infoLogs = stripIndent(data.map(({
message, code, title, type,
}, i) => {
if (type !== 'Warning') {
notify.onError({
title,
message,
})();
}
return `
---[ ${type} ${i + 1} ]-------------------------
| Path : ${message}
| ${code}
`;
}).join(`
`));
log((`
${infoLogs}
${dashChar}
`).replace(/^ {2}/gm, ''));
errors.resetError();
return cb();
}
printResults.displayName = 'print:results';
module.exports = printResults;

View File

@@ -0,0 +1,10 @@
const browserSync = require('../utils/browser-sync');
function reload(cb) {
browserSync.reload();
cb();
}
reload.displayName = 'reload';
module.exports = reload;

View File

@@ -0,0 +1,8 @@
const { parallel } = require('gulp');
const runViews = require('./run--views');
const runWatchers = require('./run--watchers');
const runDevServer = parallel(runViews, runWatchers);
module.exports = runDevServer;

View File

@@ -0,0 +1,35 @@
const nodemon = require('gulp-nodemon');
const browserSync = require('../utils/browser-sync');
const options = require('../config/nodemon');
const browserSyncOpts = require('../config/browser-sync');
function runViews(cb) {
let started = false;
nodemon({
...options,
env: {
MULTI_LANGUAGE: process.env.MULTI_LANGUAGE,
},
})
.on('start', () => {
if (started) {
cb();
return;
}
started = true;
setTimeout(() => {
browserSync.isStreaming = true;
browserSync.init(browserSyncOpts);
cb();
}, 1000);
});
}
runViews.displayName = 'run:views';
module.exports = runViews;

View File

@@ -0,0 +1,71 @@
const { series, parallel, watch } = require('gulp');
const cached = require('gulp-cached');
const reload = require('./reload');
const buildLocales = require('./build--locales');
const printResults = require('./print--results');
const buildStyles = require('./build--styles');
const buildScriptsExternal = require('./build--scripts-external');
const lintScripts = require('./lint--scripts');
const buildScriptsES6 = require('./build--scripts-es6');
const copyAssets = require('./copy--assets');
const {
filesPug,
srcLocales,
filesScssBuilt,
filesScssPartial,
filesJs,
filesAssets,
} = require('../config/directories');
const jsExternalPaths = require('../config/externals-js');
function runWatchers(cb) {
const reloadAndShowResults = parallel(printResults, reload);
// HTML --------------------
watch(filesPug, reload);
// LOCALE --------------------
watch(`${srcLocales}*/*.json`, series(
buildLocales,
reloadAndShowResults,
));
// CSS --------------------
watch(filesScssBuilt, series(
buildStyles,
printResults,
));
watch(filesScssPartial, series(
buildStyles,
printResults,
)).on('change', () => delete cached.caches.scss);
// JS --------------------
watch(jsExternalPaths, series(
buildScriptsExternal,
reloadAndShowResults
));
watch(filesJs, series(
lintScripts,
buildScriptsES6,
reloadAndShowResults,
));
// ASSETS --------------------
watch(filesAssets, series(
copyAssets,
reloadAndShowResults,
));
if (typeof cb === 'function') {
cb();
}
}
runWatchers.displayName = 'run:watchers';
module.exports = runWatchers;

View File

@@ -0,0 +1,15 @@
const { src, dest } = require('gulp');
const header = require('gulp-header');
const dayjs = require('dayjs');
const { outputScript, outputStyle } = require('../config/directories');
function versionfy() {
return src([`${outputScript}/**/*.js`, `${outputStyle}/**/*.css`])
.pipe(header(`/* version: ${dayjs().format('DD-MM-YYYY HH:mm:ss')} */`))
.pipe(dest((file) => file.base));
}
versionfy.displayName = 'versionfy';
module.exports = versionfy;

View File

@@ -0,0 +1,34 @@
const { series } = require('gulp');
const cleanOutput = require('../private-tasks/clean--output');
const buildAssets = require('../private-tasks/build--assets');
const bundleScripts = require('../private-tasks/bundle--scripts');
const cleanTempScripts = require('../private-tasks/clean--temp-scripts');
const backupChunkScripts = require('../private-tasks/backup--chunk-scripts');
const minifyChunkScripts = require('../private-tasks/minify--chunk-scripts');
const bundleStyles = require('../private-tasks/bundle--styles');
const cleanTempStyles = require('../private-tasks/clean--temp-styles');
const minifyStyles = require('../private-tasks/minify--styles');
const versionfy = require('../private-tasks/versionfy');
const buildViews = require('../private-tasks/build--views');
const buildViewsMin = require('../private-tasks/build--views-min');
const printResults = require('../private-tasks/print--results');
const tasks = [
cleanOutput,
buildAssets,
bundleScripts,
cleanTempScripts,
backupChunkScripts,
minifyChunkScripts,
bundleStyles(),
bundleStyles(true),
cleanTempStyles,
minifyStyles,
versionfy,
buildViews,
buildViewsMin,
printResults,
];
module.exports = series(...tasks);

View File

@@ -0,0 +1,15 @@
const { series } = require('gulp');
const cleanOutput = require('../private-tasks/clean--output');
const buildAssets = require('../private-tasks/build--assets');
const printResults = require('../private-tasks/print--results');
const runDevServer = require('../private-tasks/run--dev-server');
const tasks = [
cleanOutput,
buildAssets,
printResults,
runDevServer,
];
module.exports = series(...tasks);

View File

@@ -0,0 +1,7 @@
const browserSync = require('browser-sync');
const browserSyncInstance = browserSync.create();
browserSyncInstance.isStreaming = false;
module.exports = browserSyncInstance;

View File

@@ -0,0 +1,63 @@
const cached = require('gulp-cached');
const list = {
get totalIssue() {
return this.totalError + this.totalWarning;
},
};
exports.list = list;
function pushError(info) {
list.data.push(info);
list[info.type === 'Error' ? 'totalError' : 'totalWarning'] += 1;
}
function handleError({ plugin, message, codeFrame = '' } = {}) {
pushError({
type: 'Error',
plugin: plugin.toUpperCase(),
message: message.trim(),
code: codeFrame,
});
if (typeof this.emit === 'function') {
this.emit('end');
} else if (typeof this === 'function') {
this();
}
}
exports.handleError = handleError;
exports.handleESLintError = (results) => {
results.forEach(({ filePath, messages } = {}) => {
messages.forEach(({
severity, line, column, message,
} = {}) => {
const type = severity === 2 ? 'Error' : 'Warning';
pushError({
type,
plugin: `ES Lint ${type}`,
message: filePath,
code: `[${line}:${column}] ${message}`,
});
});
});
list.isJSValid = !results.errorCount;
if (results.errorCount || results.warningCount) {
delete cached.caches.eslint;
}
};
function resetError() {
list.data = [];
list.totalError = 0;
list.totalWarning = 0;
list.isJSValid = true;
}
exports.resetError = resetError;
resetError();

View File

@@ -0,0 +1,46 @@
const { readdirSync, lstatSync } = require('fs');
const pushPath = (src, paths, wontInclude) => {
const not = wontInclude ? '!' : '';
return [].concat(paths || []).map((item) => not + src + item);
};
exports.addPath = (src, paths, notIncludePaths) => {
if (typeof src === 'undefined') {
return '**/*';
}
if (typeof paths === 'undefined') {
return `${src}**/*`;
}
const includePaths = pushPath(src, paths, false);
const notICPath = pushPath(src, notIncludePaths, true);
return includePaths.concat(notICPath);
};
exports.getFolders = (dir) => {
try {
return readdirSync(dir)
.filter((folder) => lstatSync(dir + folder).isDirectory());
} catch (err) {
return [];
}
};
exports.pluralText = (text, number) => text + (number > 1 ? 's' : '');
exports.renderErrorHTML = (msg) => `
<body>
<style>
html {
background-color: #000;
color: #fff;
font-family: monospace;
}
</style>
<pre>${msg}</pre>
</body>
`;

1
index.html Normal file
View File

@@ -0,0 +1 @@
<!DOCTYPE html><html><head><!-- build:redirect --><!-- endbuild --></head><body></body></html>

10
jsconfig.json Normal file
View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"baseUrl": "./",
"paths": {
"@/*": ["./src/scripts/*"]
}
},
"exclude": ["node_modules"]
}

96
package.json Normal file
View File

@@ -0,0 +1,96 @@
{
"name": "web-template",
"title": "Web Template",
"description": "Web template use es6, pug, scss, bootstrap",
"version": "4.0.0",
"author": "",
"homepage": "",
"license": "MIT",
"repository": {
"type": "git",
"url": ""
},
"keywords": [
"web",
"template",
"es6",
"pug",
"scss",
"bootstrap"
],
"engines": {
"node": ">=10",
"npm": ">=7"
},
"scripts": {
"list-tasks": "gulp --tasks",
"start": "gulp",
"dev": "gulp",
"build": "gulp build",
"serve": "browser-sync start -c 'gulpfile.js/config/browser-sync-prod.js'",
"upload": "gulp build && gh-pages -d dist"
},
"dependencies": {
"@babel/runtime": "7.13.17",
"bootstrap": "^5.1.3",
"bootstrap-datepicker": "^1.9.0",
"bootstrap-select": "^1.13.18",
"dayjs": "1.10.4",
"debounce": "^1.2.1",
"detectizr": "^2.2.0",
"html-to-image": "^1.9.0",
"jquery": "^3.6.0",
"jquery-mask-plugin": "^1.14.16",
"jquery-validation": "^1.19.3",
"moment": "^2.29.1",
"parsleyjs": "^2.9.2",
"slick-carousel": "^1.8.1"
},
"devDependencies": {
"@babel/core": "^7.16.0",
"@babel/plugin-proposal-class-properties": "^7.16.0",
"@babel/plugin-proposal-decorators": "^7.16.4",
"@babel/plugin-proposal-optional-chaining": "^7.16.0",
"@babel/plugin-proposal-pipeline-operator": "^7.16.0",
"@babel/plugin-proposal-private-methods": "^7.16.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.6.2",
"@babel/preset-env": "^7.16.4",
"@babel/runtime": "^7.6.2",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.2.3",
"browser-sync": "^2.27.7",
"compression": "^1.7.4",
"del": "^6.0.0",
"eslint-config-airbnb-base": "14.2.1",
"eslint-import-resolver-webpack": "0.13.0",
"eslint-plugin-import": "2.22.1",
"express": "4.17.1",
"gh-pages": "^3.2.3",
"gulp": "^4.0.2",
"gulp-autoprefixer": "^6.1.0",
"gulp-cached": "1.1.1",
"gulp-clean-css": "4.3.0",
"gulp-cli": "2.3.0",
"gulp-concat": "2.6.1",
"gulp-eslint": "6.0.0",
"gulp-header": "2.0.9",
"gulp-html-replace": "1.6.2",
"gulp-merge-json": "2.1.1",
"gulp-nodemon": "^2.2.1",
"gulp-notify": "^4.0.0",
"gulp-pug": "^5.0.0",
"gulp-rename": "2.0.0",
"gulp-rtlcss": "^2.0.0",
"gulp-sass": "^5.1.0",
"gulp-sass-unicode": "^1.0.2",
"gulp-uglify": "3.0.2",
"pug": "3.0.2",
"require-dir": "1.2.0",
"sass": "^1.51.0",
"strip-indent": "3.0.0",
"vinyl-named": "1.1.0",
"webpack": "^5.65.0",
"webpack-stream": "6.1.2"
}
}

35
server/index.js Normal file
View File

@@ -0,0 +1,35 @@
const express = require('express');
const pug = require('pug');
const route = require('./route');
const { STATIC_PORT } = require('../gulpfile.js/config/server');
const { srcView, output } = require('../gulpfile.js/config/directories');
const pugOptions = require('../gulpfile.js/config/pug');
const { renderErrorHTML } = require('../gulpfile.js/utils');
const app = express();
app.locals.moment = require('moment');
const { log } = console;
app.engine('pug', (path, options, callback) => {
const opts = { ...pugOptions, ...options };
pug.renderFile(path, opts, (err, result) => {
const data = result || renderErrorHTML(err.message);
callback(null, data);
});
});
app.set('views', srcView);
app.set('view engine', 'pug');
app.use(express.static(output));
app.use(express.json());
app.use(express.urlencoded({
extended: true,
}));
app.use('/', route);
const logPort = `----- View server is running at http://localhost:${STATIC_PORT} -----`;
app.listen(STATIC_PORT, () => log(logPort));

83
server/route.js Normal file
View File

@@ -0,0 +1,83 @@
/* eslint-disable-next-line */
const { join } = require('path');
const express = require('express');
const router = express.Router();
const { output, srcLocales } = require('../gulpfile.js/config/directories');
const { renderErrorHTML } = require('../gulpfile.js/utils');
const { DEFAULT_LANG } = require('../gulpfile.js/config/server');
const multiLang = process.env.MULTI_LANGUAGE;
function forceRequire(path) {
const realPath = join(__dirname, path);
delete require.cache[realPath];
/* eslint-disable-next-line */
return require(path);
}
router.get('/', (_, res) => {
const defautLangPath = multiLang ? `/${DEFAULT_LANG}` : '';
res.redirect(`${defautLangPath}/index.html`);
});
router.get('/*.html', (req, res) => {
try {
let lang;
let match;
let localeLang;
let { path: url } = req;
if (multiLang) {
const testLang = /^\/([^/]+)\//.exec(url);
if (!testLang) {
throw new Error('No language in the url');
}
[match, lang] = testLang;
localeLang = forceRequire(`../${srcLocales + lang}.json`);
url = url.replace(match, '');
}
const testFile = /[/]?(.+)\.html/.exec(url);
if (!testFile) {
throw new Error('Not found');
}
res.render(testFile[1], {
$translator: localeLang || {},
$localeName: lang,
$path: req.url,
}, (err, html) => {
if (err) {
throw err;
}
res.send(html);
});
} catch (err) {
res.send(renderErrorHTML(err)).status(404);
}
});
router.get(/^\/.*[^(.html)]$/, (req, res) => {
res.redirect(join(req.path, 'index.html'));
});
router.post('*', (req, res) => {
try {
const json = forceRequire(join(__dirname, '..', output, req.url));
res.send(json);
} catch (err) {
res.send(renderErrorHTML(err)).status(404);
}
});
module.exports = router;

0
src/assets/data/.gitkeep Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#ffc40d</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="553.000000pt" height="553.000000pt" viewBox="0 0 553.000000 553.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,553.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M3505 5519 c-21 -11 -54 -45 -499 -503 -143 -148 -278 -285 -298
-305 -83 -81 -82 -192 1 -235 81 -42 106 -29 297 168 546 560 651 670 666 704
29 62 3 138 -56 166 -39 18 -82 20 -111 5z"/>
<path d="M2084 5486 c-64 -28 -94 -95 -72 -159 16 -46 437 -483 484 -503 65
-27 145 10 165 76 23 76 9 100 -131 244 -70 72 -172 177 -226 232 -127 131
-148 141 -220 110z"/>
<path d="M2734 5484 c-48 -24 -70 -71 -66 -146 2 -31 107 -150 153 -174 107
-55 220 60 169 172 -9 22 -42 63 -73 92 -79 74 -121 87 -183 56z"/>
<path d="M2749 4093 c-14 -10 -68 -61 -119 -113 -247 -254 -304 -310 -310
-310 -4 0 -87 84 -186 186 -98 102 -187 190 -197 195 -31 17 -79 18 -113 4
-67 -28 -95 -127 -54 -190 10 -16 98 -111 194 -209 l174 -180 -113 -115 c-63
-64 -127 -131 -144 -150 l-30 -33 -167 170 c-174 179 -204 200 -268 188 -69
-13 -118 -108 -90 -175 7 -17 71 -91 142 -164 72 -72 146 -149 165 -169 l36
-37 -87 -89 c-295 -302 -311 -320 -317 -355 -10 -51 2 -90 37 -126 32 -33 46
-36 120 -32 23 1 65 42 593 586 149 153 304 313 345 355 319 326 556 573 563
586 27 49 14 124 -28 164 -33 31 -110 38 -146 13z"/>
<path d="M3609 4058 c-38 -10 -34 -6 -704 -696 -88 -91 -198 -204 -245 -252
-47 -48 -206 -213 -355 -365 -148 -153 -306 -315 -350 -360 -199 -204 -615
-633 -642 -662 -41 -44 -57 -85 -49 -128 14 -75 89 -124 159 -104 35 9 72 46
667 659 151 156 309 318 350 360 41 42 199 204 350 359 151 156 316 325 365
376 419 427 583 600 598 627 22 43 22 85 -3 125 -35 57 -79 76 -141 61z"/>
<path d="M4055 3555 c-17 -7 -81 -66 -144 -131 -63 -66 -238 -247 -390 -402
-152 -156 -307 -316 -346 -356 -61 -63 -547 -563 -720 -741 -120 -123 -602
-620 -684 -704 -46 -47 -152 -156 -235 -241 -84 -85 -160 -167 -170 -182 -25
-39 -23 -101 5 -143 38 -54 100 -71 157 -41 23 12 167 157 587 591 68 70 601
618 715 735 41 42 199 204 350 360 151 155 319 328 374 384 120 124 636 653
655 673 22 23 26 104 7 141 -30 59 -100 84 -161 57z"/>
<path d="M4096 2635 c-26 -9 -72 -49 -150 -128 -189 -195 -608 -626 -671 -691
-65 -67 -605 -622 -720 -741 -164 -168 -617 -634 -703 -723 -52 -54 -98 -108
-103 -121 -5 -13 -9 -44 -8 -68 4 -72 75 -126 151 -115 33 5 53 25 453 437
306 315 342 352 695 715 140 144 296 304 345 355 245 251 623 640 729 748 65
67 125 137 133 156 20 46 10 109 -23 144 -14 15 -26 27 -27 27 -1 0 -16 4 -33
9 -20 6 -43 4 -68 -4z"/>
<path d="M4065 1640 c-17 -7 -155 -146 -545 -550 -30 -31 -175 -180 -321 -331
-147 -151 -328 -337 -403 -414 -75 -77 -140 -151 -144 -165 -12 -35 -6 -87 12
-116 31 -46 68 -61 142 -55 20 1 147 124 367 354 36 37 67 63 69 58 7 -20 319
-333 345 -346 37 -20 71 -19 112 3 40 21 71 73 71 117 0 51 -22 77 -286 346
l-65 65 142 147 142 147 39 -43 c170 -182 313 -318 344 -326 68 -19 136 21
155 91 20 75 9 90 -278 379 l-85 86 62 64 c34 35 110 114 169 174 59 61 113
119 118 130 46 86 -15 196 -109 194 -18 0 -42 -4 -53 -9z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View File

Binary file not shown.

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe900;" glyph-name="infomation" d="M512 192c-28.16 0-51.2 23.040-51.2 51.2v204.8c0 28.16 23.040 51.2 51.2 51.2s51.2-23.040 51.2-51.2v-204.8c0-28.16-23.040-51.2-51.2-51.2zM512.512-64c282.624 0 511.488 229.376 511.488 512s-228.864 512-511.488 512c-283.136 0-512.512-229.376-512.512-512s229.376-512 512.512-512zM512 857.6c226.304 0 409.6-183.296 409.6-409.6s-183.296-409.6-409.6-409.6c-226.304 0-409.6 183.296-409.6 409.6s183.296 409.6 409.6 409.6zM460.8 652.8c0 28.277 22.923 51.2 51.2 51.2v0c28.277 0 51.2-22.923 51.2-51.2v0c0-28.277-22.923-51.2-51.2-51.2v0c-28.277 0-51.2 22.923-51.2 51.2v0z" />
<glyph unicode="&#xe901;" glyph-name="arrow-down" horiz-adv-x="1365" d="M120.515 548.053l442.028-442.027c66.56-66.56 174.080-66.56 240.64 0l442.027 442.027c107.52 107.52 30.72 291.84-121.173 291.84h-884.053c-151.894 0-226.987-184.32-119.468-291.84z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Binary file not shown.

BIN
src/assets/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

View File

@@ -0,0 +1,55 @@
/**
* fullPage 2.6.6
* https://github.com/alvarotrigo/fullPage.js
* MIT licensed
*
* Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
*/
(function(c,l){"function"===typeof define&&define.amd?define(["jquery"],function(k){return l(k,c,c.document,c.Math)}):"undefined"!==typeof exports?module.exports=l(require("jquery"),c,c.document,c.Math):l(jQuery,c,c.document,c.Math)})("undefined"!==typeof window?window:this,function(c,l,k,n,H){var m=c(l),r=c(k);c.fn.fullpage=function(d){function Ia(a){a.find(".fp-slides").after('<div class="fp-controlArrow fp-prev"></div><div class="fp-controlArrow fp-next"></div>');"#fff"!=d.controlArrowColor&&(a.find(".fp-controlArrow.fp-next").css("border-color",
"transparent transparent transparent "+d.controlArrowColor),a.find(".fp-controlArrow.fp-prev").css("border-color","transparent "+d.controlArrowColor+" transparent transparent"));d.loopHorizontal||a.find(".fp-controlArrow.fp-prev").hide()}function Ja(){p.append('<div id="fp-nav"><ul></ul></div>');z=c("#fp-nav");z.addClass(function(){return d.showActiveTooltip?"fp-show-active "+d.navigationPosition:d.navigationPosition});for(var a=0;a<c(".fp-section").length;a++){var b="";d.anchors.length&&(b=d.anchors[a]);
var b='<li><a href="#'+b+'"><span></span></a>',g=d.navigationTooltips[a];"undefined"!==typeof g&&""!==g&&(b+='<div class="fp-tooltip '+d.navigationPosition+'">'+g+"</div>");b+="</li>";z.find("ul").append(b)}}function da(){c(".fp-section").each(function(){var a=c(this).find(".fp-slide");a.length?a.each(function(){I(c(this))}):I(c(this))});ea()}function ea(){var a=c(".fp-section.active"),b=a.find("SLIDES_WRAPPER"),g=a.find(".fp-scrollable");b.length&&(g=b.find(".fp-slide.active"));g.mouseover();fa(a);
c.isFunction(d.afterLoad)&&d.afterLoad.call(a,a.data("anchor"),a.index(".fp-section")+1);c.isFunction(d.afterRender)&&d.afterRender.call(this)}function ga(){var a;if(!d.autoScrolling||d.scrollBar){for(var b=m.scrollTop(),g=0,J=n.abs(b-k.querySelectorAll(".fp-section")[0].offsetTop),e=k.querySelectorAll(".fp-section"),f=0;f<e.length;++f){var h=n.abs(b-e[f].offsetTop);h<J&&(g=f,J=h)}a=c(e).eq(g)}if(!d.autoScrolling||d.scrollBar){if(!a.hasClass("active")){U=!0;b=c(".fp-section.active");g=b.index(".fp-section")+
1;J=V(a);e=a.data("anchor");f=a.index(".fp-section")+1;h=a.find(".fp-slide.active");if(h.length)var l=h.data("anchor"),p=h.index();u&&(a.addClass("active").siblings().removeClass("active"),c.isFunction(d.onLeave)&&d.onLeave.call(b,g,f,J),c.isFunction(d.afterLoad)&&d.afterLoad.call(a,e,f),K(e,f-1),d.anchors.length&&(A=e,W(p,l,e,f)));clearTimeout(ha);ha=setTimeout(function(){U=!1},100)}d.fitToSection&&(clearTimeout(ia),ia=setTimeout(function(){u&&(c(".fp-section.active").is(a)&&(v=!0),B(a),v=!1)},1E3))}}
function ja(a){return a.find(".fp-slides").length?a.find(".fp-slide.active").find(".fp-scrollable"):a.find(".fp-scrollable")}function L(a,b){if(h.m[a]){var d,c;"down"==a?(d="bottom",c=e.moveSectionDown):(d="top",c=e.moveSectionUp);if(0<b.length)if(d="top"===d?!b.scrollTop():"bottom"===d?b.scrollTop()+1+b.innerHeight()>=b[0].scrollHeight:void 0,d)c();else return!0;else c()}}function Ka(a){var b=a.originalEvent;if(!ka(a.target)&&X(b)){d.autoScrolling&&a.preventDefault();a=c(".fp-section.active");var g=
ja(a);u&&!w&&(b=la(b),D=b.y,M=b.x,a.find(".fp-slides").length&&n.abs(N-M)>n.abs(E-D)?n.abs(N-M)>m.width()/100*d.touchSensitivity&&(N>M?h.m.right&&e.moveSlideRight():h.m.left&&e.moveSlideLeft()):d.autoScrolling&&n.abs(E-D)>m.height()/100*d.touchSensitivity&&(E>D?L("down",g):D>E&&L("up",g)))}}function ka(a,b){b=b||0;var g=c(a).parent();return b<d.normalScrollElementTouchThreshold&&g.is(d.normalScrollElements)?!0:b==d.normalScrollElementTouchThreshold?!1:ka(g,++b)}function X(a){return"undefined"===typeof a.pointerType||
"mouse"!=a.pointerType}function La(a){a=a.originalEvent;d.fitToSection&&x.stop();X(a)&&(a=la(a),E=a.y,N=a.x)}function ma(a,b){for(var d=0,c=a.slice(n.max(a.length-b,1)),e=0;e<c.length;e++)d+=c[e];return n.ceil(d/b)}function t(a){var b=(new Date).getTime();if(d.autoScrolling&&!O){a=l.event||a;var g=a.wheelDelta||-a.deltaY||-a.detail,e=n.max(-1,n.min(1,g));149<C.length&&C.shift();C.push(n.abs(g));d.scrollBar&&(a.preventDefault?a.preventDefault():a.returnValue=!1);a=c(".fp-section.active");a=ja(a);g=
b-na;na=b;200<g&&(C=[]);u&&(b=ma(C,10),g=ma(C,70),b>=g&&(0>e?L("down",a):L("up",a)));return!1}d.fitToSection&&x.stop()}function oa(a){var b=c(".fp-section.active").find(".fp-slides"),g=b.find(".fp-slide").length;if(!(!b.length||w||2>g)){var g=b.find(".fp-slide.active"),e=null,e="prev"===a?g.prev(".fp-slide"):g.next(".fp-slide");if(!e.length){if(!d.loopHorizontal)return;e="prev"===a?g.siblings(":last"):g.siblings(":first")}w=!0;F(b,e)}}function pa(){c(".fp-slide.active").each(function(){Y(c(this),
"internal")})}function B(a,b,g){var e=a.position();if("undefined"!==typeof e&&(b={element:a,callback:b,isMovementUp:g,dest:e,dtop:e.top,yMovement:V(a),anchorLink:a.data("anchor"),sectionIndex:a.index(".fp-section"),activeSlide:a.find(".fp-slide.active"),activeSection:c(".fp-section.active"),leavingSection:c(".fp-section.active").index(".fp-section")+1,localIsResizing:v},!(b.activeSection.is(a)&&!v||d.scrollBar&&m.scrollTop()===b.dtop))){if(b.activeSlide.length)var f=b.activeSlide.data("anchor"),h=
b.activeSlide.index();d.autoScrolling&&d.continuousVertical&&"undefined"!==typeof b.isMovementUp&&(!b.isMovementUp&&"up"==b.yMovement||b.isMovementUp&&"down"==b.yMovement)&&(b.isMovementUp?c(".fp-section.active").before(b.activeSection.nextAll(".fp-section")):c(".fp-section.active").after(b.activeSection.prevAll(".fp-section").get().reverse()),y(c(".fp-section.active").position().top),pa(),b.wrapAroundElements=b.activeSection,b.dest=b.element.position(),b.dtop=b.dest.top,b.yMovement=V(b.element));
if(c.isFunction(d.onLeave)&&!b.localIsResizing){if(!1===d.onLeave.call(b.activeSection,b.leavingSection,b.sectionIndex+1,b.yMovement))return;Ma(b.activeSection)}a.addClass("active").siblings().removeClass("active");u=!1;W(h,f,b.anchorLink,b.sectionIndex);Na(b);A=b.anchorLink;K(b.anchorLink,b.sectionIndex)}}function Na(a){if(d.css3&&d.autoScrolling&&!d.scrollBar)qa("translate3d(0px, -"+a.dtop+"px, 0px)",!0),d.scrollingSpeed?setTimeout(function(){Z(a)},d.scrollingSpeed):Z(a);else{var b=Oa(a);c(b.element).animate(b.options,
d.scrollingSpeed,d.easing).promise().done(function(){Z(a)})}}function Oa(a){var b={};d.autoScrolling&&!d.scrollBar?(b.options={top:-a.dtop},b.element=".fullpage-wrapper"):(b.options={scrollTop:a.dtop},b.element="html, body");return b}function Z(a){a.wrapAroundElements&&a.wrapAroundElements.length&&(a.isMovementUp?c(".fp-section:first").before(a.wrapAroundElements):c(".fp-section:last").after(a.wrapAroundElements),y(c(".fp-section.active").position().top),pa());a.element.find(".fp-scrollable").mouseover();
c.isFunction(d.afterLoad)&&!a.localIsResizing&&d.afterLoad.call(a.element,a.anchorLink,a.sectionIndex+1);fa(a.element);Pa(a.element);u=!0;c.isFunction(a.callback)&&a.callback.call(this)}function fa(a){a.find("img[data-src], video[data-src], audio[data-src]").each(function(){c(this).attr("src",c(this).data("src"));c(this).removeAttr("data-src")})}function Pa(a){a.find("video, audio").each(function(){var a=c(this).get(0);a.hasAttribute("autoplay")&&"function"===typeof a.play&&a.play()})}function Ma(a){a.find("video, audio").each(function(){var a=
c(this).get(0);a.hasAttribute("data-ignore")||"function"!==typeof a.pause||a.pause()})}function ra(){if(!U&&!d.lockAnchors){var a=l.location.hash.replace("#","").split("/"),b=a[0],a=a[1];if(b.length){var c="undefined"===typeof A,e="undefined"===typeof A&&"undefined"===typeof a&&!w;(b&&b!==A&&!c||e||!w&&aa!=a)&&ba(b,a)}}}function Qa(a){u&&(a.pageY<P?e.moveSectionUp():a.pageY>P&&e.moveSectionDown());P=a.pageY}function F(a,b){var g=b.position(),e=b.index(),f=a.closest(".fp-section"),h=f.index(".fp-section"),
k=f.data("anchor"),l=f.find(".fp-slidesNav"),m=sa(b),p=v;if(d.onSlideLeave){var t=f.find(".fp-slide.active"),q=t.index(),r;r=q==e?"none":q>e?"left":"right";if(!p&&"none"!==r&&c.isFunction(d.onSlideLeave)&&!1===d.onSlideLeave.call(t,k,h+1,q,r,e)){w=!1;return}}b.addClass("active").siblings().removeClass("active");!d.loopHorizontal&&d.controlArrows&&(f.find(".fp-controlArrow.fp-prev").toggle(0!==e),f.find(".fp-controlArrow.fp-next").toggle(!b.is(":last-child")));f.hasClass("active")&&W(e,m,k,h);var u=
function(){p||c.isFunction(d.afterSlideLoad)&&d.afterSlideLoad.call(b,k,h+1,m,e);w=!1};d.css3?(g="translate3d(-"+n.round(g.left)+"px, 0px, 0px)",ta(a.find(".fp-slidesContainer"),0<d.scrollingSpeed).css(ua(g)),setTimeout(function(){u()},d.scrollingSpeed,d.easing)):a.animate({scrollLeft:n.round(g.left)},d.scrollingSpeed,d.easing,function(){u()});l.find(".active").removeClass("active");l.find("li").eq(e).find("a").addClass("active")}function va(){wa();if(Q){var a=c(k.activeElement);a.is("textarea")||
a.is("input")||a.is("select")||(a=m.height(),n.abs(a-ca)>20*n.max(ca,a)/100&&(e.reBuild(!0),ca=a))}else clearTimeout(xa),xa=setTimeout(function(){e.reBuild(!0)},350)}function wa(){var a=d.responsive||d.responsiveWidth,b=d.responsiveHeight;a&&e.setResponsive(m.width()<a);b&&(f.hasClass("fp-responsive")||e.setResponsive(m.height()<b))}function ta(a){var b="all "+d.scrollingSpeed+"ms "+d.easingcss3;a.removeClass("fp-notransition");return a.css({"-webkit-transition":b,transition:b})}function Ra(a,b){if(825>
a||900>b){var d=n.min(100*a/825,100*b/900).toFixed(2);p.css("font-size",d+"%")}else p.css("font-size","100%")}function K(a,b){d.menu&&(c(d.menu).find(".active").removeClass("active"),c(d.menu).find('[data-menuanchor="'+a+'"]').addClass("active"));d.navigation&&(c("#fp-nav").find(".active").removeClass("active"),a?c("#fp-nav").find('a[href="#'+a+'"]').addClass("active"):c("#fp-nav").find("li").eq(b).find("a").addClass("active"))}function V(a){var b=c(".fp-section.active").index(".fp-section");a=a.index(".fp-section");
return b==a?"none":b>a?"up":"down"}function I(a){a.css("overflow","hidden");var b=a.closest(".fp-section"),c=a.find(".fp-scrollable"),e;c.length?e=c.get(0).scrollHeight:(e=a.get(0).scrollHeight,d.verticalCentered&&(e=a.find(".fp-tableCell").get(0).scrollHeight));b=q-parseInt(b.css("padding-bottom"))-parseInt(b.css("padding-top"));e>b?c.length?c.css("height",b+"px").parent().css("height",b+"px"):(d.verticalCentered?a.find(".fp-tableCell").wrapInner('<div class="fp-scrollable" />'):a.wrapInner('<div class="fp-scrollable" />'),
a.find(".fp-scrollable").slimScroll({allowPageScroll:!0,height:b+"px",size:"10px",alwaysVisible:!0})):ya(a);a.css("overflow","")}function ya(a){a.find(".fp-scrollable").children().first().unwrap().unwrap();a.find(".slimScrollBar").remove();a.find(".slimScrollRail").remove()}function za(a){a.addClass("fp-table").wrapInner('<div class="fp-tableCell" style="height:'+Aa(a)+'px;" />')}function Aa(a){var b=q;if(d.paddingTop||d.paddingBottom)b=a,b.hasClass("fp-section")||(b=a.closest(".fp-section")),a=parseInt(b.css("padding-top"))+
parseInt(b.css("padding-bottom")),b=q-a;return b}function qa(a,b){b?ta(f):f.addClass("fp-notransition");f.css(ua(a));setTimeout(function(){f.removeClass("fp-notransition")},10)}function Ba(a){var b=c('.fp-section[data-anchor="'+a+'"]');b.length||(b=c(".fp-section").eq(a-1));return b}function ba(a,b){var d=Ba(a);"undefined"===typeof b&&(b=0);a===A||d.hasClass("active")?Ca(d,b):B(d,function(){Ca(d,b)})}function Ca(a,b){if("undefined"!==typeof b){var d=a.find(".fp-slides"),c;c=a.find(".fp-slides");var e=
c.find('.fp-slide[data-anchor="'+b+'"]');e.length||(e=c.find(".fp-slide").eq(b));c=e;c.length&&F(d,c)}}function Sa(a,b){a.append('<div class="fp-slidesNav"><ul></ul></div>');var c=a.find(".fp-slidesNav");c.addClass(d.slidesNavPosition);for(var e=0;e<b;e++)c.find("ul").append('<li><a href="#"><span></span></a></li>');c.css("margin-left","-"+c.width()/2+"px");c.find("li").first().find("a").addClass("active")}function W(a,b,c,e){e="";d.anchors.length&&!d.lockAnchors&&(a?("undefined"!==typeof c&&(e=c),
"undefined"===typeof b&&(b=a),aa=b,Da(e+"/"+b)):("undefined"!==typeof a&&(aa=b),Da(c)));Ea()}function Da(a){if(d.recordHistory)location.hash=a;else if(Q||R)history.replaceState(H,H,"#"+a);else{var b=l.location.href.split("#")[0];l.location.replace(b+"#"+a)}}function sa(a){var b=a.data("anchor");a=a.index();"undefined"===typeof b&&(b=a);return b}function Ea(){var a=c(".fp-section.active"),b=a.find(".fp-slide.active"),e=a.data("anchor"),f=sa(b),a=a.index(".fp-section"),a=String(a);d.anchors.length&&
(a=e);b.length&&(a=a+"-"+f);a=a.replace("/","-").replace("#","");p[0].className=p[0].className.replace(RegExp("\\b\\s?fp-viewing-[^\\s]+\\b","g"),"");p.addClass("fp-viewing-"+a)}function Ta(){var a=k.createElement("p"),b,c={webkitTransform:"-webkit-transform",OTransform:"-o-transform",msTransform:"-ms-transform",MozTransform:"-moz-transform",transform:"transform"};k.body.insertBefore(a,null);for(var d in c)a.style[d]!==H&&(a.style[d]="translate3d(1px,1px,1px)",b=l.getComputedStyle(a).getPropertyValue(c[d]));
k.body.removeChild(a);return b!==H&&0<b.length&&"none"!==b}function Ua(){if(Q||R){var a=Fa();c(".fullpage-wrapper").off("touchstart "+a.down).on("touchstart "+a.down,La);c(".fullpage-wrapper").off("touchmove "+a.move).on("touchmove "+a.move,Ka)}}function Va(){if(Q||R){var a=Fa();c(".fullpage-wrapper").off("touchstart "+a.down);c(".fullpage-wrapper").off("touchmove "+a.move)}}function Fa(){return l.PointerEvent?{down:"pointerdown",move:"pointermove"}:{down:"MSPointerDown",move:"MSPointerMove"}}function la(a){var b=
[];b.y="undefined"!==typeof a.pageY&&(a.pageY||a.pageX)?a.pageY:a.touches[0].pageY;b.x="undefined"!==typeof a.pageX&&(a.pageY||a.pageX)?a.pageX:a.touches[0].pageX;R&&X(a)&&(b.y=a.touches[0].pageY,b.x=a.touches[0].pageX);return b}function Y(a,b){e.setScrollingSpeed(0,"internal");"undefined"!==typeof b&&(v=!0);F(a.closest(".fp-slides"),a);"undefined"!==typeof b&&(v=!1);e.setScrollingSpeed(G.scrollingSpeed,"internal")}function y(a){d.scrollBar?f.scrollTop(a):d.css3?qa("translate3d(0px, -"+a+"px, 0px)",
!1):f.css("top",-a)}function ua(a){return{"-webkit-transform":a,"-moz-transform":a,"-ms-transform":a,transform:a}}function Ga(a,b,c){switch(b){case "up":h[c].up=a;break;case "down":h[c].down=a;break;case "left":h[c].left=a;break;case "right":h[c].right=a;break;case "all":"m"==c?e.setAllowScrolling(a):e.setKeyboardScrolling(a)}}function Wa(){y(0);c("#fp-nav, .fp-slidesNav, .fp-controlArrow").remove();c(".fp-section").css({height:"","background-color":"",padding:""});c(".fp-slide").css({width:""});
f.css({height:"",position:"","-ms-touch-action":"","touch-action":""});c(".fp-section, .fp-slide").each(function(){ya(c(this));c(this).removeClass("fp-table active")});f.addClass("fp-notransition");f.find(".fp-tableCell, .fp-slidesContainer, .fp-slides").each(function(){c(this).replaceWith(this.childNodes)});x.scrollTop(0)}function S(a,b,c){d[a]=b;"internal"!==c&&(G[a]=b)}function T(a,b){console&&console[a]&&console[a]("fullPage: "+b)}var x=c("html, body"),p=c("body"),e=c.fn.fullpage;d=c.extend({menu:!1,
anchors:[],lockAnchors:!1,navigation:!1,navigationPosition:"right",navigationTooltips:[],showActiveTooltip:!1,slidesNavigation:!1,slidesNavPosition:"bottom",scrollBar:!1,css3:!0,scrollingSpeed:700,autoScrolling:!0,fitToSection:!0,easing:"easeInOutCubic",easingcss3:"ease",loopBottom:!1,loopTop:!1,loopHorizontal:!0,continuousVertical:!1,normalScrollElements:null,scrollOverflow:!1,touchSensitivity:5,normalScrollElementTouchThreshold:5,keyboardScrolling:!0,animateAnchor:!0,recordHistory:!0,controlArrows:!0,
controlArrowColor:"#fff",verticalCentered:!0,resize:!1,sectionsColor:[],paddingTop:0,paddingBottom:0,fixedElements:null,responsive:0,responsiveWidth:0,responsiveHeight:0,sectionSelector:".section",slideSelector:".slide",afterLoad:null,onLeave:null,afterRender:null,afterResize:null,afterReBuild:null,afterSlideLoad:null,onSlideLeave:null},d);(function(){d.continuousVertical&&(d.loopTop||d.loopBottom)&&(d.continuousVertical=!1,T("warn","Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled"));
d.continuousVertical&&d.scrollBar&&(d.continuousVertical=!1,T("warn","Option `scrollBar` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled"));c.each(d.anchors,function(a,b){(c("#"+b).length||c('[name="'+b+'"]').length)&&T("error","data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).")})})();c.extend(c.easing,{easeInOutCubic:function(a,b,c,d,e){return 1>(b/=e/2)?d/2*b*b*b+c:d/2*((b-=2)*b*b+2)+c}});c.extend(c.easing,{easeInQuart:function(a,
b,c,d,e){return d*(b/=e)*b*b*b+c}});e.setAutoScrolling=function(a,b){S("autoScrolling",a,b);var g=c(".fp-section.active");d.autoScrolling&&!d.scrollBar?(x.css({overflow:"hidden",height:"100%"}),e.setRecordHistory(d.recordHistory,"internal"),f.css({"-ms-touch-action":"none","touch-action":"none"}),g.length&&y(g.position().top)):(x.css({overflow:"visible",height:"initial"}),e.setRecordHistory(!1,"internal"),f.css({"-ms-touch-action":"","touch-action":""}),y(0),g.length&&x.scrollTop(g.position().top))};
e.setRecordHistory=function(a,b){S("recordHistory",a,b)};e.setScrollingSpeed=function(a,b){S("scrollingSpeed",a,b)};e.setFitToSection=function(a,b){S("fitToSection",a,b)};e.setLockAnchors=function(a){d.lockAnchors=a};e.setMouseWheelScrolling=function(a){a?k.addEventListener?(k.addEventListener("mousewheel",t,!1),k.addEventListener("wheel",t,!1),k.addEventListener("DOMMouseScroll",t,!1)):k.attachEvent("onmousewheel",t):k.addEventListener?(k.removeEventListener("mousewheel",t,!1),k.removeEventListener("wheel",
t,!1),k.removeEventListener("DOMMouseScroll",t,!1)):k.detachEvent("onmousewheel",t)};e.setAllowScrolling=function(a,b){"undefined"!==typeof b?(b=b.replace(/ /g,"").split(","),c.each(b,function(b,c){Ga(a,c,"m")})):a?(e.setMouseWheelScrolling(!0),Ua()):(e.setMouseWheelScrolling(!1),Va())};e.setKeyboardScrolling=function(a,b){"undefined"!==typeof b?(b=b.replace(/ /g,"").split(","),c.each(b,function(b,c){Ga(a,c,"k")})):d.keyboardScrolling=a};e.moveSectionUp=function(){var a=c(".fp-section.active").prev(".fp-section");
a.length||!d.loopTop&&!d.continuousVertical||(a=c(".fp-section").last());a.length&&B(a,null,!0)};e.moveSectionDown=function(){var a=c(".fp-section.active").next(".fp-section");a.length||!d.loopBottom&&!d.continuousVertical||(a=c(".fp-section").first());!a.length||d.onBeforeMoveSection&&c.isFunction(d.onBeforeMoveSection)&&!1===d.onBeforeMoveSection.call(this,direction,currentSlide,destiny,slides,activeSection)||B(a,null,!1)};e.silentMoveTo=function(a,b){e.setScrollingSpeed(0,"internal");e.moveTo(a,
b);e.setScrollingSpeed(G.scrollingSpeed,"internal")};e.moveTo=function(a,b){var c=Ba(a);"undefined"!==typeof b?ba(a,b):0<c.length&&B(c)};e.moveSlideRight=function(){oa("next")};e.moveSlideLeft=function(){oa("prev")};e.reBuild=function(a){if(!f.hasClass("fp-destroyed")){v=!0;var b=m.width();q=m.height();d.resize&&Ra(q,b);c(".fp-section").each(function(){var a=c(this).find(".fp-slides"),b=c(this).find(".fp-slide");d.verticalCentered&&c(this).find(".fp-tableCell").css("height",Aa(c(this))+"px");c(this).css("height",
q+"px");d.scrollOverflow&&(b.length?b.each(function(){I(c(this))}):I(c(this)));1<b.length&&F(a,a.find(".fp-slide.active"))});(b=c(".fp-section.active").index(".fp-section"))&&e.silentMoveTo(b+1);v=!1;c.isFunction(d.afterResize)&&a&&d.afterResize.call(f);c.isFunction(d.afterReBuild)&&!a&&d.afterReBuild.call(f)}};e.setResponsive=function(a){var b=f.hasClass("fp-responsive");a?b||(e.setAutoScrolling(!1,"internal"),e.setFitToSection(!1,"internal"),c("#fp-nav").hide(),f.addClass("fp-responsive")):b&&(e.setAutoScrolling(G.autoScrolling,
"internal"),e.setFitToSection(G.autoScrolling,"internal"),c("#fp-nav").show(),f.removeClass("fp-responsive"))};var w=!1,Q=navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/),R="ontouchstart"in l||0<navigator.msMaxTouchPoints||navigator.maxTouchPoints,f=c(this),q=m.height(),v=!1,A,aa,u=!0,C=[],z,O,h={m:{up:!0,down:!0,left:!0,right:!0}};h.k=c.extend(!0,{},h.m);var G=c.extend(!0,{},d);c(this).length?(f.css({height:"100%",
position:"relative"}),f.addClass("fullpage-wrapper"),c("html").addClass("fp-enabled")):T("error","Error! Fullpage.js needs to be initialized with a selector. For example: $('#myContainer').fullpage();");d.css3&&(d.css3=Ta());e.setAllowScrolling(!0);f.removeClass("fp-destroyed");c(d.sectionSelector).each(function(){c(this).addClass("fp-section")});c(d.slideSelector).each(function(){c(this).addClass("fp-slide")});d.navigation&&Ja();c(".fp-section").each(function(a){var b=c(this),e=c(this).find(".fp-slide"),
f=e.length;a||0!==c(".fp-section.active").length||c(this).addClass("active");c(this).css("height",q+"px");d.paddingTop&&c(this).css("padding-top",d.paddingTop);d.paddingBottom&&c(this).css("padding-bottom",d.paddingBottom);"undefined"!==typeof d.sectionsColor[a]&&c(this).css("background-color",d.sectionsColor[a]);"undefined"!==typeof d.anchors[a]&&(c(this).attr("data-anchor",d.anchors[a]),c(this).hasClass("active")&&K(d.anchors[a],a));if(0<f){a=100*f;var h=100/f;e.wrapAll('<div class="fp-slidesContainer" />');
e.parent().wrap('<div class="fp-slides" />');c(this).find(".fp-slidesContainer").css("width",a+"%");1<f&&(d.controlArrows&&Ia(c(this)),d.slidesNavigation&&Sa(c(this),f));e.each(function(a){c(this).css("width",h+"%");d.verticalCentered&&za(c(this))});b=b.find(".fp-slide.active");b.length?Y(b):e.eq(0).addClass("active")}else d.verticalCentered&&za(c(this))}).promise().done(function(){e.setAutoScrolling(d.autoScrolling,"internal");var a=c(".fp-section.active").find(".fp-slide.active");a.length&&(0!==
c(".fp-section.active").index(".fp-section")||0===c(".fp-section.active").index(".fp-section")&&0!==a.index())&&Y(a);d.fixedElements&&d.css3&&c(d.fixedElements).appendTo(p);d.navigation&&(z.css("margin-top","-"+z.height()/2+"px"),z.find("li").eq(c(".fp-section.active").index(".fp-section")).find("a").addClass("active"));d.menu&&d.css3&&c(d.menu).closest(".fullpage-wrapper").length&&c(d.menu).appendTo(p);d.scrollOverflow?("complete"===k.readyState&&da(),m.on("load",da)):ea();wa();if(!d.animateAnchor&&
(a=l.location.hash.replace("#","").split("/")[0],a.length)){var b=c('[data-anchor="'+a+'"]');b.length&&(d.autoScrolling?y(b.position().top):(y(0),x.scrollTop(b.position().top)),K(a,null),c.isFunction(d.afterLoad)&&d.afterLoad.call(b,a,b.index(".fp-section")+1),b.addClass("active").siblings().removeClass("active"))}Ea();m.on("load",function(){var a=l.location.hash.replace("#","").split("/"),b=a[0],a=a[1];b&&ba(b,a)})});var ha,ia,U=!1;m.on("scroll",ga);var E=0,N=0,D=0,M=0,na=(new Date).getTime();m.on("hashchange",
ra);r.keydown(function(a){clearTimeout(Ha);var b=c(":focus");b.is("textarea")||b.is("input")||b.is("select")||!d.keyboardScrolling||!d.autoScrolling||(-1<c.inArray(a.which,[40,38,32,33,34])&&a.preventDefault(),Ha=setTimeout(function(){var b=a.shiftKey;O=a.ctrlKey;switch(a.which){case 38:case 33:h.k.up&&e.moveSectionUp();break;case 32:if(b&&h.k.up){e.moveSectionUp();break}case 40:case 34:h.k.down&&e.moveSectionDown();break;case 36:h.k.up&&e.moveTo(1);break;case 35:h.k.down&&e.moveTo(c(".fp-section").length);
break;case 37:h.k.left&&e.moveSlideLeft();break;case 39:h.k.right&&e.moveSlideRight()}},150))});r.keyup(function(a){O=a.ctrlKey});c(l).blur(function(){O=!1});var Ha;f.mousedown(function(a){2==a.which&&(P=a.pageY,f.on("mousemove",Qa))});f.mouseup(function(a){2==a.which&&f.off("mousemove")});var P=0;r.on("click touchstart","#fp-nav a",function(a){a.preventDefault();a=c(this).parent().index();B(c(".fp-section").eq(a))});r.on("click touchstart",".fp-slidesNav a",function(a){a.preventDefault();a=c(this).closest(".fp-section").find(".fp-slides");
var b=a.find(".fp-slide").eq(c(this).closest("li").index());F(a,b)});d.normalScrollElements&&(r.on("mouseenter",d.normalScrollElements,function(){e.setMouseWheelScrolling(!1)}),r.on("mouseleave",d.normalScrollElements,function(){e.setMouseWheelScrolling(!0)}));c(".fp-section").on("click touchstart",".fp-controlArrow",function(){c(this).hasClass("fp-prev")?h.m.left&&e.moveSlideLeft():h.m.right&&e.moveSlideRight()});m.resize(va);var ca=q,xa;e.destroy=function(a){e.setAutoScrolling(!1,"internal");e.setAllowScrolling(!1);
e.setKeyboardScrolling(!1);f.addClass("fp-destroyed");m.off("scroll",ga).off("hashchange",ra).off("resize",va);r.off("click","#fp-nav a").off("mouseenter","#fp-nav li").off("mouseleave","#fp-nav li").off("click",".fp-slidesNav a").off("mouseover",d.normalScrollElements).off("mouseout",d.normalScrollElements);c(".fp-section").off("click",".fp-controlArrow");a&&Wa()}}});

View File

@@ -0,0 +1,774 @@
/*!
* modernizr v3.6.0
* Build https://modernizr.com/download?-touchevents-addtest-setclasses-dontmin
*
* Copyright (c)
* Faruk Ates
* Paul Irish
* Alex Sexton
* Ryan Seddon
* Patrick Kettner
* Stu Cox
* Richard Herrera
* MIT License
*/
/*
* Modernizr tests which native CSS3 and HTML5 features are available in the
* current UA and makes the results available to you in two ways: as properties on
* a global `Modernizr` object, and as classes on the `<html>` element. This
* information allows you to progressively enhance your pages with a granular level
* of control over the experience.
*/
;(function(window, document, undefined){
var classes = [];
var tests = [];
/**
*
* ModernizrProto is the constructor for Modernizr
*
* @class
* @access public
*/
var ModernizrProto = {
// The current version, dummy
_version: '3.6.0',
// Any settings that don't work as separate modules
// can go in here as configuration.
_config: {
'classPrefix': '',
'enableClasses': true,
'enableJSClass': true,
'usePrefixes': true
},
// Queue of tests
_q: [],
// Stub these for people who are listening
on: function(test, cb) {
// I don't really think people should do this, but we can
// safe guard it a bit.
// -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
// This is in case people listen to synchronous tests. I would leave it out,
// but the code to *disallow* sync tests in the real version of this
// function is actually larger than this.
var self = this;
setTimeout(function() {
cb(self[test]);
}, 0);
},
addTest: function(name, fn, options) {
tests.push({name: name, fn: fn, options: options});
},
addAsyncTest: function(fn) {
tests.push({name: null, fn: fn});
}
};
// Fake some of Object.create so we can force non test results to be non "own" properties.
var Modernizr = function() {};
Modernizr.prototype = ModernizrProto;
// Leak modernizr globally when you `require` it rather than force it here.
// Overwrite name so constructor name is nicer :D
Modernizr = new Modernizr();
/**
* is returns a boolean if the typeof an obj is exactly type.
*
* @access private
* @function is
* @param {*} obj - A thing we want to check the type of
* @param {string} type - A string to compare the typeof against
* @returns {boolean}
*/
function is(obj, type) {
return typeof obj === type;
}
;
/**
* Run through all tests and detect their support in the current UA.
*
* @access private
*/
function testRunner() {
var featureNames;
var feature;
var aliasIdx;
var result;
var nameIdx;
var featureName;
var featureNameSplit;
for (var featureIdx in tests) {
if (tests.hasOwnProperty(featureIdx)) {
featureNames = [];
feature = tests[featureIdx];
// run the test, throw the return value into the Modernizr,
// then based on that boolean, define an appropriate className
// and push it into an array of classes we'll join later.
//
// If there is no name, it's an 'async' test that is run,
// but not directly added to the object. That should
// be done with a post-run addTest call.
if (feature.name) {
featureNames.push(feature.name.toLowerCase());
if (feature.options && feature.options.aliases && feature.options.aliases.length) {
// Add all the aliases into the names list
for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
}
}
}
// Run the test, or use the raw value if it's not a function
result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
// Set each of the names on the Modernizr object
for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
featureName = featureNames[nameIdx];
// Support dot properties as sub tests. We don't do checking to make sure
// that the implied parent tests have been added. You must call them in
// order (either in the test, or make the parent test a dependency).
//
// Cap it to TWO to make the logic simple and because who needs that kind of subtesting
// hashtag famous last words
featureNameSplit = featureName.split('.');
if (featureNameSplit.length === 1) {
Modernizr[featureNameSplit[0]] = result;
} else {
// cast to a Boolean, if not one already
if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
}
Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
}
classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
}
}
}
}
;
/**
* docElement is a convenience wrapper to grab the root element of the document
*
* @access private
* @returns {HTMLElement|SVGElement} The root element of the document
*/
var docElement = document.documentElement;
/**
* A convenience helper to check if the document we are running in is an SVG document
*
* @access private
* @returns {boolean}
*/
var isSVG = docElement.nodeName.toLowerCase() === 'svg';
/**
* setClasses takes an array of class names and adds them to the root element
*
* @access private
* @function setClasses
* @param {string[]} classes - Array of class names
*/
// Pass in an and array of class names, e.g.:
// ['no-webp', 'borderradius', ...]
function setClasses(classes) {
var className = docElement.className;
var classPrefix = Modernizr._config.classPrefix || '';
if (isSVG) {
className = className.baseVal;
}
// Change `no-js` to `js` (independently of the `enableClasses` option)
// Handle classPrefix on this too
if (Modernizr._config.enableJSClass) {
var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
className = className.replace(reJS, '$1' + classPrefix + 'js$2');
}
if (Modernizr._config.enableClasses) {
// Add the new classes
className += ' ' + classPrefix + classes.join(' ' + classPrefix);
if (isSVG) {
docElement.className.baseVal = className;
} else {
docElement.className = className;
}
}
}
;
/**
* hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
*
* @author kangax
* @access private
* @function hasOwnProp
* @param {object} object - The object to check for a property
* @param {string} property - The property to check for
* @returns {boolean}
*/
// hasOwnProperty shim by kangax needed for Safari 2.0 support
var hasOwnProp;
(function() {
var _hasOwnProperty = ({}).hasOwnProperty;
/* istanbul ignore else */
/* we have no way of testing IE 5.5 or safari 2,
* so just assume the else gets hit */
if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
hasOwnProp = function(object, property) {
return _hasOwnProperty.call(object, property);
};
}
else {
hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
};
}
})();
// _l tracks listeners for async tests, as well as tests that execute after the initial run
ModernizrProto._l = {};
/**
* Modernizr.on is a way to listen for the completion of async tests. Being
* asynchronous, they may not finish before your scripts run. As a result you
* will get a possibly false negative `undefined` value.
*
* @memberof Modernizr
* @name Modernizr.on
* @access public
* @function on
* @param {string} feature - String name of the feature detect
* @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not
* @example
*
* ```js
* Modernizr.on('flash', function( result ) {
* if (result) {
* // the browser has flash
* } else {
* // the browser does not have flash
* }
* });
* ```
*/
ModernizrProto.on = function(feature, cb) {
// Create the list of listeners if it doesn't exist
if (!this._l[feature]) {
this._l[feature] = [];
}
// Push this test on to the listener list
this._l[feature].push(cb);
// If it's already been resolved, trigger it on next tick
if (Modernizr.hasOwnProperty(feature)) {
// Next Tick
setTimeout(function() {
Modernizr._trigger(feature, Modernizr[feature]);
}, 0);
}
};
/**
* _trigger is the private function used to signal test completion and run any
* callbacks registered through [Modernizr.on](#modernizr-on)
*
* @memberof Modernizr
* @name Modernizr._trigger
* @access private
* @function _trigger
* @param {string} feature - string name of the feature detect
* @param {function|boolean} [res] - A feature detection function, or the boolean =
* result of a feature detection function
*/
ModernizrProto._trigger = function(feature, res) {
if (!this._l[feature]) {
return;
}
var cbs = this._l[feature];
// Force async
setTimeout(function() {
var i, cb;
for (i = 0; i < cbs.length; i++) {
cb = cbs[i];
cb(res);
}
}, 0);
// Don't trigger these again
delete this._l[feature];
};
/**
* addTest allows you to define your own feature detects that are not currently
* included in Modernizr (under the covers it's the exact same code Modernizr
* uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result
* will be added onto the Modernizr object, as well as an appropriate className set on
* the html element when configured to do so
*
* @memberof Modernizr
* @name Modernizr.addTest
* @optionName Modernizr.addTest()
* @optionProp addTest
* @access public
* @function addTest
* @param {string|object} feature - The string name of the feature detect, or an
* object of feature detect names and test
* @param {function|boolean} test - Function returning true if feature is supported,
* false if not. Otherwise a boolean representing the results of a feature detection
* @example
*
* The most common way of creating your own feature detects is by calling
* `Modernizr.addTest` with a string (preferably just lowercase, without any
* punctuation), and a function you want executed that will return a boolean result
*
* ```js
* Modernizr.addTest('itsTuesday', function() {
* var d = new Date();
* return d.getDay() === 2;
* });
* ```
*
* When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
* and to `false` every other day of the week. One thing to notice is that the names of
* feature detect functions are always lowercased when added to the Modernizr object. That
* means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
*
*
* Since we only look at the returned value from any feature detection function,
* you do not need to actually use a function. For simple detections, just passing
* in a statement that will return a boolean value works just fine.
*
* ```js
* Modernizr.addTest('hasJquery', 'jQuery' in window);
* ```
*
* Just like before, when the above runs `Modernizr.hasjquery` will be true if
* jQuery has been included on the page. Not using a function saves a small amount
* of overhead for the browser, as well as making your code much more readable.
*
* Finally, you also have the ability to pass in an object of feature names and
* their tests. This is handy if you want to add multiple detections in one go.
* The keys should always be a string, and the value can be either a boolean or
* function that returns a boolean.
*
* ```js
* var detects = {
* 'hasjquery': 'jQuery' in window,
* 'itstuesday': function() {
* var d = new Date();
* return d.getDay() === 2;
* }
* }
*
* Modernizr.addTest(detects);
* ```
*
* There is really no difference between the first methods and this one, it is
* just a convenience to let you write more readable code.
*/
function addTest(feature, test) {
if (typeof feature == 'object') {
for (var key in feature) {
if (hasOwnProp(feature, key)) {
addTest(key, feature[ key ]);
}
}
} else {
feature = feature.toLowerCase();
var featureNameSplit = feature.split('.');
var last = Modernizr[featureNameSplit[0]];
// Again, we don't check for parent test existence. Get that right, though.
if (featureNameSplit.length == 2) {
last = last[featureNameSplit[1]];
}
if (typeof last != 'undefined') {
// we're going to quit if you're trying to overwrite an existing test
// if we were to allow it, we'd do this:
// var re = new RegExp("\\b(no-)?" + feature + "\\b");
// docElement.className = docElement.className.replace( re, '' );
// but, no rly, stuff 'em.
return Modernizr;
}
test = typeof test == 'function' ? test() : test;
// Set the value (this is the magic, right here).
if (featureNameSplit.length == 1) {
Modernizr[featureNameSplit[0]] = test;
} else {
// cast to a Boolean, if not one already
if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
}
Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test;
}
// Set a single class (either `feature` or `no-feature`)
setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]);
// Trigger the event
Modernizr._trigger(feature, test);
}
return Modernizr; // allow chaining.
}
// After all the tests are run, add self to the Modernizr prototype
Modernizr._q.push(function() {
ModernizrProto.addTest = addTest;
});
/**
* List of property values to set for css tests. See ticket #21
* http://git.io/vUGl4
*
* @memberof Modernizr
* @name Modernizr._prefixes
* @optionName Modernizr._prefixes
* @optionProp prefixes
* @access public
* @example
*
* Modernizr._prefixes is the internal list of prefixes that we test against
* inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
* an array of kebab-case vendor prefixes you can use within your code.
*
* Some common use cases include
*
* Generating all possible prefixed version of a CSS property
* ```js
* var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
*
* rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
* ```
*
* Generating all possible prefixed version of a CSS value
* ```js
* rule = 'display:' + Modernizr._prefixes.join('flex; display:') + 'flex';
*
* rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
* ```
*/
// we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
// values in feature detects to continue to work
var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']);
// expose these for the plugin API. Look in the source for how to join() them against your input
ModernizrProto._prefixes = prefixes;
/**
* createElement is a convenience wrapper around document.createElement. Since we
* use createElement all over the place, this allows for (slightly) smaller code
* as well as abstracting away issues with creating elements in contexts other than
* HTML documents (e.g. SVG documents).
*
* @access private
* @function createElement
* @returns {HTMLElement|SVGElement} An HTML or SVG element
*/
function createElement() {
if (typeof document.createElement !== 'function') {
// This is the case in IE7, where the type of createElement is "object".
// For this reason, we cannot call apply() as Object is not a Function.
return document.createElement(arguments[0]);
} else if (isSVG) {
return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
} else {
return document.createElement.apply(document, arguments);
}
}
;
/**
* getBody returns the body of a document, or an element that can stand in for
* the body if a real body does not exist
*
* @access private
* @function getBody
* @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
* artificially created element that stands in for the body
*/
function getBody() {
// After page load injecting a fake body doesn't work so check if body exists
var body = document.body;
if (!body) {
// Can't use the real body create a fake one.
body = createElement(isSVG ? 'svg' : 'body');
body.fake = true;
}
return body;
}
;
/**
* injectElementWithStyles injects an element with style element and some CSS rules
*
* @access private
* @function injectElementWithStyles
* @param {string} rule - String representing a css rule
* @param {function} callback - A function that is used to test the injected element
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
* @returns {boolean}
*/
function injectElementWithStyles(rule, callback, nodes, testnames) {
var mod = 'modernizr';
var style;
var ret;
var node;
var docOverflow;
var div = createElement('div');
var body = getBody();
if (parseInt(nodes, 10)) {
// In order not to give false positives we create a node for each test
// This also allows the method to scale for unspecified uses
while (nodes--) {
node = createElement('div');
node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
div.appendChild(node);
}
}
style = createElement('style');
style.type = 'text/css';
style.id = 's' + mod;
// IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
// Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
(!body.fake ? div : body).appendChild(style);
body.appendChild(div);
if (style.styleSheet) {
style.styleSheet.cssText = rule;
} else {
style.appendChild(document.createTextNode(rule));
}
div.id = mod;
if (body.fake) {
//avoid crashing IE8, if background image is used
body.style.background = '';
//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
body.style.overflow = 'hidden';
docOverflow = docElement.style.overflow;
docElement.style.overflow = 'hidden';
docElement.appendChild(body);
}
ret = callback(div, rule);
// If this is done after page load we don't want to remove the body so check if body exists
if (body.fake) {
body.parentNode.removeChild(body);
docElement.style.overflow = docOverflow;
// Trigger layout so kinetic scrolling isn't disabled in iOS6+
// eslint-disable-next-line
docElement.offsetHeight;
} else {
div.parentNode.removeChild(div);
}
return !!ret;
}
;
/**
* testStyles injects an element with style element and some CSS rules
*
* @memberof Modernizr
* @name Modernizr.testStyles
* @optionName Modernizr.testStyles()
* @optionProp testStyles
* @access public
* @function testStyles
* @param {string} rule - String representing a css rule
* @param {function} callback - A function that is used to test the injected element
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
* @returns {boolean}
* @example
*
* `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
* along with (possibly multiple) DOM elements. This lets you check for features
* that can not be detected by simply checking the [IDL](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Interface_development_guide/IDL_interface_rules).
*
* ```js
* Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
* // elem is the first DOM node in the page (by default #modernizr)
* // rule is the first argument you supplied - the CSS rule in string form
*
* addTest('widthworks', elem.style.width === '9px')
* });
* ```
*
* If your test requires multiple nodes, you can include a third argument
* indicating how many additional div elements to include on the page. The
* additional nodes are injected as children of the `elem` that is returned as
* the first argument to the callback.
*
* ```js
* Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
* document.getElementById('modernizr').style.width === '1px'; // true
* document.getElementById('modernizr2').style.width === '2px'; // true
* elem.firstChild === document.getElementById('modernizr2'); // true
* }, 1);
* ```
*
* By default, all of the additional elements have an ID of `modernizr[n]`, where
* `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
* the second additional is `#modernizr3`, etc.).
* If you want to have more meaningful IDs for your function, you can provide
* them as the fourth argument, as an array of strings
*
* ```js
* Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
* elem.firstChild === document.getElementById('foo'); // true
* elem.lastChild === document.getElementById('bar'); // true
* }, 2, ['foo', 'bar']);
* ```
*
*/
var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
/*!
{
"name": "Touch Events",
"property": "touchevents",
"caniuse" : "touch",
"tags": ["media", "attribute"],
"notes": [{
"name": "Touch Events spec",
"href": "https://www.w3.org/TR/2013/WD-touch-events-20130124/"
}],
"warnings": [
"Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device"
],
"knownBugs": [
"False-positive on some configurations of Nokia N900",
"False-positive on some BlackBerry 6.0 builds https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695"
]
}
!*/
/* DOC
Indicates if the browser supports the W3C Touch Events API.
This *does not* necessarily reflect a touchscreen device:
* Older touchscreen devices only emulate mouse events
* Modern IE touch devices implement the Pointer Events API instead: use `Modernizr.pointerevents` to detect support for that
* Some browsers & OS setups may enable touch APIs when no touchscreen is connected
* Future browsers may implement other event models for touch interactions
See this article: [You Can't Detect A Touchscreen](http://www.stucox.com/blog/you-cant-detect-a-touchscreen/).
It's recommended to bind both mouse and touch/pointer events simultaneously see [this HTML5 Rocks tutorial](http://www.html5rocks.com/en/mobile/touchandmouse/).
This test will also return `true` for Firefox 4 Multitouch support.
*/
// Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415
Modernizr.addTest('touchevents', function() {
var bool;
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
bool = true;
} else {
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = ['@media (', prefixes.join('touch-enabled),('), 'heartz', ')', '{#modernizr{top:9px;position:absolute}}'].join('');
testStyles(query, function(node) {
bool = node.offsetTop === 9;
});
}
return bool;
});
// Run each test
testRunner();
// Remove the "no-js" class if it exists
setClasses(classes);
delete ModernizrProto.addTest;
delete ModernizrProto.addAsyncTest;
// Run the things that are supposed to run after the tests
for (var i = 0; i < Modernizr._q.length; i++) {
Modernizr._q[i]();
}
// Leak Modernizr namespace
window.Modernizr = Modernizr;
;
})(window, document);

6210
src/scripts/_libs/select2.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
const states = {
loading: 0,
interactive: 1,
complete: 2
};
const READY_STATE = 'DOMContentLoaded';
function getElementData (el) {
const elDataset = el.dataset;
return Object.keys(elDataset).reduce((obj, key) => {
let data = {};
if (elDataset[key]) {
data[key] = '';
try {
data[key] = JSON.parse(elDataset[key]);
} catch (err) {
data[key] = elDataset[key];
}
}
return { ...obj, ...data };
}, {});
}
function setupClass (Class, element, options, pluginName) {
const _this = new Class();
_this.__pluginName = pluginName;
_this.$element = $(element);
_this.options = $.extend(
{},
$.fn[pluginName].defaults,
getElementData(element),
options
);
_this.props = {};
typeof _this.init === 'function' && _this.init();
return _this;
}
export default function Plugin (param) {
function createPlugin (Class) {
const baseName = Class.name;
const name = baseName.toKebabCase();
const options = (param && param.options) || {};
const loadEvent = (param && param.when) || READY_STATE;
const selector = param && param.selector;
function init () {
$(`[data-${name}]`)[name]();
if (typeof selector === 'string') {
$(selector)[name]();
}
}
$.fn[name] = function (opts, params) {
const instanceName = `${name}-instance`;
return this.each(function () {
const instance = $.data(this, instanceName);
if (!(instance instanceof Class)) {
$.data(this, instanceName, setupClass(Class, this, opts, name));
return;
}
if (typeof instance[opts] !== 'function') {
console.error(`This element has been initialized with plugin ${baseName}, please provide a correct method`);
return;
}
instance[opts](params);
});
};
$.fn[name].defaults = options;
if (loadEvent === READY_STATE && states[document.readyState] > 0) {
init();
} else {
window.addEventListener(loadEvent, init);
}
return Class;
}
return typeof param === 'function' ? createPlugin(param) : createPlugin;
}

17
src/scripts/cores/prototype.js vendored Normal file
View File

@@ -0,0 +1,17 @@
const PI = Math.PI;
String.prototype.toCamelCase = function () {
return this.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
};
String.prototype.toKebabCase = function () {
return this.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
};
Number.prototype.toRad = function () {
return this * PI / 180;
};
Number.prototype.toDeg = function () {
return this * 180 / PI;
};

View File

@@ -0,0 +1,59 @@
const { documentElement: html } = document;
const isTouch = 'ontouchstart' in window
|| navigator.maxTouchPoints > 0
|| navigator.msMaxTouchPoints > 0;
html.classList.add(isTouch ? 'touch' : 'no-touch');
if (typeof InstallTrigger !== 'undefined') {
html.classList.add('firefox');
}
const isIOSPlatform = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod',
].includes(navigator.platform);
if (isIOSPlatform || (navigator.userAgent.includes('Mac') && isTouch)) {
html.classList.add('ios');
}
const isDeviceMobile = [
'Android',
'webOS',
'iPhone',
'iPod',
'BlackBerry',
'IEMobile',
'Opera Mini',
].includes(navigator.userAgent);
if (isDeviceMobile) {
html.classList.add('is-device');
}
const isIE = document.documentMode;
if (isIE) {
html.classList.add('ie');
}
if (!isIE && window.StyleMedia) {
html.classList.add('edge');
}
const isChrome = !!window.chrome;
if (isChrome) {
html.classList.add('chrome');
}
if (isChrome && navigator.userAgent.indexOf('Edg') > -1) {
html.classList.add('edge-chromium');
}
export default null;

View File

@@ -0,0 +1,9 @@
// Initializations
import '../cores/prototype';
import 'moment';
import 'parsleyjs';
import 'jquery';
// import '../_libs/jquery.fullPage.min.js';
window.devj = $;

View File

@@ -0,0 +1,82 @@
import { throttle } from '../utils';
import { $win } from '../utils/doms';
import layout from '../utils/layout';
let passiveIfSupported = false;
let lastWinScroll = layout.scroll;
let resizeTimeout;
let lastWinWidth = layout.width;
let lastWinHeight = layout.height;
let lastBreakpointIsDesktop = layout.isDesktop;
const RESIZE_TIME = 180;
try {
const passive = Object.defineProperty({}, 'passive', {
get() {
passiveIfSupported = { passive: true };
return true;
},
});
window.addEventListener('test', null, passive);
} catch (err) { /**/ }
window.addEventListener('scroll', throttle(() => {
const currentWinScroll = layout.scroll;
if (currentWinScroll === lastWinScroll) {
return;
}
const name = currentWinScroll < lastWinScroll ? 'up' : 'down';
$win.trigger('scrolling', currentWinScroll);
$win.trigger(`scroll:${name}`, currentWinScroll);
lastWinScroll = currentWinScroll;
}), passiveIfSupported);
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
setTimeout(() => {
const currentWinWidth = layout.width;
const currentWinHeight = layout.height;
const isWidthChanged = lastWinWidth !== currentWinWidth;
const isHeightChanged = lastWinHeight !== currentWinHeight;
$win.trigger('resized', [currentWinWidth, currentWinHeight]);
if (isWidthChanged) {
$win.trigger('width-change', currentWinWidth);
const currentBreakpointIsDesktop = layout.isDesktop;
if (lastBreakpointIsDesktop !== currentBreakpointIsDesktop) {
// Prevent conflict event name with slick
$win.trigger('breakpoint:change', currentWinWidth);
const breakpointEvtName = currentBreakpointIsDesktop
? 'desktop'
: 'mobile';
$win.trigger(`breakpoint:${breakpointEvtName}`, currentWinWidth);
lastBreakpointIsDesktop = currentBreakpointIsDesktop;
}
lastWinWidth = currentWinWidth;
}
if (isHeightChanged) {
$win.trigger('height-change', currentWinHeight);
lastWinHeight = currentWinHeight;
}
if (isWidthChanged && isHeightChanged) {
$win.trigger('size-change', currentWinWidth, currentWinHeight);
}
}, RESIZE_TIME);
}, passiveIfSupported);

View File

@@ -0,0 +1,7 @@
const { staticJsAssetsPath } = window;
if (staticJsAssetsPath) {
__webpack_require__.p = staticJsAssetsPath;
}
export default null;

8
src/scripts/main.js Normal file
View File

@@ -0,0 +1,8 @@
import '@/initializations/update-js-assets-path';
import '@/initializations/browser-detect';
import '@/initializations/import-jquery-plugins';
import '@/initializations/improve-window-events';
import 'slick-carousel';
// Plugins
import '@/plugins/back-to-top';

View File

@@ -0,0 +1,22 @@
import { $win } from '@/utils/doms';
@Plugin
export default class BackToTop {
init() {
const $ele = this.$element;
$ele.off(`click`).on(`click`, () => {
$('html, body').animate({
scrollTop: 0,
});
});
$win.on('scroll', () => {
if ($win.scrollTop() > 20) {
$ele.addClass('active');
} else {
$ele.removeClass('active');
}
});
}
}

View File

@@ -0,0 +1,98 @@
import { transformObjectToParams } from '@/utils';
function getScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.async = true;
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
export class ApiRepository {
baseUrl = '';
scriptCacher = {};
getScript = getScript;
constructor(baseUrl = '') {
this.baseUrl = baseUrl;
}
getUrl(path, params) {
let url = this.baseUrl + path;
if (typeof params === 'object') {
url += `?${transformObjectToParams(params)}`;
}
return url;
}
loadScript(url) {
if (!this.scriptCacher[url]) {
this.scriptCacher[url] = getScript(url);
}
return this.scriptCacher[url];
}
get(path, data) {
return new Promise((resolve, reject) => {
const url = this.getUrl(path);
$.ajax({
url,
data,
method: 'get',
})
.done(resolve)
.catch(reject);
});
}
post(path, data = {}) {
return new Promise((resolve, reject) => {
const url = this.getUrl(path);
$.ajax({
url,
data,
method: 'post',
})
.done(resolve)
.catch(reject);
});
}
put(path, data = {}) {
return new Promise((resolve, reject) => {
const url = this.getUrl(path);
$.ajax({
url,
data,
method: 'put',
})
.done(resolve)
.catch(reject);
});
}
async resolveJSON(data) {
if (typeof data === 'object') {
return data;
}
const response = await this.get(data);
return response;
}
}
export default new ApiRepository();

View File

@@ -0,0 +1,40 @@
export default {
set(key, value = '', days = 7) {
if (!key) {
console.error('no key to set cookie');
return;
}
let expires = '';
if (days) {
const date = new Date();
const expiresDate = days * 24 * 60 * 60 * 1000;
date.setTime(date.getTime() + expiresDate);
expires = `; expires=${date.toUTCString()}`;
}
document.cookie = `${key}=${value.toString() + expires}`;
},
get(key) {
const cookieArr = document.cookie.split(';');
for (let i = 0, l = cookieArr.length; i < l; i += 1) {
const perCookie = cookieArr[i].trim();
const indexOfSplitter = perCookie.trim().indexOf('=');
const perCookieKey = perCookie.slice(0, indexOfSplitter);
if (perCookieKey === key) {
return perCookie.slice(indexOfSplitter + 1);
}
}
return null;
},
remove(key) {
document.cookie = `${key}=; Max-Age=-99999999;`;
},
};

11
src/scripts/utils/date.js Normal file
View File

@@ -0,0 +1,11 @@
import dayjs from 'dayjs';
export const defaultDateFormat = 'YYYY-MM-DD';
export function transformNumberToDate(number, format = defaultDateFormat) {
return dayjs(number).format(format);
}
export function transformDateToNumber(date) {
return +dayjs(date, defaultDateFormat);
}

View File

@@ -0,0 +1,9 @@
export const $win = $(window);
export const $doc = $(document);
export const $html = $('html');
export const $body = $('body');
export const $mapKey = $('meta[name="map-key"]');
export const $htmlAndbody = $('html, body');
export const $canFixed = $([
'.header',
].join(','));

75
src/scripts/utils/http.js Normal file
View File

@@ -0,0 +1,75 @@
import { GMAP_URL, DEFAULT_AJAX_OPTS } from './variables';
import { wait } from './index';
import { lang } from './layout';
const SCRIPT_CACHED = {};
function getScript (src) {
return new Promise((resolve, reject) => {
let script = document.createElement('script');
script.async = true;
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
export function loadScript (url) {
if (!SCRIPT_CACHED[url]) {
SCRIPT_CACHED[url] = getScript(url);
}
return SCRIPT_CACHED[url];
}
export function callApi (opts) {
return new Promise((resolve, reject) => {
const isString = typeof opts === 'string';
let options = {
...DEFAULT_AJAX_OPTS,
data: {},
url: isString ? opts : ''
};
if (!isString) {
options = { ...options, ...opts };
}
if (!options.data.lang) {
options.data.lang = lang;
}
$.ajax(options).done(resolve).fail(reject);
});
}
export async function loadMapApi () {
await loadScript(GMAP_URL);
return window.google.maps;
}
export async function download (url, fileName = '') {
if (!url) {
return;
}
const $link = $('<a />', {
href: url,
download: fileName,
style: 'display:none'
});
$link
.on('click', e => e.stopImmediatePropagation())
.appendTo('body')[0]
.click();
await wait();
$link.remove();
}

View File

@@ -0,0 +1,53 @@
export function throttle(fn, thisArg = window) {
let scheduledAnimationFrame;
return () => {
if (scheduledAnimationFrame) {
return;
}
scheduledAnimationFrame = true;
requestAnimationFrame(() => {
fn.call(thisArg);
scheduledAnimationFrame = false;
});
};
}
export function transformToCamelCase(str) {
return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
}
export function transformToKebabCase(str) {
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}
export function cloneJSON(json) {
return JSON.parse(JSON.stringify(json));
}
export function transformObjectToParams(obj) {
return Object
.keys(obj)
.reduce((arr, key) => (
arr.concat(`${key}=${encodeURIComponent(obj[key])}`)
), [])
.join('&');
}
export function wait (ms = 10) {
let timeout;
const _promise = new Promise((resolve) => {
timeout = setTimeout(() => {
resolve(timeout);
}, ms);
});
_promise.cancel = () => clearTimeout(timeout);
return _promise;
}
export const waitTmp = { cancel () { /* empty fn */ } };

225
src/scripts/utils/layout.js Normal file
View File

@@ -0,0 +1,225 @@
import { $canFixed } from '@/utils/doms';
import { RESPONSIVE_BREAKPOINTS } from './variables';
const { TABLET, DESKTOP } = RESPONSIVE_BREAKPOINTS;
const { body, documentElement: html } = document;
const freezeClass = '--freeze';
const addBorderClass = '--add-fixed-border';
let lockTimeout;
let lastScroll;
let $header = $('.header');
function calculateScrollWidth() {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.top = '0px';
div.style.left = '0px';
div.style.width = '100%';
div.style.height = '50px';
body.appendChild(div);
const fullWidth = div.offsetWidth;
div.style.overflowY = 'scroll';
const limitWidth = div.clientWidth;
body.removeChild(div);
const scrollWidth = fullWidth - limitWidth;
html.classList.add(`--scroll-${scrollWidth}`);
return scrollWidth;
}
export const removeAccents = (alias) => {
let str = alias;
str = str.replace(/à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ/g, 'a')
.replace(/è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ/g, 'e')
.replace(/ì|í|ị|ỉ|ĩ/g, 'i')
.replace(/ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ/g, 'o')
.replace(/ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ/g, 'u')
.replace(/ỳ|ý|ỵ|ỷ|ỹ/g, 'y')
.replace(/đ/g, 'd')
.replace(/À|Á|Ạ|Ả|Ã|Â|Ầ|Ấ|Ậ|Ẩ|Ẫ|Ă|Ằ|Ắ|Ặ|Ẳ|Ẵ/g, 'A')
.replace(/È|É|Ẹ|Ẻ|Ẽ|Ê|Ề|Ế|Ệ|Ể|Ễ/g, 'E')
.replace(/Ì|Í|Ị|Ỉ|Ĩ/g, 'I')
.replace(/Ò|Ó|Ọ|Ỏ|Õ|Ô|Ồ|Ố|Ộ|Ổ|Ỗ|Ơ|Ờ|Ớ|Ợ|Ở|Ỡ/g, 'O')
.replace(/Ù|Ú|Ụ|Ủ|Ũ|Ư|Ừ|Ứ|Ự|Ử|Ữ/g, 'U')
.replace(/Ỳ|Ý|Ỵ|Ỷ|Ỹ/g, 'Y')
.replace(/Đ/g, 'D')
.replace(/\u0300|\u0301|\u0303|\u0309|\u0323/g, '')
.replace(/\u02C6|\u0306|\u031B/g, '')
.replace(/[\u0300-\u036f]/g, '');
return str;
};
export const removeEscape = (value) => {
const str = value.trim().replace(/(<([^>]+)>)|&|<|>|"|'/ig, '');
return removeAccents(str);
};
export const regexEmail = /^([A-Za-z0-9][\._\+\-]{0,1})+[A-Za-z0-9]+@[A-Za-z0-9]+(\.{0,1}[A-Za-z0-9]){2,3}\.[a-z]{2,3}$/; //eslint-disable-line
export const scrollWidth = calculateScrollWidth();
export const lang = html.getAttribute('lang') || '';
export const isRTL = html.getAttribute('dir') === 'rtl';
export const isIOS = html.classList.contains('ios');
export const isIE = html.classList.contains('ie')
|| html.classList.contains('edge');
export default {
scrollWidth,
lang,
isRTL,
isIOS,
isIE,
get screenWidth() {
return window.innerWidth;
},
get width() {
return body.clientWidth;
},
get height() {
return window.innerHeight;
},
get bodyHeight() {
return body.offsetHeight;
},
get isFrozen() {
return body.classList.contains(freezeClass);
},
get isDesktop() {
return this.screenWidth >= DESKTOP;
},
get isSmallScreen() {
return this.screenWidth >= TABLET;
},
get isMobile() {
return !this.isDesktop;
},
get scroll() {
return document.documentElement.scrollTop
|| document.body.scrollTop
|| window.pageYOffset;
},
set scroll(top) {
window.scrollTo({
top,
left: 0,
behavior: 'smooth',
});
},
scrollImmediate(top) {
window.scrollTo(0, top);
},
scrollToElement($element, immediately) {
if (!$element[0]) {
return;
}
if (!$header[0]) {
$header = $('.header');
}
const scrollTo = $element.offset().top - ($header.outerHeight() || 0);
if (immediately) {
this.scrollImmediate(scrollTo);
} else {
this.scroll = $element.offset().top - ($header.outerHeight() || 0);
}
},
freeze(callback) {
clearTimeout(lockTimeout);
setTimeout(() => {
window.isFreezing = true;
const willBeFrozen = !this.isFrozen;
if (!willBeFrozen) {
if (typeof callback === 'function') {
callback();
}
return;
}
if (this.isIOS) {
lastScroll = this.scroll;
body.style.top = `${-lastScroll}px`;
}
body.classList.add(freezeClass);
if (this.bodyHeight > this.height) {
body.classList.add(addBorderClass);
$canFixed.each((_, element) => {
if (window.getComputedStyle(element).position === 'fixed') {
element.classList.add(addBorderClass);
}
});
}
if (this.isIOS) {
this.scrollImmediate(0);
}
if (typeof callback === 'function') {
callback();
}
});
},
unfreeze(callback) {
clearTimeout(lockTimeout);
lockTimeout = setTimeout(() => {
window.isFreezing = false;
if (!this.isFrozen) {
if (typeof callback === 'function') {
callback();
}
return;
}
body.classList.remove(freezeClass);
body.classList.remove(addBorderClass);
$canFixed.removeClass(addBorderClass);
if (this.isIOS) {
body.style.top = '';
this.scrollImmediate(lastScroll);
if (typeof callback === 'function') {
setTimeout(() => {
callback();
}, 50);
}
} else if (typeof callback === 'function') {
callback();
}
});
},
};

View File

@@ -0,0 +1,17 @@
import { $mapKey } from '../utils/doms';
const GMAP_KEY = $mapKey.attr('content') || '';
export const GMAP_URL = GMAP_KEY && `https://maps.googleapis.com/maps/api/js?v=3&key=${GMAP_KEY}`;
export const RESIZE_TIME = 180;
export const RESPONSIVE_BREAKPOINTS = {
TABLET: 768,
DESKTOP: 992
};
export const DEFAULT_AJAX_OPTS = {
cache: false
};

View File

@@ -0,0 +1,15 @@
.footer {
width: 100%;
height: rem(80);
align-items: center;
display: flex;
justify-content: space-between;
color: $color-white;
background-color: $color-black;
padding: 0 rem(20);
font-size: 16px;
img {
max-width: rem(60);
}
}

View File

@@ -0,0 +1,31 @@
.header {
width: 100%;
padding: rem(10) rem(20);
color: $color-black;
background-color: $color-black;
display: flex;
align-items: center;
justify-content: space-between;
img {
max-width: 60px;
}
ul {
display: flex;
color: $color-white;
list-style: none;
padding-left: 0;
margin: 0;
li {
padding: 0 rem(10);
a {
color: $color-white;
font-size: rem(16);
text-decoration: none;
}
}
}
}

8
src/styles/$libs.scss Normal file
View File

@@ -0,0 +1,8 @@
@import "_utils/index";
@import "_cores/layout";
@import "../../node_modules/bootstrap/scss/bootstrap";
@import "../../node_modules/bootstrap-select/dist/css/bootstrap-select";
@import "../../node_modules/slick-carousel/slick/slick";
@import "../../node_modules/slick-carousel/slick/slick-theme";
// @import "_libs/jquery.fullPage";

View File

@@ -0,0 +1,55 @@
html {
font-family: $font-family-default;
font-size: $font-size-rem;
scroll-behavior: smooth;
// height: 100%;
height: -webkit-fill-available;
// Fix modernizr bug
&.safari {
background: none;
}
}
body {
position: relative;
width: 100%;
margin: 0;
font-size: $font-size-default;
font-family: $font-family-default;
--bs-body-font-family: $font-family-default;
.main {
min-height: calc(100vh - 145px);
}
&.freeze {
height: 100%;
overflow: hidden !important; /* stylelint-disable-line */
html.ios & {
position: fixed;
width: 100%;
}
&[class*="--scroll-"] {
border-right-style: solid;
border-right-color: $color-white;
}
@for $i from 13 through 18 {
&.\--scroll-#{$i} {
border-right-width: $i * 1px;
}
}
}
}
img {
max-width: 100%;
&:not([src]),
&[src=""] {
display: none;
}
}

View File

View File

@@ -0,0 +1,203 @@
/**
* fullPage 2.6.6
* https://github.com/alvarotrigo/fullPage.js
* MIT licensed
*
* Copyright (C) 2013 alvarotrigo.com - A project by Alvaro Trigo
*/
html.fp-enabled,
.fp-enabled body {
margin: 0;
padding: 0;
overflow:hidden;
/*Avoid flicker on slides transitions for mobile phones #336 */
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
#superContainer {
height: 100%;
position: relative;
/* Touch detection for Windows 8 */
-ms-touch-action: none;
/* IE 11 on Windows Phone 8.1*/
touch-action: none;
}
.fp-section {
position: relative;
-webkit-box-sizing: border-box; /* Safari<=5 Android<=3 */
-moz-box-sizing: border-box; /* <=28 */
box-sizing: border-box;
}
.fp-slide {
float: left;
}
.fp-slide, .fp-slidesContainer {
height: 100%;
display: block;
}
.fp-slides {
z-index:1;
height: 100%;
overflow: hidden;
position: relative;
-webkit-transition: all 0.3s ease-out; /* Safari<=6 Android<=4.3 */
transition: all 0.3s ease-out;
}
.fp-section.fp-table, .fp-slide.fp-table {
display: table;
table-layout:fixed;
width: 100%;
}
.fp-tableCell {
display: table-cell;
vertical-align: middle;
width: 100%;
height: 100%;
}
.fp-slidesContainer {
float: left;
position: relative;
}
.fp-controlArrow {
position: absolute;
z-index: 4;
top: 50%;
cursor: pointer;
width: 0;
height: 0;
border-style: solid;
margin-top: -38px;
-webkit-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
.fp-controlArrow.fp-prev {
left: 15px;
width: 0;
border-width: 38.5px 34px 38.5px 0;
border-color: transparent #fff transparent transparent;
}
.fp-controlArrow.fp-next {
right: 15px;
border-width: 38.5px 0 38.5px 34px;
border-color: transparent transparent transparent #fff;
}
.fp-scrollable {
overflow: scroll;
}
.fp-notransition {
-webkit-transition: none !important;
transition: none !important;
}
#fp-nav {
position: fixed;
z-index: 100;
margin-top: -32px;
top: 50%;
opacity: 1;
-webkit-transform: translate3d(0,0,0);
}
#fp-nav.right {
right: 17px;
}
#fp-nav.left {
left: 17px;
}
.fp-slidesNav{
position: absolute;
z-index: 4;
left: 50%;
opacity: 1;
}
.fp-slidesNav.bottom {
bottom: 17px;
}
.fp-slidesNav.top {
top: 17px;
}
#fp-nav ul,
.fp-slidesNav ul {
margin: 0;
padding: 0;
}
#fp-nav ul li,
.fp-slidesNav ul li {
display: block;
width: 14px;
height: 13px;
margin: 7px;
position:relative;
}
.fp-slidesNav ul li {
display: inline-block;
}
#fp-nav ul li a,
.fp-slidesNav ul li a {
display: block;
position: relative;
z-index: 1;
width: 100%;
height: 100%;
cursor: pointer;
text-decoration: none;
}
#fp-nav ul li a.active span,
.fp-slidesNav ul li a.active span,
#fp-nav ul li:hover a.active span,
.fp-slidesNav ul li:hover a.active span{
height: 12px;
width: 12px;
margin: -6px 0 0 -6px;
border-radius: 100%;
}
#fp-nav ul li a span,
.fp-slidesNav ul li a span {
border-radius: 50%;
position: absolute;
z-index: 1;
height: 4px;
width: 4px;
border: 0;
background: #333;
left: 50%;
top: 50%;
margin: -2px 0 0 -2px;
-webkit-transition: all 0.1s ease-in-out;
-moz-transition: all 0.1s ease-in-out;
-o-transition: all 0.1s ease-in-out;
transition: all 0.1s ease-in-out;
}
#fp-nav ul li:hover a span,
.fp-slidesNav ul li:hover a span{
width: 10px;
height: 10px;
margin: -5px 0px 0px -5px;
}
#fp-nav ul li .fp-tooltip {
position: absolute;
top: -2px;
color: #fff;
font-size: 14px;
font-family: arial, helvetica, sans-serif;
white-space: nowrap;
max-width: 220px;
overflow: hidden;
display: block;
opacity: 0;
width: 0;
}
#fp-nav ul li:hover .fp-tooltip,
#fp-nav.fp-show-active a.active + .fp-tooltip {
-webkit-transition: opacity 0.2s ease-in;
transition: opacity 0.2s ease-in;
width: auto;
opacity: 1;
}
#fp-nav ul li .fp-tooltip.right {
right: 20px;
}
#fp-nav ul li .fp-tooltip.left {
left: 20px;
}

View File

@@ -0,0 +1,21 @@
.back-to-top {
position: fixed;
bottom: 45px;
right: 45px;
z-index: 10;
cursor: pointer;
opacity: 0;
transition: opacity 0.3s ease-in-out;
img {
max-width: 60px;
}
@include mq('md', max) {
right: 25px;
}
&.active {
opacity: 1;
}
}

View File

@@ -0,0 +1,43 @@
@use 'sass:math';
$unit-range: (
'px': 1px,
'em': 1em,
'rem': 1rem,
);
@function addUnit($value, $unit) {
@if type-of($unit) != 'string' {
@error 'Value for unit should be a string.';
}
$matched-unit: map-get($unit-range, $unit);
@if $matched-unit {
@return $value * $matched-unit;
} @else {
@error 'Value for unit not a valid unit.';
}
}
@function px2unit($unit, $pixels, $context) {
@if $unit {
@if (unitless($pixels)) {
$pixels: $pixels * 1px;
}
@if (unitless($context)) {
$context: $context * 1px;
}
@return addUnit(math.div($pixels, $context), $unit);
}
}
@function em($pixels, $context) {
@return px2unit('em', $pixels, $context);
}
@function rem($pixels, $context: $font-size-rem) {
@return px2unit('rem', $pixels, $context);
}

Some files were not shown because too many files have changed in this diff Show More