├── src
├── app-info.js
├── themes
│ ├── generated
│ │ ├── variables.base.scss
│ │ ├── variables.additional.scss
│ │ ├── variables.base.dark.scss
│ │ └── variables.additional.dark.scss
│ ├── metadata.base.json
│ ├── metadata.base.dark.json
│ ├── metadata.additional.json
│ └── metadata.additional.dark.json
├── app-navigation.js
├── components
│ ├── theme-switcher.vue
│ ├── app-footer.vue
│ ├── user-panel.vue
│ ├── header-toolbar.vue
│ └── side-nav-menu.vue
├── main.js
├── utils
│ └── media-query.js
├── theme-service.js
├── dx-styles.scss
├── variables.scss
├── layouts
│ ├── single-card.vue
│ ├── side-nav-outer-toolbar.vue
│ └── side-nav-inner-toolbar.vue
├── auth.js
├── App.vue
├── views
│ ├── profile-page.vue
│ ├── reset-password-form.vue
│ ├── change-password-form.vue
│ ├── tasks-page.vue
│ ├── login-form.vue
│ ├── create-account-form.vue
│ └── home-page.vue
└── router.js
├── vue.config.js
├── vue-template.png
├── public
└── favicon.ico
├── SECURITY.md
├── jsconfig.json
├── .gitignore
├── index.html
├── vite.config.js
├── eslint.config.js
├── package.json
├── README.md
├── .github
└── workflows
│ ├── deploy.yml
│ └── codeql-analysis.yml
└── devextreme.json
/src/app-info.js:
--------------------------------------------------------------------------------
1 | export default {
2 | title: "DevExtreme App"
3 | };
4 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | publicPath: "/devextreme-vue-template"
3 | };
4 |
--------------------------------------------------------------------------------
/vue-template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevExpress/devextreme-vue-template/HEAD/vue-template.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevExpress/devextreme-vue-template/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | ## Security
2 |
3 | Please refer to [DevExpress Security Policy](https://github.com/DevExpress/Shared/security/policy)
4 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./src/*"]
5 | }
6 | },
7 | "exclude": ["node_modules", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/src/themes/generated/variables.base.scss:
--------------------------------------------------------------------------------
1 | $base-accent: #0f6cbd;
2 | $base-bg: #ffffff;
3 | $base-border-color: #e0e0e0;
4 | $base-text-color: #242424;
5 | $base-border-radius: 4px;
6 |
--------------------------------------------------------------------------------
/src/themes/generated/variables.additional.scss:
--------------------------------------------------------------------------------
1 | $base-accent: #0f6cbd;
2 | $base-bg: #ffffff;
3 | $base-border-color: #e0e0e0;
4 | $base-text-color: #242424;
5 | $base-border-radius: 4px;
6 |
--------------------------------------------------------------------------------
/src/themes/generated/variables.base.dark.scss:
--------------------------------------------------------------------------------
1 | $base-accent: #479ef5;
2 | $base-bg: #292929;
3 | $base-border-color: #616161;
4 | $base-text-color: #ffffff;
5 | $base-border-radius: 4px;
6 |
--------------------------------------------------------------------------------
/src/themes/generated/variables.additional.dark.scss:
--------------------------------------------------------------------------------
1 | $base-accent: #479ef5;
2 | $base-bg: #292929;
3 | $base-border-color: #616161;
4 | $base-text-color: #ffffff;
5 | $base-border-radius: 4px;
6 |
--------------------------------------------------------------------------------
/src/themes/metadata.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "items": [],
3 | "baseTheme": "fluent.blue.light",
4 | "assetsBasePath": "../../../node_modules/devextreme/dist/css/",
5 | "outputColorScheme": "base",
6 | "base": true
7 | }
8 |
--------------------------------------------------------------------------------
/src/themes/metadata.base.dark.json:
--------------------------------------------------------------------------------
1 | {
2 | "items": [],
3 | "baseTheme": "fluent.blue.dark",
4 | "assetsBasePath": "../../../node_modules/devextreme/dist/css/",
5 | "outputColorScheme": "dark",
6 | "base": true,
7 | "makeSwatch": true
8 | }
9 |
--------------------------------------------------------------------------------
/src/themes/metadata.additional.json:
--------------------------------------------------------------------------------
1 | {
2 | "items": [],
3 | "baseTheme": "fluent.blue.light",
4 | "assetsBasePath": "../../../node_modules/devextreme/dist/css/",
5 | "outputColorScheme": "additional",
6 | "makeSwatch": true,
7 | "base": true,
8 | "widgets": [
9 | "treeview"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/src/themes/metadata.additional.dark.json:
--------------------------------------------------------------------------------
1 | {
2 | "items": [],
3 | "baseTheme": "fluent.blue.dark",
4 | "assetsBasePath": "../../../node_modules/devextreme/dist/css/",
5 | "outputColorScheme": "additional-dark",
6 | "makeSwatch": true,
7 | "base": true,
8 | "widgets": [
9 | "treeview"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | logs
12 | *.log
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | pnpm-debug.log*
17 |
18 | # Editor directories and files
19 | .idea
20 | .vscode
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/src/app-navigation.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | text: "Home",
4 | path: "/home",
5 | icon: "home"
6 | },
7 | {
8 | text: "Examples",
9 | icon: "folder",
10 | items: [
11 | {
12 | text: "Profile",
13 | path: "/profile"
14 | },
15 | {
16 | text: "Tasks",
17 | path: "/tasks"
18 | }
19 | ]
20 | }
21 | ];
22 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | DevExtreme App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from 'node:url'
2 |
3 | import { defineConfig } from 'vite'
4 | import vue from '@vitejs/plugin-vue'
5 | import vueDevTools from 'vite-plugin-vue-devtools'
6 |
7 | // https://vite.dev/config/
8 | export default defineConfig({
9 | plugins: [
10 | vue(),
11 | vueDevTools(),
12 | ],
13 | resolve: {
14 | alias: {
15 | '@': fileURLToPath(new URL('./src', import.meta.url))
16 | },
17 | },
18 | })
19 |
--------------------------------------------------------------------------------
/src/components/theme-switcher.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
20 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import 'devextreme/dist/css/dx.common.css';
2 | import './themes/generated/theme.base.dark.css';
3 | import './themes/generated/theme.base.css';
4 | import './themes/generated/theme.additional.dark.css';
5 | import './themes/generated/theme.additional.css';
6 | import { createApp } from "vue";
7 | import router from "./router";
8 | import themes from "devextreme/ui/themes";
9 |
10 | import App from "./App.vue";
11 | import appInfo from "./app-info";
12 |
13 | themes.initialized(() => {
14 | const app = createApp(App);
15 | app.use(router);
16 | app.config.globalProperties.$appInfo = appInfo;
17 | app.mount('#app');
18 | });
19 |
--------------------------------------------------------------------------------
/src/components/app-footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
25 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig, globalIgnores } from 'eslint/config'
2 | import globals from 'globals'
3 | import js from '@eslint/js'
4 | import pluginVue from 'eslint-plugin-vue'
5 |
6 | export default defineConfig([
7 | {
8 | name: 'app/files-to-lint',
9 | files: ['**/*.{js,mjs,jsx,vue}'],
10 | },
11 |
12 | globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
13 |
14 | {
15 | languageOptions: {
16 | globals: {
17 | ...globals.browser,
18 | },
19 | },
20 | },
21 |
22 | js.configs.recommended,
23 | ...pluginVue.configs['flat/essential'],
24 |
25 | {
26 | name: 'disable-unused-vars-in-vue',
27 | files: ['**/*.vue'],
28 | rules: {
29 | 'no-unused-vars': 'off',
30 | },
31 | },
32 | ])
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "devextreme-vue-template",
3 | "version": "0.1.0",
4 | "private": true,
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview",
10 | "lint": "eslint . --fix",
11 | "build-themes": "devextreme build",
12 | "postinstall": "npm run build-themes"
13 | },
14 | "dependencies": {
15 | "vue": "^3.5.17",
16 | "sass-embedded": "^1.85.1",
17 | "vue-router": "^4.0.1",
18 | "devextreme": "25.1.3",
19 | "devextreme-vue": "25.1.3"
20 | },
21 | "devDependencies": {
22 | "@eslint/js": "^9.29.0",
23 | "@vitejs/plugin-vue": "^6.0.0",
24 | "eslint": "^9.29.0",
25 | "eslint-plugin-vue": "~10.2.0",
26 | "globals": "^16.2.0",
27 | "vite": "^7.0.0",
28 | "vite-plugin-vue-devtools": "^7.7.7",
29 | "devextreme-cli": "1.11.0",
30 | "devextreme-themebuilder": "25.1.3"
31 | }
32 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DevExtreme Vue Template
2 |
3 | The DevExtreme Vue Template is a Vue application with a navigation menu and sample views in a responsive layout (see a [live preview](https://devexpress.github.io/devextreme-vue-template/)). This application is created with [Vite](https://vite.dev/guide/) and uses [DevExtreme Vue components](https://js.devexpress.com/Documentation/Guide/Vue_Components/DevExtreme_Vue_Components/).
4 |
5 | 
6 |
7 | ## Getting Started
8 |
9 | For more information about the DevExtreme Vue Template and how to customize it, refer to the following help topic: [Application Template](https://js.devexpress.com/Documentation/Guide/Vue_Components/Application_Template/).
10 |
11 | ## License
12 |
13 | **DevExtreme Vue Template is released as a MIT-licensed (free and open-source) add-on to DevExtreme.**
14 |
15 | - [DevExtreme License](https://js.devexpress.com/Licensing/)
16 | - [Free trial](http://js.devexpress.com/Buy/)
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | deploy:
8 | runs-on: ubuntu-latest
9 | timeout-minutes: 20
10 |
11 | steps:
12 | - name: Get sources
13 | uses: actions/checkout@v3
14 |
15 | - name: Use Node.js
16 | uses: actions/setup-node@v3
17 | with:
18 | node-version: '20'
19 |
20 | - name: Restore npm cache
21 | uses: actions/cache@v3
22 | with:
23 | path: ./node_modules
24 | key: ${{ runner.os }}-node-modules
25 |
26 | - name: Install dependencies (npm ci)
27 | run: npm ci --no-audit --no-fund
28 |
29 | - name: Install Internal Package
30 | uses: DevExpress/github-actions/install-internal-package@main
31 |
32 | - name: Build
33 | run: |
34 | rm -rf dist
35 | npx vite build --base "/devextreme-vue-template/"
36 |
37 | - name: Deploy
38 | uses: JamesIves/github-pages-deploy-action@ba1486788b0490a235422264426c45848eac35c6
39 | with:
40 | branch: gh-pages
41 | folder: dist
42 | target-folder: .
43 |
--------------------------------------------------------------------------------
/src/utils/media-query.js:
--------------------------------------------------------------------------------
1 | const Breakpoints = {
2 | XSmall: "(max-width: 599.99px)",
3 | Small: "(min-width: 600px) and (max-width: 959.99px)",
4 | Medium: "(min-width: 960px) and (max-width: 1279.99px)",
5 | Large: "(min-width: 1280px)"
6 | };
7 |
8 | let handlers = [];
9 | const xSmallMedia = window.matchMedia(Breakpoints.XSmall);
10 | const smallMedia = window.matchMedia(Breakpoints.Small);
11 | const mediumMedia = window.matchMedia(Breakpoints.Medium);
12 | const largeMedia = window.matchMedia(Breakpoints.Large);
13 |
14 | [xSmallMedia, smallMedia, mediumMedia, largeMedia].forEach(media => {
15 | media.addListener(() => {
16 | handlers.forEach(handler => handler());
17 | });
18 | });
19 |
20 | export const sizes = () => {
21 | return {
22 | "screen-x-small": xSmallMedia.matches,
23 | "screen-small": smallMedia.matches,
24 | "screen-medium": mediumMedia.matches,
25 | "screen-large": largeMedia.matches
26 | };
27 | };
28 |
29 | export const subscribe = handler => handlers.push(handler);
30 |
31 | export const unsubscribe = handler => {
32 | handlers = handlers.filter(item => item !== handler);
33 | };
34 |
--------------------------------------------------------------------------------
/src/theme-service.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue';
2 |
3 | class ThemeService {
4 | themes = ['light', 'dark']
5 | themeClassNamePrefix = 'dx-swatch-';
6 | currentTheme = ref('');
7 | isDark = ref(false);
8 |
9 | constructor() {
10 | if (!document.getElementById('app').className.includes(this.themeClassNamePrefix)) {
11 | this.currentTheme.value = this.themes[0];
12 |
13 | document.getElementById('app').classList.add(this.themeClassNamePrefix + this.currentTheme.value);
14 | }
15 | }
16 |
17 | switchAppTheme() {
18 | const prevTheme = this.currentTheme.value;
19 | const isCurrentThemeDark = prevTheme === 'dark';
20 |
21 | this.currentTheme.value = this.themes[prevTheme === this.themes[0] ? 1 : 0];
22 |
23 | document.getElementById('app').classList.replace(
24 | this.themeClassNamePrefix + prevTheme,
25 | this.themeClassNamePrefix + this.currentTheme.value
26 | );
27 |
28 | const additionalClassNamePrefix = this.themeClassNamePrefix + 'additional';
29 | const additionalClassNamePostfix = isCurrentThemeDark ? '-' + prevTheme : '';
30 | const additionalClassName = `${additionalClassNamePrefix}${additionalClassNamePostfix}`
31 |
32 | document.getElementById('app')
33 | .querySelector(`.${additionalClassName}`)?.classList
34 | .replace(additionalClassName, additionalClassNamePrefix + (isCurrentThemeDark ? '' : '-dark'));
35 |
36 | this.isDark.value = this.currentTheme.value === 'dark';
37 | }
38 | }
39 |
40 | export const themeService = new ThemeService();
41 |
--------------------------------------------------------------------------------
/src/dx-styles.scss:
--------------------------------------------------------------------------------
1 | $side-panel-min-width: 60px;
2 |
3 | .dx-viewport {
4 | .dx-popup-wrapper {
5 | z-index: 1510 !important;
6 | }
7 |
8 | .content {
9 | line-height: 1.5;
10 | flex-grow: 1;
11 | padding: 20px 40px;
12 |
13 | h2 {
14 | font-size: 32px;
15 | margin: 0;
16 | line-height: 40px;
17 | }
18 | }
19 |
20 | .screen-x-small :not(.dx-card).content {
21 | padding: 20px;
22 | }
23 |
24 | .container {
25 | height: 100%;
26 | flex-direction: column;
27 | display: flex;
28 | }
29 |
30 | .layout-body {
31 | flex: 1;
32 | min-height: 0;
33 | }
34 |
35 | .side-nav-outer-toolbar .dx-drawer {
36 | height: calc(100% - 56px)
37 | }
38 |
39 | .content-block {
40 | margin-top: 20px;
41 | }
42 |
43 |
44 | .responsive-paddings {
45 | padding: 20px;
46 | }
47 |
48 | .screen-large .responsive-paddings {
49 | padding: 40px;
50 | }
51 |
52 | .dx-card.wide-card {
53 | border-radius: 0;
54 | margin-left: 0;
55 | margin-right: 0;
56 | border-right: 0;
57 | border-left: 0;
58 | }
59 |
60 | .with-footer > .dx-scrollable-wrapper >
61 | .dx-scrollable-container > .dx-scrollable-content {
62 | height: 100%;
63 |
64 | & > .dx-scrollview-content {
65 | display: flex;
66 | flex-direction: column;
67 | min-height: 100%;
68 | }
69 | }
70 |
71 | #app {
72 | background-color: var(--base-bg-darken-5);
73 | height: 100%;
74 | }
75 | }
76 |
77 | .dx-theme-fluent {
78 | .dx-drawer-wrapper {
79 | .dx-drawer-panel-content,
80 | .dx-overlay-content {
81 | box-shadow: 0 4px 4px 0 var(--shadow-color-first), 0 1px 2px 0 var(--shadow-color-second);
82 | }
83 | }
84 | }
85 |
86 |
--------------------------------------------------------------------------------
/src/variables.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:meta';
2 | @use 'sass:color';
3 | @use 'sass:map';
4 | @use "./themes/generated/variables.base.scss" as variablesBase;
5 | @use "./themes/generated/variables.base.dark.scss" as variablesBaseDark;
6 | @use "./themes/generated/variables.additional.scss" as variablesAdditional;
7 | @use "./themes/generated/variables.additional.dark.scss" as variablesAdditionalDark;
8 |
9 | @mixin theme-variables($theme-name) {
10 | $theme: meta.module-variables($theme-name);
11 | $base-text-color: map.get($theme, 'base-text-color');
12 | $base-bg: map.get($theme, 'base-bg');
13 |
14 | --base-text-color: #{$base-text-color};
15 | --base-bg: #{$base-bg};
16 | --base-bg-darken-5: #{color.adjust($base-bg, $lightness: -5%)};
17 | --base-accent: #{map.get($theme, 'base-accent')};
18 | --base-text-color-alpha-7: #{rgba($base-text-color, color.alpha($base-text-color) * 0.7)};
19 | }
20 |
21 | :root {
22 | body {
23 | @include theme-variables('variablesBase');
24 |
25 | --footer-border-color: rgba(224, 224, 224, 1);
26 | --plus-icon-color: #242424;
27 | --devextreme-logo-color: #596C7D;
28 | --vue-logo-text-color: #35495E;
29 |
30 | --shadow-color-first: rgba(0, 0, 0, 0.06);
31 | --shadow-color-second: rgba(0, 0, 0, 0.12);
32 | }
33 |
34 | .dx-swatch-additional {
35 | @include theme-variables('variablesAdditional');
36 | }
37 |
38 | .dx-swatch-dark {
39 | @include theme-variables('variablesBaseDark');;
40 |
41 | --plus-icon-color: #fff;
42 | --devextreme-logo-color: #fff;
43 | --vue-logo-text-color: #fff;
44 |
45 | --shadow-color-first: rgba(0, 0, 0, 0.12);
46 | --shadow-color-second: rgba(0, 0, 0, 0.24);
47 | --footer-border-color: rgba(97, 97, 97, 1);
48 | }
49 |
50 | .dx-swatch-additional-dark {
51 | @include theme-variables('variablesAdditionalDark');
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/layouts/single-card.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
42 |
43 |
87 |
--------------------------------------------------------------------------------
/src/auth.js:
--------------------------------------------------------------------------------
1 | const defaultUser = {
2 | email: 'sandra@example.com',
3 | avatarUrl: 'https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png'
4 | };
5 |
6 | export default {
7 | _user: defaultUser,
8 | loggedIn() {
9 | return !!this._user;
10 | },
11 |
12 | async logIn(email, password) {
13 | try {
14 | // Send request
15 | console.log(email, password);
16 | this._user = { ...defaultUser, email };
17 |
18 | return {
19 | isOk: true,
20 | data: this._user
21 | };
22 | }
23 | catch {
24 | return {
25 | isOk: false,
26 | message: "Authentication failed"
27 | };
28 | }
29 | },
30 |
31 | async logOut() {
32 | this._user = null;
33 | },
34 |
35 | async getUser() {
36 | try {
37 | // Send request
38 |
39 | return {
40 | isOk: true,
41 | data: this._user
42 | };
43 | }
44 | catch {
45 | return {
46 | isOk: false
47 | };
48 | }
49 | },
50 |
51 | async resetPassword(email) {
52 | try {
53 | // Send request
54 | console.log(email);
55 |
56 | return {
57 | isOk: true
58 | };
59 | }
60 | catch {
61 | return {
62 | isOk: false,
63 | message: "Failed to reset password"
64 | };
65 | }
66 | },
67 |
68 | async changePassword(email, recoveryCode) {
69 | try {
70 | // Send request
71 | console.log(email, recoveryCode);
72 |
73 | return {
74 | isOk: true
75 | };
76 | }
77 | catch {
78 | return {
79 | isOk: false,
80 | message: "Failed to change password"
81 | }
82 | }
83 | },
84 |
85 | async createAccount(email, password) {
86 | try {
87 | // Send request
88 | console.log(email, password);
89 |
90 | return {
91 | isOk: true
92 | };
93 | }
94 | catch {
95 | return {
96 | isOk: false,
97 | message: "Failed to create account"
98 | };
99 | }
100 | }
101 | };
102 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
75 |
76 |
99 |
--------------------------------------------------------------------------------
/src/components/user-panel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
25 |
26 |
27 |
28 |
42 |
95 |
--------------------------------------------------------------------------------
/src/views/profile-page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Profile
4 |
5 |
6 |
9 |
{{ formData.Notes }}
10 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
68 |
69 |
89 |
--------------------------------------------------------------------------------
/devextreme.json:
--------------------------------------------------------------------------------
1 | {
2 | "applicationEngine": "vue",
3 | "vue": {
4 | "version": 3,
5 | "template": "javascript"
6 | },
7 | "build": {
8 | "commands": [
9 | {
10 | "command": "build-theme",
11 | "options": {
12 | "inputFile": "src/themes/metadata.base.json",
13 | "outputFile": "src/themes/generated/theme.base.css"
14 | }
15 | },
16 | {
17 | "command": "build-theme",
18 | "options": {
19 | "inputFile": "src/themes/metadata.base.dark.json",
20 | "outputFile": "src/themes/generated/theme.base.dark.css"
21 | }
22 | },
23 | {
24 | "command": "build-theme",
25 | "options": {
26 | "inputFile": "src/themes/metadata.additional.json",
27 | "outputFile": "src/themes/generated/theme.additional.css"
28 | }
29 | },
30 | {
31 | "command": "build-theme",
32 | "options": {
33 | "inputFile": "src/themes/metadata.additional.dark.json",
34 | "outputFile": "src/themes/generated/theme.additional.dark.css"
35 | }
36 | },
37 | {
38 | "command": "export-theme-vars",
39 | "options": {
40 | "inputFile": "src/themes/metadata.base.json",
41 | "outputFile": "src/themes/generated/variables.base.scss"
42 | }
43 | },
44 | {
45 | "command": "export-theme-vars",
46 | "options": {
47 | "inputFile": "src/themes/metadata.base.dark.json",
48 | "outputFile": "src/themes/generated/variables.base.dark.scss"
49 | }
50 | },
51 | {
52 | "command": "export-theme-vars",
53 | "options": {
54 | "inputFile": "src/themes/metadata.additional.json",
55 | "outputFile": "src/themes/generated/variables.additional.scss"
56 | }
57 | },
58 | {
59 | "command": "export-theme-vars",
60 | "options": {
61 | "inputFile": "src/themes/metadata.additional.dark.json",
62 | "outputFile": "src/themes/generated/variables.additional.dark.scss"
63 | }
64 | }
65 | ]
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ "master" ]
17 | pull_request:
18 | schedule:
19 | - cron: '0 0 * * 6'
20 |
21 | jobs:
22 | analyze:
23 | name: Analyze
24 | runs-on: ubuntu-latest
25 | permissions:
26 | actions: read
27 | contents: read
28 | security-events: write
29 |
30 | strategy:
31 | fail-fast: false
32 | matrix:
33 | language: [ 'javascript' ]
34 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
35 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
36 |
37 | steps:
38 | - name: Checkout repository
39 | uses: actions/checkout@v3
40 |
41 | # Initializes the CodeQL tools for scanning.
42 | - name: Initialize CodeQL
43 | uses: github/codeql-action/init@v2
44 | with:
45 | languages: ${{ matrix.language }}
46 | # If you wish to specify custom queries, you can do so here or in a config file.
47 | # By default, queries listed here will override any specified in a config file.
48 | # Prefix the list here with "+" to use these queries and those in the config file.
49 |
50 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
51 | # queries: security-extended,security-and-quality
52 |
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v2
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
61 |
62 | # If the Autobuild fails above, remove it and uncomment the following three lines.
63 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
64 |
65 | # - run: |
66 | # echo "Run, Build Application using script"
67 | # ./location_of_script_within_repo/buildscript.sh
68 |
69 | - name: Perform CodeQL Analysis
70 | uses: github/codeql-action/analyze@v2
71 | with:
72 | category: "/language:${{matrix.language}}"
73 |
--------------------------------------------------------------------------------
/src/views/reset-password-form.vue:
--------------------------------------------------------------------------------
1 |
2 |
36 |
37 |
38 |
98 |
99 |
113 |
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import auth from "./auth";
2 | import { createRouter, createWebHashHistory } from "vue-router";
3 |
4 | import Home from "./views/home-page.vue";
5 | import Profile from "./views/profile-page.vue";
6 | import Tasks from "./views/tasks-page.vue";
7 | import defaultLayout from "./layouts/side-nav-outer-toolbar.vue";
8 | import simpleLayout from "./layouts/single-card.vue";
9 |
10 | function loadView(view) {
11 | return () => import (/* webpackChunkName: "login" */ `./views/${view}.vue`)
12 | }
13 |
14 | const router = new createRouter({
15 | routes: [
16 | {
17 | path: "/home",
18 | name: "home",
19 | meta: {
20 | requiresAuth: true,
21 | layout: defaultLayout
22 | },
23 | component: Home
24 | },
25 | {
26 | path: "/profile",
27 | name: "profile",
28 | meta: {
29 | requiresAuth: true,
30 | layout: defaultLayout
31 | },
32 | component: Profile
33 | },
34 | {
35 | path: "/tasks",
36 | name: "tasks",
37 | meta: {
38 | requiresAuth: true,
39 | layout: defaultLayout
40 | },
41 | component: Tasks
42 | },
43 | {
44 | path: "/login-form",
45 | name: "login-form",
46 | meta: {
47 | requiresAuth: false,
48 | layout: simpleLayout,
49 | title: "Sign In"
50 | },
51 | component: loadView("login-form")
52 | },
53 | {
54 | path: "/reset-password",
55 | name: "reset-password",
56 | meta: {
57 | requiresAuth: false,
58 | layout: simpleLayout,
59 | title: "Reset Password",
60 | description: "Please enter the email address that you used to register, and we will send you a link to reset your password via Email."
61 | },
62 | component: loadView("reset-password-form")
63 | },
64 | {
65 | path: "/create-account",
66 | name: "create-account",
67 | meta: {
68 | requiresAuth: false,
69 | layout: simpleLayout,
70 | title: "Sign Up"
71 | },
72 | component: loadView("create-account-form"),
73 | },
74 | {
75 | path: "/change-password/:recoveryCode",
76 | name: "change-password",
77 | meta: {
78 | requiresAuth: false,
79 | layout: simpleLayout,
80 | title: "Change Password"
81 | },
82 | component: loadView("change-password-form")
83 | },
84 | {
85 | path: "/",
86 | redirect: "/home"
87 | },
88 | {
89 | path: "/recovery",
90 | redirect: "/home"
91 | },
92 | {
93 | path: "/:pathMatch(.*)*",
94 | redirect: "/home"
95 | }
96 | ],
97 | history: createWebHashHistory()
98 | });
99 |
100 | router.beforeEach((to, from, next) => {
101 |
102 | if (to.name === "login-form" && auth.loggedIn()) {
103 | next({ name: "home" });
104 | }
105 |
106 | if (to.matched.some(record => record.meta.requiresAuth)) {
107 | if (!auth.loggedIn()) {
108 | next({
109 | name: "login-form",
110 | query: { redirect: to.fullPath }
111 | });
112 | } else {
113 | next();
114 | }
115 | } else {
116 | next();
117 | }
118 | });
119 |
120 | export default router;
121 |
--------------------------------------------------------------------------------
/src/views/change-password-form.vue:
--------------------------------------------------------------------------------
1 |
2 |
44 |
45 |
46 |
112 |
113 |
116 |
--------------------------------------------------------------------------------
/src/views/tasks-page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Tasks
4 |
5 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
27 |
32 |
33 |
38 |
43 |
44 |
45 |
51 |
52 |
58 |
59 |
65 |
66 |
72 |
73 |
78 |
79 |
80 |
81 |
82 |
135 |
140 |
--------------------------------------------------------------------------------
/src/components/header-toolbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
46 |
47 |
48 |
112 |
113 |
155 |
--------------------------------------------------------------------------------
/src/layouts/side-nav-outer-toolbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
21 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
125 |
126 |
138 |
--------------------------------------------------------------------------------
/src/views/login-form.vue:
--------------------------------------------------------------------------------
1 |
2 |
56 |
57 |
58 |
123 |
124 |
138 |
--------------------------------------------------------------------------------
/src/views/create-account-form.vue:
--------------------------------------------------------------------------------
1 |
2 |
62 |
63 |
64 |
129 |
130 |
151 |
--------------------------------------------------------------------------------
/src/components/side-nav-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
19 |
20 |
21 |
22 |
120 |
121 |
195 |
--------------------------------------------------------------------------------
/src/layouts/side-nav-inner-toolbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
52 |
53 |
54 |
155 |
156 |
175 |
--------------------------------------------------------------------------------
/src/views/home-page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Home
4 |
5 |
6 |
7 |
49 |
50 |
60 |
61 |
121 |
122 |
123 |
124 | Thanks for using the DevExtreme Vue App Template.
125 |
126 |
This application was built using Vite
127 | and DevExtreme CLI
128 | and includes the following DevExtreme components:
129 |
140 |
141 |
142 | To customize your DevExtreme Vue application further, please refer to the following help topics:
143 |
144 |
145 |
159 |
160 | For technical content related to DevExtreme Vue components, feel free to explore
161 | our online documentation
162 | and technical demos.
163 |
164 |
165 |
166 |
167 |
168 |
169 |
215 |
--------------------------------------------------------------------------------