├── src ├── assets │ ├── styles │ │ ├── tailwind.css │ │ ├── main.scss │ │ ├── vars │ │ │ └── _color.scss │ │ └── layout │ │ │ ├── _init.scss │ │ │ └── _reset.scss │ └── static │ │ └── images │ │ ├── readme │ │ ├── step_03.jpg │ │ ├── step_04.jpg │ │ ├── step_05.jpg │ │ ├── step_07.jpg │ │ ├── top-banner.jpg │ │ ├── deploy-vercel.jpg │ │ ├── deploy-onrender.jpg │ │ ├── tiki-lighthouse.jpg │ │ └── bandwidth-variable.jpg │ │ ├── development │ │ ├── webp │ │ │ ├── minion.webp │ │ │ ├── ninja.webp │ │ │ └── kungfu-panda.webp │ │ ├── png │ │ │ └── kunfu_panda │ │ │ │ ├── 01.png │ │ │ │ ├── 02.png │ │ │ │ ├── 03.png │ │ │ │ ├── 04.png │ │ │ │ └── 05.png │ │ ├── gif │ │ │ ├── kung-fu-panda-bored.gif │ │ │ ├── kung-fu-panda-hey.gif │ │ │ └── kung-fu-panda-pain.gif │ │ └── svg │ │ │ ├── diamond.svg │ │ │ ├── bitcoin.svg │ │ │ ├── chili.svg │ │ │ ├── sycee-gold.svg │ │ │ ├── cannabis.svg │ │ │ ├── onion-green.svg │ │ │ ├── money.svg │ │ │ ├── bug.svg │ │ │ ├── onion-purple.svg │ │ │ └── medicines.svg │ │ ├── icons │ │ └── image-loading-icon.png │ │ └── logo.svg ├── pages │ ├── DetailPage.vue │ ├── NotFoundPage.vue │ ├── HomePage.vue │ ├── CommentPage.vue │ ├── LoginPage.vue │ └── ContentPage.vue ├── components │ ├── ErrorComponent.vue │ ├── comment-page │ │ ├── CommentSection.vue │ │ ├── CommentLoader.vue │ │ └── CommentRow.vue │ ├── RouterLink.vue │ ├── ComponentLoader.vue │ ├── content-page │ │ └── ModuleContentSection.vue │ ├── Header.vue │ ├── ImageItem.vue │ ├── PageLoader.vue │ └── home-page │ │ └── ModuleSection.vue ├── app │ ├── store │ │ ├── UserStore.ts │ │ ├── LocaleStore.ts │ │ ├── APIStore.ts │ │ └── ServerStore.ts │ └── router │ │ ├── composable │ │ └── useCertificateCustomizationInfo │ │ │ ├── types.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ └── utils │ │ └── BeforeEachHandler.ts ├── App.ts ├── App.vue ├── shim-vue.d.ts ├── static.d.ts ├── utils │ ├── CookieHelper.ts │ ├── LazyRoute.ts │ └── StringHelper.ts └── composable │ └── useStringHelper.ts ├── .prettierignore ├── env ├── env.api.mjs ├── env.assets.mjs ├── env.project.mjs ├── env.general.mjs ├── env.store.mjs ├── env-register.mjs └── env.router.mjs ├── config ├── utils │ ├── PortHandler │ │ ├── .env │ │ └── index.js │ ├── ObjectToEnvConverter.js │ ├── StyleLoader.js │ ├── SocketHandler.js │ ├── NetworkGenerator.js │ └── WebpackCustomizeDefinePlugin.js ├── postcss.config.js ├── prettier.config.js ├── commit-packages │ └── package.json ├── webpack.serve.config.js ├── lint-and-format-packages │ └── package.json ├── env │ ├── ENV_AUTO_IMPORT.mjs │ └── env.mjs ├── types │ ├── ImportMeta.d.ts │ └── dts-generator.mjs ├── build-tool-packages │ └── package.json ├── cz.config.js ├── eslint.config.js ├── .git-cz.json ├── package.json ├── .eslintrc-auto-import.json ├── webpack.production.config.js ├── webpack.development.config.js └── templates │ └── index.development.image-loading.html ├── .husky ├── pre-commit ├── commit-msg └── prepare-commit-msg ├── .gitignore ├── .editorconfig ├── .vscode ├── extensions.json └── settings.json ├── index.production.html ├── package.json ├── tailwind.config.js ├── tsconfig.json ├── webpack.config.js └── README.md /src/assets/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss/utilities'; 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore all HTML files: 2 | *.html 3 | confing/**/*.d.ts 4 | -------------------------------------------------------------------------------- /env/env.api.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | prefix: 'api', 3 | data: {}, 4 | } 5 | -------------------------------------------------------------------------------- /config/utils/PortHandler/.env: -------------------------------------------------------------------------------- 1 | PUPPETEER_SSR_PORT=8081 2 | SOCKET_IO_PORT=3030 3 | -------------------------------------------------------------------------------- /env/env.assets.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | prefix: 'assets', 3 | data: {}, 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/styles/main.scss: -------------------------------------------------------------------------------- 1 | @import 'vars/color'; 2 | @import 'layout/reset'; 3 | -------------------------------------------------------------------------------- /src/pages/DetailPage.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /env/env.project.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | prefix: 'project', 3 | data: {}, 4 | } 5 | -------------------------------------------------------------------------------- /src/components/ErrorComponent.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run pre-commit 5 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx commitlint --edit $1 5 | -------------------------------------------------------------------------------- /env/env.general.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | prefix: 'general', 3 | data: { 4 | greeting: 'Vue 3.x', 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/pages/NotFoundPage.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/assets/styles/vars/_color.scss: -------------------------------------------------------------------------------- 1 | $dark-color: #020100; 2 | $yellow-color: #f1d302; 3 | $blue-color: #235789; 4 | $white-color: #fdfffc; 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | package-lock.json 3 | yarn.lock 4 | node_modules 5 | dist 6 | config/env/.env 7 | config/env/env.json 8 | *.DS_Store 9 | -------------------------------------------------------------------------------- /.husky/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | exec < /dev/tty && node_modules/.bin/cz --hook || true 5 | -------------------------------------------------------------------------------- /src/app/store/UserStore.ts: -------------------------------------------------------------------------------- 1 | export type IUserInfo = { 2 | email: string 3 | } 4 | 5 | export const UserInfoState = reactive({ 6 | email: '', 7 | }) 8 | -------------------------------------------------------------------------------- /env/env.store.mjs: -------------------------------------------------------------------------------- 1 | const ENV_STORE = { 2 | prefix: 'store', 3 | data: { 4 | key: { 5 | user: 'user', 6 | }, 7 | }, 8 | } 9 | 10 | export default ENV_STORE 11 | -------------------------------------------------------------------------------- /config/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'postcss-preset-env', 4 | 'autoprefixer', 5 | require('tailwindcss')('./tailwind.config.js'), 6 | ], 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/static/images/readme/step_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/step_03.jpg -------------------------------------------------------------------------------- /src/assets/static/images/readme/step_04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/step_04.jpg -------------------------------------------------------------------------------- /src/assets/static/images/readme/step_05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/step_05.jpg -------------------------------------------------------------------------------- /src/assets/static/images/readme/step_07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/step_07.jpg -------------------------------------------------------------------------------- /src/assets/static/images/readme/top-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/top-banner.jpg -------------------------------------------------------------------------------- /src/assets/static/images/readme/deploy-vercel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/deploy-vercel.jpg -------------------------------------------------------------------------------- /src/assets/static/images/readme/deploy-onrender.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/deploy-onrender.jpg -------------------------------------------------------------------------------- /src/assets/static/images/readme/tiki-lighthouse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/tiki-lighthouse.jpg -------------------------------------------------------------------------------- /src/app/router/composable/useCertificateCustomizationInfo/types.ts: -------------------------------------------------------------------------------- 1 | export interface IUserInfo { 2 | email: string 3 | } 4 | 5 | export interface ICertCustomizationInfo { 6 | user: IUserInfo 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/static/images/development/webp/minion.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/webp/minion.webp -------------------------------------------------------------------------------- /src/assets/static/images/development/webp/ninja.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/webp/ninja.webp -------------------------------------------------------------------------------- /src/assets/static/images/icons/image-loading-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/icons/image-loading-icon.png -------------------------------------------------------------------------------- /src/assets/static/images/readme/bandwidth-variable.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/readme/bandwidth-variable.jpg -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [**] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /src/assets/static/images/development/png/kunfu_panda/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/png/kunfu_panda/01.png -------------------------------------------------------------------------------- /src/assets/static/images/development/png/kunfu_panda/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/png/kunfu_panda/02.png -------------------------------------------------------------------------------- /src/assets/static/images/development/png/kunfu_panda/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/png/kunfu_panda/03.png -------------------------------------------------------------------------------- /src/assets/static/images/development/png/kunfu_panda/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/png/kunfu_panda/04.png -------------------------------------------------------------------------------- /src/assets/static/images/development/png/kunfu_panda/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/png/kunfu_panda/05.png -------------------------------------------------------------------------------- /src/assets/static/images/development/webp/kungfu-panda.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/webp/kungfu-panda.webp -------------------------------------------------------------------------------- /src/assets/static/images/development/gif/kung-fu-panda-bored.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/gif/kung-fu-panda-bored.gif -------------------------------------------------------------------------------- /src/assets/static/images/development/gif/kung-fu-panda-hey.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/gif/kung-fu-panda-hey.gif -------------------------------------------------------------------------------- /src/assets/static/images/development/gif/kung-fu-panda-pain.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anhchangvt1994/webpack-project--template-vue-ts__vue-router/HEAD/src/assets/static/images/development/gif/kung-fu-panda-pain.gif -------------------------------------------------------------------------------- /config/prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSameLine: false, 3 | semi: false, 4 | singleQuote: true, 5 | useTabs: true, 6 | printWidth: 80, 7 | trailingComma: 'es5', 8 | vueIndentScriptAndStyle: true, 9 | } 10 | -------------------------------------------------------------------------------- /src/assets/styles/layout/_init.scss: -------------------------------------------------------------------------------- 1 | // NOTE - Init image background 2 | img.image-item { 3 | background-color: #fdfffc; 4 | 5 | &.--is-error { 6 | background: url('images/icons/image-loading-icon.png') center/contain 7 | no-repeat; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/pages/HomePage.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | -------------------------------------------------------------------------------- /config/utils/ObjectToEnvConverter.js: -------------------------------------------------------------------------------- 1 | module.exports = (obj) => { 2 | if (!obj || typeof obj !== 'object') return 3 | 4 | let tmpENVContent = '' 5 | for (let key in obj) { 6 | tmpENVContent += key + '=' + (!obj[key] ? '' : obj[key] + '\n') 7 | } 8 | 9 | return tmpENVContent 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "vue.volar", 4 | "vue.vscode-typescript-vue-plugin", 5 | "tabnine.tabnine-vscode", 6 | "ionutvmi.path-autocomplete", 7 | "rohit-gohri.format-code-action" 8 | ], 9 | "unwantedRecommendations": ["vscode.typescript-language-features"] 10 | } 11 | -------------------------------------------------------------------------------- /src/app/router/composable/useCertificateCustomizationInfo/index.ts: -------------------------------------------------------------------------------- 1 | import { UserInfoState } from 'app/store/UserStore' 2 | import { ICertCustomizationInfo } from './types' 3 | 4 | export default function useCertificateCustomizationInfo(): ICertCustomizationInfo { 5 | return { 6 | user: UserInfoState, 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /env/env-register.mjs: -------------------------------------------------------------------------------- 1 | import ENV_ROUTER from './env.router.mjs' 2 | import ENV_GENERAL from './env.general.mjs' 3 | import ENV_PROJECT from './env.project.mjs' 4 | import ENV_API from './env.api.mjs' 5 | import ENV_STORE from './env.store.mjs' 6 | 7 | export default [ENV_ROUTER, ENV_GENERAL, ENV_PROJECT, ENV_API, ENV_STORE] 8 | -------------------------------------------------------------------------------- /src/app/store/LocaleStore.ts: -------------------------------------------------------------------------------- 1 | export type ILocaleInfo = { 2 | lang?: string 3 | country?: string 4 | } 5 | export const LocaleState = reactive({}) 6 | export const setLocaleState = (locale: ILocaleInfo) => { 7 | if (!locale) return 8 | 9 | LocaleState.lang = locale.lang 10 | LocaleState.country = locale.country 11 | } 12 | -------------------------------------------------------------------------------- /index.production.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/app/store/APIStore.ts: -------------------------------------------------------------------------------- 1 | import { hashCode } from 'utils/StringHelper' 2 | 3 | const API_STORE_CLONED = JSON.parse(JSON.stringify(API_STORE || {})) 4 | 5 | export const getAPIStore = (key?: string) => { 6 | if (!key) return API_STORE_CLONED 7 | 8 | key = hashCode(key) 9 | 10 | if (!API_STORE_CLONED[key]) return 11 | 12 | return API_STORE_CLONED[key] 13 | } // getAPIStore 14 | -------------------------------------------------------------------------------- /config/commit-packages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commit-packages", 3 | "version": "1.0.0", 4 | "description": "commit-packages", 5 | "main": "", 6 | "scripts": {}, 7 | "author": "", 8 | "license": "ISC", 9 | "dependencies": { 10 | "@commitlint/config-conventional": "^17.6.6", 11 | "commitizen": "^4.3.0", 12 | "commitlint": "^17.6.6", 13 | "cz-git": "^1.6.1", 14 | "husky": "^8.0.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/static/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/pages/CommentPage.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 21 | -------------------------------------------------------------------------------- /src/App.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import router from 'app/router' 3 | import 'assets/styles/tailwind.css' 4 | import RouterLink from 'components/RouterLink.vue' 5 | 6 | const App = (() => { 7 | const initVueApp = () => { 8 | import('App.vue').then(function (data) { 9 | if (!data || !data.default) return 10 | createApp(data.default) 11 | .component('router-link', RouterLink) 12 | .use(router) 13 | .mount('#root') 14 | }) 15 | } // initVueApp() 16 | 17 | return { 18 | init() { 19 | initVueApp() 20 | }, 21 | } 22 | })() 23 | App.init() 24 | -------------------------------------------------------------------------------- /config/webpack.serve.config.js: -------------------------------------------------------------------------------- 1 | const { webpack } = require('webpack') 2 | const WebpackDevServer = require('webpack-dev-server') 3 | const { getPort, findFreePort } = require('./utils/PortHandler') 4 | 5 | ;(async () => { 6 | const port = await findFreePort(process.env.PORT) 7 | console.log() 8 | const serverInitial = new WebpackDevServer( 9 | webpack({ 10 | mode: 'production', 11 | entry: {}, 12 | output: {}, 13 | }), 14 | { 15 | compress: true, 16 | port: port, 17 | static: './dist', 18 | historyApiFallback: true, 19 | } 20 | ) 21 | 22 | serverInitial.start() 23 | })() 24 | -------------------------------------------------------------------------------- /env/env.router.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | prefix: 'router', 3 | data: { 4 | base: { 5 | path: '/', 6 | }, 7 | home: { 8 | name: 'HomePage', 9 | path: '/', 10 | }, 11 | content: { 12 | name: 'ContentPage', 13 | path: '/:title?-:id(\\d+)?', 14 | }, 15 | content_comment: { 16 | name: 'ContentComment', 17 | path: 'comment', 18 | }, 19 | comment: { 20 | name: 'CommentPage', 21 | path: 'comment/detail', 22 | }, 23 | login: { 24 | name: 'LoginPage', 25 | path: '/login', 26 | }, 27 | not_found: { 28 | name: 'NotFoundPage', 29 | path: '/:pathMatch(.*)*', 30 | }, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /src/components/comment-page/CommentSection.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | 20 | 25 | -------------------------------------------------------------------------------- /src/components/RouterLink.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 21 | 22 | 32 | -------------------------------------------------------------------------------- /src/shim-vue.d.ts: -------------------------------------------------------------------------------- 1 | // NOTE - Use for eslint import testing 2 | // declare module '*.vue' { 3 | // import type { DefineComponent } from 'vue' 4 | // const component: DefineComponent< 5 | // Record, 6 | // Record, 7 | // unknown 8 | // > 9 | // export default component 10 | // } 11 | 12 | // router declare 13 | import type { ICertInfo } from 'app/router/utils/BeforeEachHandler' 14 | import 'vue-router' 15 | 16 | declare module 'vue-router' { 17 | interface RouteMeta { 18 | protect?: (certInfo?: ICertInfo) => boolean | string | void 19 | reProtect?: () => void 20 | lang?: string 21 | country?: string 22 | } 23 | } 24 | 25 | declare global { 26 | const API_STORE: { [key: string]: any } = {} 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "nuxt.isNuxtApp": false, 3 | 4 | "path-autocomplete.extensionOnImport": true, 5 | "path-autocomplete.includeExtension": true, 6 | "path-autocomplete.excludedItems": { 7 | "**": { 8 | "when": "**/*.{js,ts,jsx,tsx,vue}", 9 | "isDir": true, 10 | "context": "(import|require).*" 11 | } 12 | }, 13 | "path-autocomplete.pathMappings": { 14 | "/": "${workspace}/src/assets/static", 15 | "assets": "${workspace}/src/assets" 16 | }, 17 | "path-autocomplete.pathSeparators": " \t({[", 18 | "editor.suggest.showModules": false, 19 | "editor.formatOnSave": false, 20 | "editor.defaultFormatter": "esbenp.prettier-vscode", 21 | "editor.codeActionsOnSave": [ 22 | "source.formatDocument", 23 | "source.fixAll.tslint", 24 | "source.fixAll.eslint" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/static.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const value: string 3 | export = value 4 | } 5 | declare module '*.png' { 6 | const value: string 7 | export = value 8 | } 9 | declare module '*.jpg' { 10 | const value: string 11 | export = value 12 | } 13 | declare module '*.jpeg' { 14 | const value: string 15 | export = value 16 | } 17 | declare module '*.webp' { 18 | const value: string 19 | export = value 20 | } 21 | declare module '*.mp3' { 22 | const value: string 23 | export = value 24 | } 25 | declare module '*.mp4' { 26 | const value: string 27 | export = value 28 | } 29 | declare module '*.mov' { 30 | const value: string 31 | export = value 32 | } 33 | declare module '*.mkv' { 34 | const value: string 35 | export = value 36 | } 37 | declare module '*.webm' { 38 | const value: string 39 | export = value 40 | } 41 | -------------------------------------------------------------------------------- /src/components/ComponentLoader.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 35 | -------------------------------------------------------------------------------- /src/utils/CookieHelper.ts: -------------------------------------------------------------------------------- 1 | export function getCookie(cname) { 2 | let name = cname + '=' 3 | let decodedCookie = decodeURIComponent(document.cookie) 4 | let ca = decodedCookie.split(';') 5 | for (let i = 0; i < ca.length; i++) { 6 | let c = ca[i] 7 | while (c.charAt(0) == ' ') { 8 | c = c.substring(1) 9 | } 10 | if (c.indexOf(name) == 0) { 11 | return c.substring(name.length, c.length) 12 | } 13 | } 14 | return '' 15 | } // getCookie 16 | 17 | export function setCookie(cname, cvalue, exdays?) { 18 | const d = new Date() 19 | d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000) 20 | let expires = 'expires=' + d.toUTCString() 21 | document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/;' 22 | } // setCookie 23 | 24 | export function deleteCookie(cname) { 25 | document.cookie = cname + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;' 26 | } // deleteCookie 27 | -------------------------------------------------------------------------------- /config/lint-and-format-packages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lint-and-format-packages", 3 | "version": "1.0.0", 4 | "description": "lint-and-format-packages", 5 | "main": "", 6 | "scripts": {}, 7 | "author": "", 8 | "license": "ISC", 9 | "dependencies": { 10 | "@rushstack/eslint-patch": "^1.3.2", 11 | "@typescript-eslint/eslint-plugin": "^5.61.0", 12 | "@typescript-eslint/parser": "^5.61.0", 13 | "@vue/eslint-config-prettier": "^7.1.0", 14 | "@vue/eslint-config-typescript": "^11.0.3", 15 | "eslint": "^8.44.0", 16 | "eslint-config-prettier": "^8.8.0", 17 | "eslint-import-resolver-custom-alias": "^1.3.2", 18 | "eslint-import-resolver-typescript": "^3.5.5", 19 | "eslint-plugin-import": "^2.27.5", 20 | "eslint-plugin-prettier": "^4.2.1", 21 | "eslint-plugin-vue": "^9.15.1", 22 | "espree": "^9.6.0", 23 | "lint-staged": "^13.2.3", 24 | "prettier": "^2.8.8", 25 | "vue-eslint-parser": "^9.3.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/components/content-page/ModuleContentSection.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | 23 | 43 | -------------------------------------------------------------------------------- /config/utils/StyleLoader.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const loader = require('style-loader') 3 | 4 | module.exports = function () {} 5 | 6 | module.exports.pitch = function (request) { 7 | const result = loader.pitch.call(this, request) 8 | const index = result.indexOf( 9 | 'options.styleTagTransform = styleTagTransformFn;\n' 10 | ) 11 | if (index === -1) return result 12 | const insertIndex = index - 1 13 | 14 | // eslint-disable-next-line prefer-destructuring 15 | const resourcePath = this.resourcePath 16 | const relativePath = path.relative( 17 | path.resolve(__dirname, '..'), 18 | resourcePath 19 | ) 20 | 21 | const insertAttr = ` 22 | if (typeof options.attributes !== 'object') { 23 | options.attributes = {} 24 | } 25 | options.attributes["source-path"] = '${relativePath}' // do anything you want 26 | runtimeOptions.attributes = options.attributes; 27 | ` 28 | 29 | console.log( 30 | result.slice(0, insertIndex) + insertAttr + result.slice(insertIndex) 31 | ) 32 | 33 | return result.slice(0, insertIndex) + insertAttr + result.slice(insertIndex) 34 | } 35 | -------------------------------------------------------------------------------- /config/env/ENV_AUTO_IMPORT.mjs: -------------------------------------------------------------------------------- 1 | export const ROUTER_BASE_PATH="/";export const ROUTER_HOME_NAME="HomePage";export const ROUTER_HOME_PATH="/";export const ROUTER_CONTENT_NAME="ContentPage";export const ROUTER_CONTENT_PATH="/:title?-:id(\\d+)?";export const ROUTER_CONTENT_COMMENT_NAME="ContentComment";export const ROUTER_CONTENT_COMMENT_PATH="comment";export const ROUTER_COMMENT_NAME="CommentPage";export const ROUTER_COMMENT_PATH="comment/detail";export const ROUTER_LOGIN_NAME="LoginPage";export const ROUTER_LOGIN_PATH="/login";export const ROUTER_NOT_FOUND_NAME="NotFoundPage";export const ROUTER_NOT_FOUND_PATH="/:pathMatch(.*)*";export const GENERAL_GREETING="Vue 3.x";export const STORE_KEY_USER="user";export const ENV_VARIABLE_EXPORTER_FOR_AUTO_IMPORT={"@/config/env/ENV_AUTO_IMPORT.mjs":["ROUTER_BASE_PATH","ROUTER_HOME_NAME","ROUTER_HOME_PATH","ROUTER_CONTENT_NAME","ROUTER_CONTENT_PATH","ROUTER_CONTENT_COMMENT_NAME","ROUTER_CONTENT_COMMENT_PATH","ROUTER_COMMENT_NAME","ROUTER_COMMENT_PATH","ROUTER_LOGIN_NAME","ROUTER_LOGIN_PATH","ROUTER_NOT_FOUND_NAME","ROUTER_NOT_FOUND_PATH","GENERAL_GREETING","STORE_KEY_USER"]} -------------------------------------------------------------------------------- /config/types/ImportMeta.d.ts: -------------------------------------------------------------------------------- 1 | interface ImportMeta { 2 | env: Env; 3 | } 4 | 5 | interface Env { 6 | PORT: number; 7 | IO_PORT: number; 8 | LOCAL_ADDRESS: string; 9 | LOCAL_HOST: string; 10 | IPV4_ADDRESS: string; 11 | IPV4_HOST: string; 12 | IO_HOST: string; 13 | ROUTER_BASE_PATH: string; 14 | ROUTER_HOME_NAME: string; 15 | ROUTER_HOME_PATH: string; 16 | ROUTER_CONTENT_NAME: string; 17 | ROUTER_CONTENT_PATH: string; 18 | ROUTER_CONTENT_COMMENT_NAME: string; 19 | ROUTER_CONTENT_COMMENT_PATH: string; 20 | ROUTER_COMMENT_NAME: string; 21 | ROUTER_COMMENT_PATH: string; 22 | ROUTER_LOGIN_NAME: string; 23 | ROUTER_LOGIN_PATH: string; 24 | ROUTER_NOT_FOUND_NAME: string; 25 | ROUTER_NOT_FOUND_PATH: string; 26 | GENERAL_GREETING: string; 27 | STORE_KEY_USER: string; 28 | } 29 | -------------------------------------------------------------------------------- /src/utils/LazyRoute.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | AsyncComponentLoader, 3 | AsyncComponentOptions, 4 | Component, 5 | } from 'vue' 6 | 7 | export interface ILazyRouteCustomConfig { 8 | loadingComponent?: Component 9 | errorComponent?: Component 10 | delay?: number 11 | timeout?: number 12 | suspensible?: boolean 13 | onError?: ( 14 | error: Error, 15 | retry: () => void, 16 | fail: () => void, 17 | attempts: number 18 | ) => any 19 | } 20 | 21 | function LazyRoute() { 22 | function _generateLazyFunc( 23 | input: T extends AsyncComponentLoader ? any : any 24 | ) { 25 | const AsyncComponent = defineAsyncComponent(input) 26 | return defineComponent({ 27 | render() { 28 | return h(AsyncComponent, this.$props) 29 | }, 30 | }) 31 | } 32 | 33 | return { 34 | init(initConfig?: ILazyRouteCustomConfig) { 35 | return (input, newConfig?: ILazyRouteCustomConfig) => { 36 | return _generateLazyFunc({ 37 | ...(initConfig || {}), 38 | ...(newConfig || {}), 39 | loader: input, 40 | }) 41 | } 42 | }, // init 43 | } 44 | } 45 | 46 | export default LazyRoute() 47 | -------------------------------------------------------------------------------- /config/utils/SocketHandler.js: -------------------------------------------------------------------------------- 1 | const http = require('http') 2 | const { Server } = require('socket.io') 3 | const { findFreePort, setPort } = require('./PortHandler') 4 | 5 | const server = http.createServer() 6 | const io = new Server(server) 7 | 8 | let socket = null 9 | const promiseIOConnection = new Promise(async (resolve) => { 10 | const SOCKET_IO_PORT = await findFreePort(3030) 11 | setPort(SOCKET_IO_PORT, 'SOCKET_IO_PORT') 12 | 13 | let callback = null 14 | io.on('connection', (initializeSocket) => { 15 | let sockets = {} 16 | // Save the list of all connections to a variable 17 | sockets[initializeSocket.io] = initializeSocket 18 | socket = initializeSocket 19 | 20 | // When disconnect, delete the socket with the variable 21 | initializeSocket.on('disconnect', () => { 22 | delete sockets[initializeSocket.id] 23 | }) 24 | 25 | if (callback) { 26 | callback({ server, io, socket }) 27 | } else { 28 | resolve({ 29 | server, 30 | io, 31 | socket, 32 | setupCallback: function (fn) { 33 | callback = fn 34 | }, 35 | }) 36 | } 37 | }) 38 | 39 | server.listen(SOCKET_IO_PORT) 40 | }) 41 | 42 | module.exports = promiseIOConnection 43 | -------------------------------------------------------------------------------- /src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 50 | 51 | 57 | -------------------------------------------------------------------------------- /config/utils/NetworkGenerator.js: -------------------------------------------------------------------------------- 1 | //======================================= 2 | // NOTE - generate External IP 3 | //======================================= 4 | const os = require('os') 5 | const OSNetworkInterfaces = os.networkInterfaces() 6 | const Ethernet = 7 | OSNetworkInterfaces.Ethernet || Object.values(OSNetworkInterfaces) 8 | 9 | let IPV4_ADDRESS = null 10 | 11 | if (Ethernet) { 12 | let ethernetFormatted = Ethernet 13 | 14 | if (ethernetFormatted[0].length) { 15 | let tmpEthernetFormatted = [] 16 | 17 | ethernetFormatted.forEach(function (EthernetItem) { 18 | tmpEthernetFormatted = tmpEthernetFormatted.concat(EthernetItem) 19 | }) 20 | 21 | ethernetFormatted = tmpEthernetFormatted 22 | } 23 | 24 | ethernetFormatted.some(function (ethernetItem) { 25 | const ethernetItemInfo = 26 | ethernetItem.family && 27 | /ipv4|4/.test(ethernetItem.family?.toLowerCase?.() ?? ethernetItem.family) 28 | ? ethernetItem 29 | : null 30 | 31 | if ( 32 | ethernetItemInfo && 33 | ethernetItemInfo.address !== '127.0.0.1' && 34 | (ethernetItemInfo.address.includes('192') || 35 | ethernetItemInfo.address.includes('172')) 36 | ) { 37 | IPV4_ADDRESS = ethernetItemInfo.address 38 | return true 39 | } 40 | }) 41 | } 42 | 43 | module.exports = { IPV4_ADDRESS } 44 | -------------------------------------------------------------------------------- /config/types/dts-generator.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | quicktype, 3 | InputData, 4 | jsonInputForTargetLanguage, 5 | } from 'quicktype-core' 6 | import { 7 | ENV_OBJECT_DEFAULT as ImportMeta, 8 | promiseENVWriteFileSync, 9 | } from '../env/env.mjs' 10 | import { writeFile } from 'fs' 11 | import { resolve } from 'path' 12 | 13 | async function quicktypeJSON(targetLanguage, jsonString) { 14 | const jsonInput = jsonInputForTargetLanguage(targetLanguage) 15 | 16 | // We could add multiple samples for the same desired 17 | // type, or many sources for other types. Here we're 18 | // just making one type from one piece of sample JSON. 19 | await jsonInput.addSource({ 20 | name: 'ImportMeta', 21 | samples: [jsonString], 22 | }) 23 | 24 | const inputData = new InputData() 25 | inputData.addInput(jsonInput) 26 | 27 | return await quicktype({ 28 | inputData, 29 | lang: targetLanguage, 30 | rendererOptions: { 'just-types': 'true' }, 31 | }) 32 | } 33 | 34 | async function main() { 35 | const { lines: tdsGroup } = await quicktypeJSON( 36 | 'typescript', 37 | JSON.stringify({ env: ImportMeta }) 38 | ) 39 | 40 | writeFile( 41 | resolve('./config/types', 'ImportMeta.d.ts'), 42 | tdsGroup.join('\n').replace(/export\s/g, ''), 43 | function (err) {} 44 | ) 45 | } 46 | 47 | main() 48 | 49 | export { promiseENVWriteFileSync } 50 | -------------------------------------------------------------------------------- /src/composable/useStringHelper.ts: -------------------------------------------------------------------------------- 1 | import { 2 | generateSentenceCase, 3 | generateTitleCase, 4 | getSlug, 5 | getSlugWithoutDash, 6 | getUnsignedLetters, 7 | } from 'utils/StringHelper' 8 | 9 | export const useSlug = () => { 10 | const state = ref() 11 | const setState = (param: string) => { 12 | state.value = getSlug(param) 13 | } 14 | 15 | return [state, setState] 16 | } // useSlug 17 | 18 | export const useSlugWithoutDash = () => { 19 | const state = ref() 20 | const setState = (param: string) => { 21 | state.value = getSlugWithoutDash(param) 22 | } 23 | 24 | return [state, setState] 25 | } // useSlugWithoutDash 26 | 27 | export const useUnsignedLetters = () => { 28 | const state = ref() 29 | const setState = (param: string) => { 30 | state.value = getUnsignedLetters(param) 31 | } 32 | 33 | return [state, setState] 34 | } // useUnsignedLetters 35 | 36 | export const useTitleCase = () => { 37 | const state = ref() 38 | const setState = (param: string) => { 39 | state.value = generateTitleCase(param) 40 | } 41 | 42 | return [state, setState] 43 | } // useTitleCase 44 | 45 | export const useSentenceCase = () => { 46 | const state = ref() 47 | const setState = (param: string) => { 48 | state.value = generateSentenceCase(param) 49 | } 50 | 51 | return [state, setState] 52 | } // useSentenceCase 53 | -------------------------------------------------------------------------------- /src/assets/static/images/development/svg/diamond.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/components/ImageItem.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 26 | 27 | 64 | -------------------------------------------------------------------------------- /src/pages/LoginPage.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 36 | 37 | 66 | -------------------------------------------------------------------------------- /config/build-tool-packages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "build-tool-packages", 3 | "version": "1.0.0", 4 | "description": "build-tool-packages", 5 | "main": "", 6 | "scripts": {}, 7 | "author": "", 8 | "license": "ISC", 9 | "overrides": { 10 | "isomorphic-fetch@*": "$isomorphic-fetch", 11 | "@babel/types@*": "$@babel/types" 12 | }, 13 | "dependencies": { 14 | "@babel/core": "7.22.15", 15 | "@babel/types": "7.22.15", 16 | "@babel/preset-env": "7.22.15", 17 | "@babel/preset-typescript": "7.22.15", 18 | "autoprefixer": "^10.4.14", 19 | "babel-loader": "^9.1.2", 20 | "babel-preset-typescript-vue3": "^2.0.17", 21 | "clean-webpack-plugin": "^4.0.0", 22 | "copy-webpack-plugin": "^11.0.0", 23 | "core-js": "^3.31.0", 24 | "cross-env": "^7.0.3", 25 | "css-loader": "^6.8.1", 26 | "css-minimizer-webpack-plugin": "^5.0.1", 27 | "cz-git": "^1.6.1", 28 | "esbuild-loader": "^3.0.1", 29 | "html-webpack-plugin": "^5.5.3", 30 | "isomorphic-fetch": "^3.0.0", 31 | "mini-css-extract-plugin": "^2.7.6", 32 | "postcss": "^8.4.24", 33 | "postcss-loader": "^7.3.3", 34 | "postcss-preset-env": "^9.0.0", 35 | "prettier": "^2.8.8", 36 | "purgecss-webpack-plugin": "^5.0.0", 37 | "quicktype-core": "^23.0.49", 38 | "sass": "^1.63.6", 39 | "sass-loader": "^13.3.2", 40 | "socket.io": "^4.7.1", 41 | "sucrase": "^3.33.0", 42 | "tailwindcss": "^3.3.2", 43 | "terser-webpack-plugin": "^5.3.9", 44 | "tsconfig-paths": "^4.2.0", 45 | "unplugin-auto-import": "^0.16.5", 46 | "webpack-dev-server": "^4.15.1", 47 | "vue-loader": "^17.2.2", 48 | "webpack": "^5.88.2", 49 | "webpack-cli": "^5.1.4" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/components/PageLoader.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 63 | -------------------------------------------------------------------------------- /config/cz.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | useEmoji: true, 3 | skipQuestions: ['footerPrefix', 'footer', 'confirmCommit'], 4 | types: [ 5 | { 6 | value: 'chore', 7 | name: "chore: 🤷 If you don't know the type will select", 8 | emoji: ':shrug:', 9 | }, 10 | { 11 | value: 'perf', 12 | name: 'perf: ⚡️ Improve perfomance', 13 | emoji: ':zap:', 14 | }, 15 | { 16 | value: 'release', 17 | name: 'release: 🎯 Create a release commit', 18 | emoji: ':dart:', 19 | }, 20 | { 21 | value: 'docs', 22 | name: 'docs: 🗒 Create / change some document files (ex: *.docs, *.md)', 23 | emoji: ':spiral_notepad:', 24 | }, 25 | { 26 | value: 'test', 27 | name: 'test: 🔬 Add / change a test', 28 | emoji: ':microscope:', 29 | }, 30 | { 31 | value: 'style', 32 | name: 'style: 🎨 Only style for layout', 33 | emoji: ':art:', 34 | }, 35 | { 36 | value: 'fix', 37 | name: 'fix: 🐞 Fix a bug', 38 | emoji: ':lady_beetle:', 39 | }, 40 | { 41 | value: 'feat', 42 | name: 'feat: 🧩 Create a new feature', 43 | emoji: ':jigsaw:', 44 | }, 45 | { 46 | value: 'update', 47 | name: 'update: 🧩 Update but not improve performance', 48 | emoji: ':jigsaw:', 49 | }, 50 | ], 51 | scopes: [ 52 | 'page', 53 | 'comp-page', 54 | 'comp-glob', 55 | 'lib', 56 | 'util', 57 | 'enum', 58 | 'define', 59 | 'server', 60 | 'other', 61 | ], 62 | messages: { 63 | type: 'Select the type of committing:', 64 | customScope: 'Select the scope this component affects:', 65 | subject: 'Title:\n', 66 | body: 'Description:\n', 67 | breaking: 'List any breaking changes:\n', 68 | footer: 'Issues this commit closes, e.g #123:', 69 | confirmCommit: 'Ready to commit ?\n', 70 | }, 71 | } 72 | -------------------------------------------------------------------------------- /src/components/home-page/ModuleSection.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 55 | 56 | 74 | -------------------------------------------------------------------------------- /config/eslint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | ignorePatterns: ['webpack.config.js', 'env/**/*', 'config/**/*', 'dist/**/*'], 4 | env: { 5 | browser: true, 6 | es6: true, 7 | // jest: true, 8 | node: true, 9 | }, 10 | extends: [ 11 | '.eslintrc-auto-import.json', 12 | 'plugin:vue/vue3-recommended', 13 | 'plugin:@typescript-eslint/recommended', 14 | 'eslint:recommended', 15 | '@vue/typescript/recommended', 16 | '@vue/eslint-config-prettier', 17 | '@vue/eslint-config-typescript', 18 | 'plugin:prettier/recommended', 19 | 'plugin:import/recommended', 20 | 'plugin:import/typescript', 21 | 'plugin:import/errors', 22 | 'plugin:import/warnings', 23 | 'prettier', 24 | ], 25 | plugins: ['@typescript-eslint/eslint-plugin'], 26 | parser: 'vue-eslint-parser', 27 | parserOptions: { 28 | parser: { 29 | js: 'espree', 30 | jsx: 'espree', 31 | ts: '@typescript-eslint/parser', 32 | tsx: '@typescript-eslint/parser', 33 | '