commit 1022033690ffd57bc059bea93514dfb9d96fe6ad Author: corrad-software Date: Wed Apr 9 11:16:18 2025 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc55024 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +node_modules +*.log* +.nuxt +.nitro +.cache +.output +.env +dist +sw.* diff --git a/.nuxtignore b/.nuxtignore new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..eed4e74 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# Nuxt 3 Minimal Starter + +Look at the [nuxt 3 documentation](https://v3.nuxtjs.org) to learn more. + +## Setup + +Make sure to install the dependencies: + +```bash +# yarn +yarn install + +# npm +npm install + +# pnpm +pnpm install --shamefully-hoist +``` + +## Development Server + +Start the development server on http://localhost:3000 + +```bash +npm run dev +``` + +## Production + +Build the application for production: + +```bash +npm run build +``` + +Locally preview production build: + +```bash +npm run preview +``` + +Checkout the [deployment documentation](https://v3.nuxtjs.org/guide/deploy/presets) for more information. +# corrad diff --git a/app.config.js b/app.config.js new file mode 100644 index 0000000..6a71328 --- /dev/null +++ b/app.config.js @@ -0,0 +1,9 @@ +// app.config.ts +export default defineAppConfig({ + nuxtIcon: { + size: "24px", // default size applied + aliases: { + nuxt: "logos:nuxt-icon", + }, + }, +}); diff --git a/app.vue b/app.vue new file mode 100644 index 0000000..1b2b723 --- /dev/null +++ b/app.vue @@ -0,0 +1,34 @@ + + + diff --git a/assets/img/avatar/1.svg b/assets/img/avatar/1.svg new file mode 100644 index 0000000..8a1230a --- /dev/null +++ b/assets/img/avatar/1.svg @@ -0,0 +1 @@ +image/svg+xmlAdventurer NeutralLisa Wischofskyhttps://www.instagram.com/lischi_art/ \ No newline at end of file diff --git a/assets/img/avatar/2.svg b/assets/img/avatar/2.svg new file mode 100644 index 0000000..8036ad1 --- /dev/null +++ b/assets/img/avatar/2.svg @@ -0,0 +1 @@ +image/svg+xmlAdventurer NeutralLisa Wischofskyhttps://www.instagram.com/lischi_art/ \ No newline at end of file diff --git a/assets/img/avatar/3.svg b/assets/img/avatar/3.svg new file mode 100644 index 0000000..68b8c20 --- /dev/null +++ b/assets/img/avatar/3.svg @@ -0,0 +1 @@ +image/svg+xmlAdventurer NeutralLisa Wischofskyhttps://www.instagram.com/lischi_art/ \ No newline at end of file diff --git a/assets/img/avatar/4.svg b/assets/img/avatar/4.svg new file mode 100644 index 0000000..f948439 --- /dev/null +++ b/assets/img/avatar/4.svg @@ -0,0 +1 @@ +image/svg+xmlAdventurer NeutralLisa Wischofskyhttps://www.instagram.com/lischi_art/ \ No newline at end of file diff --git a/assets/img/avatar/user.webp b/assets/img/avatar/user.webp new file mode 100644 index 0000000..7c6f810 Binary files /dev/null and b/assets/img/avatar/user.webp differ diff --git a/assets/img/bg.jpg b/assets/img/bg.jpg new file mode 100644 index 0000000..a1d7ccd Binary files /dev/null and b/assets/img/bg.jpg differ diff --git a/assets/img/brand/google-logo.svg b/assets/img/brand/google-logo.svg new file mode 100644 index 0000000..b518c52 --- /dev/null +++ b/assets/img/brand/google-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/default-thumbnail.jpg b/assets/img/default-thumbnail.jpg new file mode 100644 index 0000000..832a898 Binary files /dev/null and b/assets/img/default-thumbnail.jpg differ diff --git a/assets/img/icon/check.svg b/assets/img/icon/check.svg new file mode 100644 index 0000000..1c20989 --- /dev/null +++ b/assets/img/icon/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/icon/chevron-right-dark.svg b/assets/img/icon/chevron-right-dark.svg new file mode 100644 index 0000000..52f6af8 --- /dev/null +++ b/assets/img/icon/chevron-right-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/icon/chevron-right.svg b/assets/img/icon/chevron-right.svg new file mode 100644 index 0000000..8abc75e --- /dev/null +++ b/assets/img/icon/chevron-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/illustration/404-2.svg b/assets/img/illustration/404-2.svg new file mode 100644 index 0000000..23defa0 --- /dev/null +++ b/assets/img/illustration/404-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/illustration/404.svg b/assets/img/illustration/404.svg new file mode 100644 index 0000000..e1c14a2 --- /dev/null +++ b/assets/img/illustration/404.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/illustration/500.svg b/assets/img/illustration/500.svg new file mode 100644 index 0000000..b544f74 --- /dev/null +++ b/assets/img/illustration/500.svg @@ -0,0 +1 @@ +monitor \ No newline at end of file diff --git a/assets/img/illustration/login.svg b/assets/img/illustration/login.svg new file mode 100644 index 0000000..4b04d69 --- /dev/null +++ b/assets/img/illustration/login.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/loader.gif b/assets/img/loader.gif new file mode 100644 index 0000000..870ab01 Binary files /dev/null and b/assets/img/loader.gif differ diff --git a/assets/img/logo/logo-nobg.svg b/assets/img/logo/logo-nobg.svg new file mode 100644 index 0000000..06d57b9 --- /dev/null +++ b/assets/img/logo/logo-nobg.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/logo/logo-word-black-ai.svg b/assets/img/logo/logo-word-black-ai.svg new file mode 100644 index 0000000..6073931 --- /dev/null +++ b/assets/img/logo/logo-word-black-ai.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/logo/logo-word-black.svg b/assets/img/logo/logo-word-black.svg new file mode 100644 index 0000000..eda6811 --- /dev/null +++ b/assets/img/logo/logo-word-black.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/logo/logo-word-white-ai.svg b/assets/img/logo/logo-word-white-ai.svg new file mode 100644 index 0000000..2252264 --- /dev/null +++ b/assets/img/logo/logo-word-white-ai.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/logo/logo-word-white.svg b/assets/img/logo/logo-word-white.svg new file mode 100644 index 0000000..9b622c0 --- /dev/null +++ b/assets/img/logo/logo-word-white.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/logo/logo.svg b/assets/img/logo/logo.svg new file mode 100644 index 0000000..0bae9f2 --- /dev/null +++ b/assets/img/logo/logo.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/logo/word-black-ai.svg b/assets/img/logo/word-black-ai.svg new file mode 100644 index 0000000..7d8700c --- /dev/null +++ b/assets/img/logo/word-black-ai.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/img/logo/word-black.svg b/assets/img/logo/word-black.svg new file mode 100644 index 0000000..612f59d --- /dev/null +++ b/assets/img/logo/word-black.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/img/logo/word-white-ai.svg b/assets/img/logo/word-white-ai.svg new file mode 100644 index 0000000..c208246 --- /dev/null +++ b/assets/img/logo/word-white-ai.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/img/logo/word-white.svg b/assets/img/logo/word-white.svg new file mode 100644 index 0000000..6785941 --- /dev/null +++ b/assets/img/logo/word-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/img/user/default.svg b/assets/img/user/default.svg new file mode 100644 index 0000000..f9f55f0 --- /dev/null +++ b/assets/img/user/default.svg @@ -0,0 +1 @@ +JD \ No newline at end of file diff --git a/assets/img/user/profile-1.jpg b/assets/img/user/profile-1.jpg new file mode 100644 index 0000000..68d5926 Binary files /dev/null and b/assets/img/user/profile-1.jpg differ diff --git a/assets/js/formkit-custom.js b/assets/js/formkit-custom.js new file mode 100644 index 0000000..93cdfb7 --- /dev/null +++ b/assets/js/formkit-custom.js @@ -0,0 +1,16 @@ +import { createInput } from "@formkit/vue"; +import OneTimePassword from "~/components/formkit/OneTimePassword.vue"; +import MaskText from "~/components/formkit/TextMask.vue"; +import FileDropzone from "~/components/formkit/FileDropzone.vue"; + +export default { + otp: createInput(OneTimePassword, { + props: ["digits"], + }), + mask: createInput(MaskText, { + props: ["mask"], + }), + dropzone: createInput(FileDropzone, { + props: ["accept", "multiple", "maxSize", "minSize", "maxFiles", "disabled"], + }), +}; diff --git a/assets/js/formkit-theme.js b/assets/js/formkit-theme.js new file mode 100644 index 0000000..dd57e22 --- /dev/null +++ b/assets/js/formkit-theme.js @@ -0,0 +1,94 @@ +// Create some re-useable definitions because +// many input types are identical in how +// we want to style them. +const textClassification = { + label: "formkit-outer-text", + inner: "formkit-inner-text", + input: "formkit-input-text", + prefix: "formkit-prefix-text", + message: "formkit-message-text", +}; +const boxClassification = { + inner: "formkit-inner-box", + fieldset: "formkit-fieldset-box", + legend: "formkit-legend-box", + wrapper: "formkit-wrapper-box", + help: "formkit-help-box", + input: "formkit-input-box", + label: "formkit-label-box", + message: "formkit-message-box", +}; +const buttonClassification = { + wrapper: "formkit-wrapper-button", + input: "formkit-input-button", +}; +const OtpClassification = { + label: "formkit-label-otp", + inner: "formkit-inner-otp", + digit: "formkit-digit-otp", + message: "formkit-message-otp", +}; + +const colorClassification = { + label: "formkit-label-color", + input: "formkit-input-color", +}; + +const fileClassification = { + label: "formkit-label-file", + inner: "formkit-inner-file", + input: "formkit-input-file", +}; + +const rangeClassification = { + input: "formkit-input-range", +}; + +// export our definitions using our above +// templates and declare one-offs and +// overrides as needed. +export default { + // the global key will apply to all inputs + global: { + label: "formkit-label-global", + outer: "formkit-outer-global", + help: "formkit-help-global", + messages: "formkit-messages-global", + message: "formkit-message-global", + wrapper: "formkit-wrapper-global", + }, + button: buttonClassification, + color: colorClassification, + date: textClassification, + "datetime-local": textClassification, + checkbox: boxClassification, + email: textClassification, + file: fileClassification, + month: textClassification, + number: textClassification, + password: textClassification, + radio: { + ...boxClassification, + input: "formkit-input-radio", + }, + range: rangeClassification, + search: textClassification, + select: { ...textClassification, option: "p-2" }, + submit: buttonClassification, + tel: textClassification, + text: textClassification, + textarea: { + ...textClassification, + input: "formkit-input-textarea", + }, + time: textClassification, + url: textClassification, + week: textClassification, + otp: OtpClassification, + mask: textClassification, + dropzone: { + ...textClassification, + inner: "formkit-inner-dropzone", + dropzone: "formkit-dropzone", + }, +}; diff --git a/assets/style/css/base/theme.css b/assets/style/css/base/theme.css new file mode 100644 index 0000000..67c296b --- /dev/null +++ b/assets/style/css/base/theme.css @@ -0,0 +1,126 @@ +html[data-theme="default"] { + --color-primary: 13, 27, 42; + --color-secondary: 97, 176, 183; + --color-accent: 243, 244, 246; + --color-success: 79, 192, 103; + --color-info: 65, 133, 242; + --color-warning: 246, 141, 32; + --color-danger: 229, 83, 69; + --text-color: 9, 9, 11; + --border-color: 228, 228, 231; + --bg-1: 243, 244, 246; + --bg-2: 255, 255, 255; + --scroll-color: 170, 170, 170; + --scroll-hover-color: 155, 155, 155; + --fk-border-color: 228, 228, 231; + --fk-placeholder-color: 146, 146, 153; + --box-shadow: rgba(36, 35, 71, 0.05) 0px 1px 1px, + rgba(36, 35, 71, 0.05) 0px 0px 1px 1px; + --cp-bg: 255, 255, 255; + --rounded-box: 0.2rem; + --rounded-btn: 0.2rem; + --rounded-badge: 1.9rem; + --animation-btn: 0.25s; + --animation-input: 0.2s; + --btn-text-case: uppercase; + --btn-focus-scale: 0.95; + --padding-btn: 0.5rem; + --border-btn: 1px; + --tab-border: 1px; + --tab-radius: 0.5rem; + --tw-shadow: #e5eaf2; +} + +html[data-theme="dark"] { + --color-primary: 97, 176, 183; + --color-secondary: 13, 27, 42; + --color-accent: 15, 23, 42; + --color-success: 79, 192, 103; + --color-info: 65, 133, 242; + --color-warning: 246, 141, 32; + --color-danger: 229, 83, 69; + --text-color: 209, 213, 219; + --border-color: 30, 41, 59; + --bg-1: 15, 23, 42; + --bg-2: 30, 41, 59; + --scroll-color: 170, 170, 170; + --scroll-hover-color: 155, 155, 155; + --fk-border-color: 71, 85, 105; + --fk-placeholder-color: 71, 85, 105; + --box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --cp-bg: 255, 255, 255; + --rounded-box: 0.5rem; + --rounded-btn: 0.5rem; + --rounded-badge: 1.9rem; + --animation-btn: 0.25s; + --animation-input: 0.2s; + --btn-text-case: uppercase; + --btn-focus-scale: 0.95; + --padding-btn: 0.625rem 1.5rem; + --border-btn: 1px; + --tab-border: 1px; + --tab-radius: 0.5rem; + --tw-shadow: #e5eaf2; +} + +html[data-theme="nier"] { + --color-primary: 99, 95, 84; + --color-secondary: 207, 107, 83; + --color-accent: 243, 88, 106; + --color-success: 79, 192, 103; + --color-info: 65, 133, 242; + --color-warning: 246, 141, 32; + --color-danger: 229, 83, 69; + --text-color: 78, 75, 66; + --border-color: 153, 152, 131; + --bg-1: 205, 200, 176; + --bg-2: 218, 212, 187; + --scroll-color: 99, 95, 84; + --scroll-hover-color: 99, 95, 84; + --fk-border-color: 99, 95, 84; + --fk-placeholder-color: 188, 175, 145; + --box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --cp-bg: 255, 255, 255; + --rounded-box: 0.5rem; + --rounded-btn: 0.5rem; + --rounded-badge: 1.9rem; + --animation-btn: 0.25s; + --animation-input: 0.2s; + --btn-text-case: uppercase; + --btn-focus-scale: 0.95; + --padding-btn: 0.625rem 0.875rem; + --border-btn: 1px; + --tab-border: 1px; + --tab-radius: 0.5rem; + --tw-shadow: #e5eaf2; +} + +html[data-theme="custom1"] { + --color-primary: 9, 76, 90; + --color-secondary: 62, 72, 83; + --color-accent: 0, 103, 236; + --color-success: 11, 152, 76; + --color-info: 208, 89, 41; + --color-warning: 229, 197, 13; + --color-danger: 238, 5, 34; + --text-color: 15, 15, 14; + --border-color: 153, 152, 131; + --bg-1: 214, 215, 206; + --bg-2: 235, 232, 217; + --scroll-color: 9, 76, 90; + --scroll-hover-color: 9, 76, 90; + --box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --cp-bg: 255, 255, 255; + --rounded-box: 0.5rem; + --rounded-btn: 0.5rem; + --rounded-badge: 1.9rem; + --animation-btn: 0.25s; + --animation-input: 0.2s; + --btn-text-case: uppercase; + --btn-focus-scale: 0.95; + --padding-btn: 0.625rem 1.5rem; + --border-btn: 1px; + --tab-border: 1px; + --tab-radius: 0.5rem; + --tw-shadow: #e5eaf2; +} \ No newline at end of file diff --git a/assets/style/css/component/alert.css b/assets/style/css/component/alert.css new file mode 100644 index 0000000..5be607f --- /dev/null +++ b/assets/style/css/component/alert.css @@ -0,0 +1,28 @@ +/* RS Alert Component */ +.alert { + @apply visible flex items-center justify-between py-3 px-3 rounded-lg; +} + +.alert.alert-primary { + @apply bg-primary/20 text-primary; +} + +.alert.alert-secondary { + @apply bg-secondary/20 text-secondary; +} + +.alert.alert-success { + @apply bg-success/20 text-success; +} + +.alert.alert-info { + @apply bg-info/20 text-info; +} + +.alert.alert-warning { + @apply bg-warning/20 text-warning; +} + +.alert.alert-danger { + @apply bg-danger/20 text-danger; +} diff --git a/assets/style/css/component/badge.css b/assets/style/css/component/badge.css new file mode 100644 index 0000000..6f06645 --- /dev/null +++ b/assets/style/css/component/badge.css @@ -0,0 +1,28 @@ +/* RS Badge Component */ +.badge { + @apply inline-flex items-center justify-center px-2 py-1 rounded-full text-xs font-semibold leading-none; +} + +.badge.badge-primary { + @apply bg-primary text-white; +} + +.badge.badge-secondary { + @apply bg-secondary text-white; +} + +.badge.badge-success { + @apply bg-success text-white; +} + +.badge.badge-info { + @apply bg-info text-white; +} + +.badge.badge-warning { + @apply bg-warning text-white; +} + +.badge.badge-danger { + @apply bg-danger text-white; +} diff --git a/assets/style/css/component/button.css b/assets/style/css/component/button.css new file mode 100644 index 0000000..10eecf5 --- /dev/null +++ b/assets/style/css/component/button.css @@ -0,0 +1,154 @@ +/* RS Button */ +.button { + @apply w-fit rounded-lg flex justify-center items-center h-fit; +} + +.button[class*="button-"]:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.button.button-primary { + @apply bg-primary text-white; +} + +.button.button-secondary { + @apply bg-secondary text-white; +} + +.button.button-success { + @apply bg-success text-white; +} + +.button.button-info { + @apply bg-info text-white; +} + +.button.button-warning { + @apply bg-warning text-white; +} + +.button.button-danger { + @apply bg-danger text-white; +} + +.button[class*="outline-"]:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.button.outline-primary { + @apply border border-primary text-primary; +} + +.button.outline-primary:hover { + @apply bg-primary/5; +} + +.button.outline-secondary { + @apply border border-secondary text-secondary; +} + +.button.outline-secondary:hover { + @apply bg-secondary/5; +} + +.button.outline-success { + @apply border border-success text-success; +} + +.button.outline-success:hover { + @apply bg-success/5; +} + +.button.outline-info { + @apply border border-info text-info; +} + +.button.outline-info:hover { + @apply bg-info/5; +} + +.button.outline-warning { + @apply border border-warning text-warning; +} + +.button.outline-warning:hover { + @apply bg-warning/5; +} + +.button.outline-danger { + @apply border border-danger text-danger; +} + +.button.outline-danger:hover { + @apply bg-danger/5; +} + +.button[class*="text-"]:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.button.texts-primary { + @apply text-primary; +} + +.button.texts-primary:hover { + @apply bg-primary/10; +} + +.button.texts-secondary { + @apply text-secondary; +} + +.button.texts-secondary:hover { + @apply bg-secondary/10; +} + +.button.texts-success { + @apply text-success; +} + +.button.texts-success:hover { + @apply bg-success/10; +} + +.button.texts-info { + @apply text-info; +} + +.button.texts-info:hover { + @apply bg-info/10; +} + +.button.texts-warning { + @apply text-warning; +} + +.button.texts-warning:hover { + @apply bg-warning/10; +} + +.button.texts-danger { + @apply text-danger; +} + +.button.texts-danger:hover { + @apply bg-danger/10; +} + +.button-sm { + @apply text-xs; + padding: var(--padding-btn); +} + +.button-md { + @apply text-sm; + padding: var(--padding-btn); +} + +.button-lg { + @apply text-base; + padding: var(--padding-btn); +} diff --git a/assets/style/css/component/card.css b/assets/style/css/component/card.css new file mode 100644 index 0000000..064e3d2 --- /dev/null +++ b/assets/style/css/component/card.css @@ -0,0 +1,19 @@ +/* RS Card Component */ +.card { + @apply mb-6; + background-color: rgb(var(--bg-2)); + border-radius: var(--rounded-box); + box-shadow: var(--box-shadow); +} + +.card .card-header { + @apply text-xl p-5 font-medium; +} + +.card .card-body { + @apply px-5 pb-5; +} + +.card .card-footer { + @apply px-5 pb-5; +} diff --git a/assets/style/css/component/collapse.css b/assets/style/css/component/collapse.css new file mode 100644 index 0000000..2399133 --- /dev/null +++ b/assets/style/css/component/collapse.css @@ -0,0 +1,61 @@ +/* RS Collapse Component */ +.accordion { + @apply w-full mb-4 visible; + background-color: rgb(var(--bg-2)); +} + +.accordion.accordion-border { + @apply border-t border-x rounded-lg; + border-color: rgb(var(--border)); +} + +.accordion .accordion-group { + @apply overflow-hidden duration-300 dark:border-slate-700; + background-color: rgb(var(--bg-2)); +} + +.accordion .accordion-group.accordion-default { + @apply border-b; + border-color: rgb(var(--border)); +} + +.accordion .accordion-group.accordion-border { + @apply border-b last:rounded-b-lg; + border-color: rgb(var(--border)); +} + +.accordion .accordion-group.accordion-card { + @apply my-4; + box-shadow: var(--box-shadow); +} + +.accordion .accordion-group .accordion-header { + @apply text-lg font-medium px-5 pr-10 py-4 cursor-pointer; +} + +.accordion .accordion-group .accordion-body { + @apply px-5 pb-4 pt-2; +} + +.accordion-group .accordion-header { + position: relative; +} + +.accordion-group .accordion-header::after { + content: ""; + position: absolute; + width: 19px; + height: 19px; + top: 50%; + right: 0%; + transform: translate(-100%, -50%) rotate(0deg); + background: url("/assets/img/icon/chevron-right.svg"); + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + transition: 0.25s ease-in-out; +} + +.accordion-group--open .accordion-header::after { + transform: translate(-100%, -50%) rotate(90deg); +} diff --git a/assets/style/css/component/common.css b/assets/style/css/component/common.css new file mode 100644 index 0000000..b80d16a --- /dev/null +++ b/assets/style/css/component/common.css @@ -0,0 +1,42 @@ +body { + color: rgb(var(--text-color)); + background-color: rgb(var(--bg-1)); +} + +.w-header { + @apply z-20 fixed top-0 right-0 px-5 py-3 duration-300 shadow-md; + background-color: rgb(var(--bg-2)); + box-shadow: var(--box-shadow); +} + +.w-header-search { + @apply px-4 z-40 duration-300 shadow-md -top-20 focus-within:top-0 right-0; + background-color: rgb(var(--bg-2)); +} + +.vertical-menu { + @apply text-base h-screen fixed w-64 top-0 z-50 duration-300 border-l-0 shadow-md; + background-color: rgb(var(--bg-2)); + box-shadow: var(--box-shadow); +} + +.icon-btn { + @apply flex + items-center + justify-center + transition-colors + duration-300; + color: rgb(var(--text-color)); +} + +.icon-btn.profile { + @apply border; + border-radius: var(--rounded-box); + border: 1px solid rgb(var(--border-color)); + color: rgb(var(--text-color)); +} + +.icon-btn:hover { + color: rgb(var(--text-color)); + background-color: rgb(var(--bg-1)); +} diff --git a/assets/style/css/component/dropdown.css b/assets/style/css/component/dropdown.css new file mode 100644 index 0000000..fde209d --- /dev/null +++ b/assets/style/css/component/dropdown.css @@ -0,0 +1,53 @@ +/* RS Dropdown Component */ +.dropdown { + @apply relative inline-flex; +} + +.dropdown .dropdown-section { + @apply absolute z-10 shadow-md rounded-lg py-1 whitespace-nowrap; + background-color: rgb(var(--bg-2)); +} + +.dropdown-section.list-bottom-sm { + @apply top-10; +} + +.dropdown-section.list-bottom-md { + @apply top-12; +} + +.dropdown-section.list-bottom-lg { + @apply top-16; +} + +.dropdown-section.list-top-sm { + @apply bottom-10; +} + +.dropdown-section.list-top-md { + @apply bottom-12; +} + +.dropdown-section.list-top-lg { + @apply bottom-16; +} + +.dropdown-section.list-left { + @apply top-0 -left-[10.5rem]; +} + +.dropdown-section.list-right { + @apply top-0 -right-[10.5rem]; +} + +.dropdown-section.list-align-right { + @apply right-0; +} + +.dropdown-section .dropdown-item { + @apply flex items-center cursor-pointer px-4 py-2; +} + +.dropdown-section .dropdown-item:hover { + background-color: rgb(var(--bg-1)); +} diff --git a/assets/style/css/component/modal.css b/assets/style/css/component/modal.css new file mode 100644 index 0000000..4d5f300 --- /dev/null +++ b/assets/style/css/component/modal.css @@ -0,0 +1,50 @@ +/* RS Modal Component */ +.modal { + @apply fixed top-0 left-0 w-full h-full overflow-hidden z-[1000] duration-300; + background: rgba(15, 23, 42, 0.5); +} + +.modal.modal-top { + @apply flex items-start; +} + +.modal.modal-center { + @apply flex items-center; +} + +.modal.modal-end { + @apply flex items-end; +} + +.modal.modal-hide-overlay { + @apply !bg-transparent; +} + +.modal .modal-dialog { + @apply w-full md:w-auto relative z-[9999]; + margin: 1.75rem auto; +} + +.modal .modal-dialog .modal-content { + @apply border-none shadow-lg relative flex flex-col w-full pointer-events-auto bg-clip-padding rounded-md outline-none text-current; + background-color: rgb(var(--bg-2)); +} + +.modal .modal-dialog .modal-content .modal-header { + @apply flex flex-shrink-0 items-center justify-between p-4 border-b rounded-t-md; + border-color: rgb(var(--border-color)); +} + +.modal .modal-dialog .modal-content .modal-body { + @apply relative p-4; +} + +.modal .modal-dialog .modal-content .modal-footer { + @apply flex flex-shrink-0 flex-wrap items-center justify-end px-4 pb-4 rounded-b-md gap-x-3; +} + +@media screen and (max-width: 768px) { + .modal-dialog { + margin: 1.75rem 1rem; + } +} diff --git a/assets/style/css/component/progress.css b/assets/style/css/component/progress.css new file mode 100644 index 0000000..9c1c9b6 --- /dev/null +++ b/assets/style/css/component/progress.css @@ -0,0 +1,80 @@ +/* RS Progress Component */ +.progress-wrapper { + @apply w-full mb-4; +} + +.progress-wrapper .progress-label { + @apply text-sm mb-1; +} + +.progress-wrapper .progress { + @apply flex rounded-full; +} + +.progress-wrapper .progress.progress-sm { + @apply h-3; +} + +.progress-wrapper .progress.progress-md { + @apply h-4; +} + +.progress-wrapper .progress.progress-lg { + @apply h-5; +} + +.progress-wrapper .progress.progress-sm { + @apply h-3; +} + +.progress-wrapper .progress.progress-primary { + @apply bg-primary/20; +} + +.progress-wrapper .progress.progress-secondary { + @apply bg-secondary/20; +} + +.progress-wrapper .progress.progress-success { + @apply bg-success/20; +} + +.progress-wrapper .progress.progress-info { + @apply bg-info/20; +} + +.progress-wrapper .progress.progress-warning { + @apply bg-warning/20; +} + +.progress-wrapper .progress.progress-danger { + @apply bg-danger/20; +} + +.progress-wrapper .progress .progress-bar { + @apply flex items-center justify-center rounded-full text-white; +} + +.progress-wrapper .progress .progress-bar.primary { + @apply bg-primary; +} + +.progress-wrapper .progress .progress-bar.secondary { + @apply bg-secondary; +} + +.progress-wrapper .progress .progress-bar.success { + @apply bg-success; +} + +.progress-wrapper .progress .progress-bar.info { + @apply bg-info; +} + +.progress-wrapper .progress .progress-bar.warning { + @apply bg-warning; +} + +.progress-wrapper .progress .progress-bar.danger { + @apply bg-danger; +} diff --git a/assets/style/css/component/tab.css b/assets/style/css/component/tab.css new file mode 100644 index 0000000..ad3dcd0 --- /dev/null +++ b/assets/style/css/component/tab.css @@ -0,0 +1,323 @@ +/* RS Tab Component */ +.tab { + @apply rounded-md; +} + +.tab.vertical { + @apply flex flex-col md:flex-row; +} + +.tab.tab-card { + @apply shadow-md pt-4; +} + +.tab.card-vertical { + @apply shadow-md; +} + +.tab.card-primary { + @apply bg-primary; +} + +.tab.card-secondary { + @apply bg-secondary; +} + +.tab.card-success { + @apply bg-success; +} + +.tab.card-info { + @apply bg-info; +} + +.tab.card-warning { + @apply bg-warning; +} + +.tab.card-danger { + @apply bg-danger; +} + +.tab .tab-nav { + @apply flex flex-wrap list-none pl-0; +} + +.tab .tab-nav.tab-nav-card { + @apply mx-4 mb-0; +} + +.tab .tab-nav.card-vertical { + @apply py-0 pt-4 md:py-4; +} + +.tab .tab-nav.vertical { + @apply flex-row md:flex-col gap-2; +} + +.tab .tab-nav.vertical-fill { + @apply flex-1; +} + +.tab .tab-nav .tab-item { + @apply cursor-pointer; +} + +.tab .tab-nav .tab-item.fill { + @apply flex-1 w-full; +} + +.tab .tab-nav .tab-item.border-horizontal { + @apply border-0 hover:border hover:border-b-0 rounded-t-md px-6; +} + +.tab .tab-nav .tab-item.border-horizontal-active { + @apply border rounded-t-md border-b-0; +} + +.tab .tab-nav .tab-item.border-vertical { + @apply border-0 hover:border hover:border-r-0 rounded-l-md px-6; +} + +.tab .tab-nav .tab-item.border-vertical-active { + @apply border rounded-t-md rounded-bl-none md:rounded-r-none md:rounded-l-md border-r border-b-0 md:border-b md:border-r-0; +} + +.tab .tab-nav .tab-item.border-hover-primary { + @apply hover:border-primary; +} + +.tab .tab-nav .tab-item.border-hover-secondary { + @apply hover:border-secondary; +} + +.tab .tab-nav .tab-item.border-hover-success { + @apply hover:border-success; +} + +.tab .tab-nav .tab-item.border-hover-info { + @apply hover:border-info; +} + +.tab .tab-nav .tab-item.border-hover-warning { + @apply hover:border-warning; +} + +.tab .tab-nav .tab-item.border-hover-danger { + @apply hover:border-danger; +} + +.tab .tab-nav .tab-item.border-active-primary { + @apply border-primary text-primary; +} + +.tab .tab-nav .tab-item.border-active-secondary { + @apply border-secondary text-secondary; +} + +.tab .tab-nav .tab-item.border-active-success { + @apply border-success text-success; +} + +.tab .tab-nav .tab-item.border-active-info { + @apply border-info text-info; +} + +.tab .tab-nav .tab-item.border-active-warning { + @apply border-warning text-warning; +} + +.tab .tab-nav .tab-item.border-active-danger { + @apply border-danger text-danger; +} + +.tab .tab-nav .tab-item .tab-item-link { + @apply block font-medium text-base leading-tight capitalize border-x-0 border-t-0 py-3; +} + +.tab .tab-nav .tab-item .tab-item-link.default { + @apply hover:border-b-2 mx-2 px-4; +} + +.tab .tab-nav .tab-item .tab-item-link.default-vertical { + @apply hover:border-l-2 mx-2 px-4; +} + +.tab .tab-nav .tab-item .tab-item-link.default-active { + @apply border-b-2; +} + +.tab .tab-nav .tab-item .tab-item-link.default-vertical-active { + @apply border-l-2; +} + +.tab .tab-nav .tab-item .tab-item-link.default-hover-primary { + @apply hover:border-primary hover:text-primary; +} + +.tab .tab-nav .tab-item .tab-item-link.default-hover-secondary { + @apply hover:border-secondary hover:text-secondary; +} + +.tab .tab-nav .tab-item .tab-item-link.default-hover-success { + @apply hover:border-success hover:text-success; +} + +.tab .tab-nav .tab-item .tab-item-link.default-hover-info { + @apply hover:border-info hover:text-info; +} + +.tab .tab-nav .tab-item .tab-item-link.default-hover-warning { + @apply hover:border-warning hover:text-warning; +} + +.tab .tab-nav .tab-item .tab-item-link.default-hover-danger { + @apply hover:border-danger hover:text-danger; +} + +.tab .tab-nav .tab-item .tab-item-link.default-primary { + @apply text-primary border-primary; +} + +.tab .tab-nav .tab-item .tab-item-link.default-secondary { + @apply text-secondary border-secondary; +} + +.tab .tab-nav .tab-item .tab-item-link.default-success { + @apply text-success border-success; +} + +.tab .tab-nav .tab-item .tab-item-link.default-info { + @apply text-info border-info; +} + +.tab .tab-nav .tab-item .tab-item-link.default-warning { + @apply text-warning border-warning; +} + +.tab .tab-nav .tab-item .tab-item-link.default-danger { + @apply text-danger border-danger; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card { + @apply px-5 mx-1 text-white rounded-t-md; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-vertical { + @apply px-5 my-0 text-white rounded-bl-none rounded-t-md md:rounded-tr-none md:rounded-l-md; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-primary { + @apply bg-primary/90; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-secondary { + @apply bg-secondary/90; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-success { + @apply bg-success/90; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-info { + @apply bg-info/90; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-warning { + @apply bg-warning/90; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-danger { + @apply bg-danger/90; +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-primary-active { + @apply text-primary/90; + background-color: rgb(var(--bg-2)); +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-secondary-active { + @apply text-secondary/90; + background-color: rgb(var(--bg-2)); +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-success-active { + @apply text-success/90; + background-color: rgb(var(--bg-2)); +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-info-active { + @apply text-info/90; + background-color: rgb(var(--bg-2)); +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-warning-active { + @apply text-warning/90; + background-color: rgb(var(--bg-2)); +} + +.tab .tab-nav .tab-item .tab-item-link.link-card-danger-active { + @apply text-danger/90; + background-color: rgb(var(--bg-2)); +} + +.tab .tab-nav .tab-item .tab-item-link.link-justify-left { + @apply flex flex-wrap justify-start; +} + +.tab .tab-nav .tab-item .tab-item-link.link-justify-center { + @apply flex flex-wrap justify-center; +} + +.tab .tab-nav .tab-item .tab-item-link.link-justify-right { + @apply flex flex-wrap justify-end; +} + +.tab .tab-content { + @apply rounded-lg; + background-color: rgb(var(--bg-2)); +} + +.tab .tab-content.content-vertical { + @apply flex-grow; +} + +.tab .tab-content.content-vertical-fill { + @apply flex-1; +} + +.tab .tab-content.content-border { + @apply border rounded-b-md; +} + +.tab .tab-content.content-border-vertical { + @apply border rounded-md rounded-l-none; +} + +.tab .tab-content.content-border-primary { + @apply border-primary; +} + +.tab .tab-content.content-border-secondary { + @apply border-secondary; +} + +.tab .tab-content.content-border-success { + @apply border-success; +} + +.tab .tab-content.content-border-info { + @apply border-info; +} + +.tab .tab-content.content-border-warning { + @apply border-warning; +} + +.tab .tab-content.content-border-danger { + @apply border-danger; +} + +.tab .tab-content .tab-pane { + @apply py-4 px-4; +} diff --git a/assets/style/css/component/table.css b/assets/style/css/component/table.css new file mode 100644 index 0000000..3582637 --- /dev/null +++ b/assets/style/css/component/table.css @@ -0,0 +1,32 @@ +/* Table Component */ +.table-wrapper { + @apply w-full border-0 rounded-md border-gray-200 dark:border-slate-700; +} + +.table-header { + @apply m-4 overflow-hidden; + transition: max-height 0.25s cubic-bezier(0, 1, 0, 1); + max-height: 42px; +} + +.table-header.open { + @apply overflow-visible; + transition: max-height 0.5s ease-in-out; + max-height: 9999px; +} + +.table-header-filter { + @apply flex flex-col md:flex-row justify-start md:justify-between items-start md:items-center gap-4; +} + +.table-content { + @apply w-full; +} + +.table-footer { + @apply flex justify-center md:justify-between items-center m-4; +} + +.table-footer-page { + @apply flex justify-center gap-x-2; +} diff --git a/assets/style/css/form/asterisk.css b/assets/style/css/form/asterisk.css new file mode 100644 index 0000000..cb6b209 --- /dev/null +++ b/assets/style/css/form/asterisk.css @@ -0,0 +1,3 @@ +.formkit-asterisk { + color: red; +} \ No newline at end of file diff --git a/assets/style/css/form/box.css b/assets/style/css/form/box.css new file mode 100644 index 0000000..fe988a1 --- /dev/null +++ b/assets/style/css/form/box.css @@ -0,0 +1,59 @@ +.formkit-inner-box { + @apply relative; +} + +.formkit-fieldset-box { + @apply max-w-md border border-[rgb(var(--fk-border-color))] rounded-lg px-4 py-2; +} + +.formkit-legend-box { + @apply font-bold text-sm; +} + +.formkit-wrapper-box { + @apply flex items-center mb-3 cursor-pointer; +} + +.formkit-help-box { + @apply mb-3; +} + +.formkit-input-box { + @apply flex + items-center + hover:cursor-pointer + appearance-none + h-5 w-5 mr-2 + border-2 + border-[rgb(var(--fk-border-color))] + checked:bg-primary + checked:border-transparent + bg-[rgb(var(--bg-2))] + rounded-md + checked:shadow-sm checked:shadow-primary/40 + focus:outline-none focus:ring-0 transition duration-200; +} + +.formkit-input-radio { + @apply flex + items-center + hover:cursor-pointer + appearance-none + h-5 w-5 mr-2 + border-2 + border-[rgb(var(--fk-border-color))] + checked:bg-primary + checked:border-transparent + bg-[rgb(var(--bg-2))] + rounded-full + checked:shadow-sm checked:shadow-primary/40 + focus:outline-none focus:ring-0 transition duration-200; +} + +.formkit-label-box { + @apply text-sm formkit-disabled:text-gray-300; +} + +.formkit-message-box { + @apply formkit-invalid:text-red-500; +} diff --git a/assets/style/css/form/button.css b/assets/style/css/form/button.css new file mode 100644 index 0000000..441bc79 --- /dev/null +++ b/assets/style/css/form/button.css @@ -0,0 +1,7 @@ +.formkit-wrapper-button { + @apply mb-1; +} + +.formkit-input-button { + @apply bg-primary hover:bg-primary/90 text-white text-sm font-normal py-2 px-5 rounded-lg; +} diff --git a/assets/style/css/form/color.css b/assets/style/css/form/color.css new file mode 100644 index 0000000..7834abd --- /dev/null +++ b/assets/style/css/form/color.css @@ -0,0 +1,18 @@ +.formkit-label-color { + @apply block mb-1 font-bold text-sm; +} + +.formkit-input-color { + @apply w-16 h-10 cursor-pointer rounded-lg mb-2 border-none appearance-none bg-transparent; +} + +.formkit-input-color::-webkit-color-swatch { + border-radius: 5px; + border: none; + box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); +} +.formkit-input-color::-moz-color-swatch { + border-radius: 5px; + border: none; + box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); +} diff --git a/assets/style/css/form/dropzone.css b/assets/style/css/form/dropzone.css new file mode 100644 index 0000000..e64f29c --- /dev/null +++ b/assets/style/css/form/dropzone.css @@ -0,0 +1,7 @@ +.formkit-inner-dropzone { + @apply w-full; +} + +.formkit-dropzone { + @apply border-2 border-[rgb(var(--fk-border-color))] border-dashed p-6 active:bg-[rgb(var(--bg-1))]; +} diff --git a/assets/style/css/form/file.css b/assets/style/css/form/file.css new file mode 100644 index 0000000..523e8f7 --- /dev/null +++ b/assets/style/css/form/file.css @@ -0,0 +1,32 @@ +.formkit-label-file { + @apply block mb-1 font-bold text-sm; +} + +.formkit-inner-file { + @apply w-full cursor-pointer; +} + +.formkit-input-file { + @apply w-full cursor-pointer border rounded-lg text-gray-600 text-sm mb-1 file:cursor-pointer file:mr-4 file:py-2 file:px-4 file:rounded-l-lg file:border-0 file:text-sm file:bg-primary file:text-white hover:file:bg-primary/90; + border-color: rgb(var(--fk-border-color)); +} + +.formkit-file-list { + @apply flex flex-col; +} + +.formkit-file-item { + @apply flex items-center py-2 px-4 rounded-lg border border-gray-200 mb-1 mt-1; +} + +.formkit-file-name { + @apply text-[rgb(var(--text-color))] text-sm; +} + +.formkit-file-remove { + @apply ml-auto text-primary text-sm; +} + +.formkit-no-files { + @apply text-[rgb(var(--text-color))] text-sm; +} diff --git a/assets/style/css/form/global.css b/assets/style/css/form/global.css new file mode 100644 index 0000000..73416b1 --- /dev/null +++ b/assets/style/css/form/global.css @@ -0,0 +1,23 @@ +.formkit-label-global { + @apply text-[rgb(var(--text-color))]; +} + +.formkit-outer-global { + @apply mb-4 text-[rgb(var(--text-color))] formkit-disabled:opacity-50; +} + +.formkit-help-global { + @apply text-xs mt-1; +} + +.formkit-messages-global { + @apply list-none p-0 mt-1 mb-0; +} + +.formkit-message-global { + @apply text-red-500 mb-1 text-xs; +} + +.formkit-wrapper-global { + @apply relative; +} diff --git a/assets/style/css/form/otp.css b/assets/style/css/form/otp.css new file mode 100644 index 0000000..31656eb --- /dev/null +++ b/assets/style/css/form/otp.css @@ -0,0 +1,29 @@ +.formkit-label-otp { + @apply block mb-2 font-semibold text-sm formkit-invalid:text-red-500 dark:formkit-invalid:text-danger; +} + +.formkit-inner-otp { + @apply flex + items-center + justify-start + align-middle + rounded-lg mb-1 + overflow-hidden; +} + +.formkit-digit-otp { + @apply w-10 h-10 mr-2 + text-center + rounded-lg + border + border-[rgb(var(--fk-border-color))] + text-sm + bg-[rgb(var(--bg-2))] + placeholder-secondary + focus-within:border-primary + focus:outline-none; +} + +.formkit-message-otp { + @apply formkit-invalid:text-red-500 dark:formkit-invalid:text-danger; +} diff --git a/assets/style/css/form/range.css b/assets/style/css/form/range.css new file mode 100644 index 0000000..6ea37d1 --- /dev/null +++ b/assets/style/css/form/range.css @@ -0,0 +1,3 @@ +.formkit-input-range { + @apply appearance-none w-full h-2 p-0 bg-[rgb(var(--bg-1))] rounded-full focus:outline-none focus:ring-0 focus:shadow-none; +} diff --git a/assets/style/css/form/text.css b/assets/style/css/form/text.css new file mode 100644 index 0000000..16ac948 --- /dev/null +++ b/assets/style/css/form/text.css @@ -0,0 +1,40 @@ +.formkit-outer-text { + @apply block mb-2 font-semibold text-sm formkit-invalid:text-red-500 dark:formkit-invalid:text-danger; +} + +.formkit-inner-text { + @apply flex + items-center + justify-center + align-middle + w-full + border + border-[rgb(var(--fk-border-color))] + formkit-invalid:border-red-500 + rounded-lg + overflow-hidden + focus-within:border-primary + mb-0; +} + +.formkit-input-text { + @apply w-full + h-10 + px-3 + border-none + text-sm + bg-[rgb(var(--bg-2))] + placeholder-[rgb(var(--fk-placeholder-color))] + focus:outline-none + disabled:bg-[rgb(var(--bg-1))] + disabled:border-[rgb(var(--bg-1))] + disabled:placeholder-[rgb(var(--bg-1))]; +} + +.formkit-prefix-text { + @apply ml-2; +} + +.formkit-message-text { + @apply formkit-invalid:text-red-500; +} diff --git a/assets/style/css/form/textarea.css b/assets/style/css/form/textarea.css new file mode 100644 index 0000000..edc4481 --- /dev/null +++ b/assets/style/css/form/textarea.css @@ -0,0 +1,8 @@ +.formkit-input-textarea { + @apply block + w-full + px-3 py-2 + placeholder-[rgb(var(--fk-placeholder-color))] + bg-[rgb(var(--bg-2))] + focus:outline-none; +} diff --git a/assets/style/css/tailwind.css b/assets/style/css/tailwind.css new file mode 100644 index 0000000..7c98191 --- /dev/null +++ b/assets/style/css/tailwind.css @@ -0,0 +1,34 @@ +/* Base Import Tailwind CSS */ +@import "tailwindcss/base"; +@import "./base/theme"; + +/* Components Import Tailwind CSS */ +@import "tailwindcss/components"; +@import "./component/common"; +@import "./component/alert"; +@import "./component/badge"; +@import "./component/button"; +@import "./component/card"; +@import "./component/collapse"; +@import "./component/dropdown"; +@import "./component/modal"; +@import "./component/progress"; +@import "./component/tab"; +@import "./component/table"; + +/* Form Import Tailwind CSS */ +@import "./form/global"; +@import "./form/text"; +@import "./form/textarea"; +@import "./form/box"; +@import "./form/button"; +@import "./form/otp"; +@import "./form/color"; +@import "./form/file"; +@import "./form/range"; +@import "./form/dropzone"; +@import "./form/asterisk"; + +/* Utilities Import Tailwind CSS */ +@import "tailwindcss/utilities"; +@import "./utility/typography"; diff --git a/assets/style/css/utility/typography.css b/assets/style/css/utility/typography.css new file mode 100644 index 0000000..7c43e9d --- /dev/null +++ b/assets/style/css/utility/typography.css @@ -0,0 +1,29 @@ +h1 { + @apply text-4xl + font-bold; +} + +h2 { + @apply text-3xl + font-bold; +} + +h3 { + @apply text-2xl + font-bold; +} + +h4 { + @apply text-xl + font-bold; +} + +h5 { + @apply text-lg + font-bold; +} + +h6 { + @apply text-base + font-bold; +} diff --git a/assets/style/scss/custom/apps/products.scss b/assets/style/scss/custom/apps/products.scss new file mode 100644 index 0000000..6260088 --- /dev/null +++ b/assets/style/scss/custom/apps/products.scss @@ -0,0 +1,49 @@ +$small: 640px; +$medium: 768px; +$large: 1024px; +$xlarge: 1280px; + +.filter-wrapper { + &.filter-wrapper-show { + display: block; + } + + &.filter-wrapper-hide { + display: none; + } +} + +@media screen and (max-width: $medium) { + .filter-wrapper { + transition: right 0.25s ease; + &.filter-wrapper-show { + display: block; + right: 0px; + } + + &.filter-wrapper-hide { + display: block; + right: -260px; + } + } + + .filter-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: -50; + + &.show { + visibility: visible; + opacity: 1; + } + + &.hide { + visibility: hidden; + opacity: 0; + } + } +} diff --git a/assets/style/scss/custom/layout/horizontal.scss b/assets/style/scss/custom/layout/horizontal.scss new file mode 100644 index 0000000..1e44438 --- /dev/null +++ b/assets/style/scss/custom/layout/horizontal.scss @@ -0,0 +1,18 @@ +.h-layout { + .content-page { + padding: 10.5rem 2rem 0 2rem; + height: 100vh; + } + + .w-header, + .w-header-search { + width: 100%; + } + + .w-header-search { + position: fixed; + display: flex; + align-items: center; + height: 64px; + } +} diff --git a/assets/style/scss/custom/layout/vertical.scss b/assets/style/scss/custom/layout/vertical.scss new file mode 100644 index 0000000..50b8c47 --- /dev/null +++ b/assets/style/scss/custom/layout/vertical.scss @@ -0,0 +1,107 @@ +$small: 640px; +$medium: 768px; +$large: 1024px; +$xlarge: 1280px; + +@media screen and (max-width: $medium) { + body:has(.menu-overlay:not(.hide)) { + overflow: hidden; + } + + .menu-overlay { + position: fixed; + top: 0; + height: 120vh; + z-index: 45; + display: block; + visibility: visible; + opacity: 1; + transition: all 0.5s ease; + background-color: rgba(34, 41, 47, 0.5); + left: 0; + right: 0; + } + + .menu-overlay { + &.hide { + visibility: hidden; + opacity: 0; + } + } +} + +// Layout Vertical CSS +.v-layout { + .content-page { + height: 100%; + } + + .w-header-search { + position: fixed; + display: flex; + align-items: center; + height: 64px; + } + + .w-header, + .w-header-search { + width: calc(100% - 256px); + + @media screen and (max-width: $medium) { + width: 100%; + } + } + + .vertical-menu { + left: 0; + } + + .content-page { + margin-left: 256px; + padding: 6rem 2rem 10px 2rem; + + @media screen and (max-width: $medium) { + margin-left: 0px; + padding: 6rem 1.25rem 0 1.25rem; + } + } + + &.menu-hide { + .w-header { + width: calc(100% - 0px); + } + + .vertical-menu { + left: -260px; + } + + .content-page { + margin-left: 0; + } + } + + .menu-content, + .menu-content-child { + max-height: 1000px; + overflow: hidden; + + &.hide { + max-height: 0px; + } + } + + .menu-content-max, + .menu-content-child-max { + max-height: 100vh; + } + + svg.side-menu-arrow { + transition: 0.25s ease-in-out; + } + + .nav-open { + svg.side-menu-arrow { + transform: rotate(90deg); + } + } +} diff --git a/assets/style/scss/custom/library/_dropdown.scss b/assets/style/scss/custom/library/_dropdown.scss new file mode 100644 index 0000000..3458997 --- /dev/null +++ b/assets/style/scss/custom/library/_dropdown.scss @@ -0,0 +1,27 @@ +$small: 640px; +$medium: 768px; +$large: 1024px; +$xlarge: 1280px; + +.s-dropdown { + background-color: white; + padding: 10px 0; + border-radius: 5px; + top: 65px !important; + border: 1px solid rgb(229, 231, 235); + box-shadow: 0px 0px 10px rgba(226, 232, 240, 0.2); + + @media screen and (max-width: $medium) { + left: 0px !important; + width: 100% !important; + margin: 0px 2px !important; + } +} + +.dark { + .s-dropdown { + background-color: #1e293b; + box-shadow: 0px 0px 10px rgba(15, 23, 42, 0.2); + border: 1px solid #182130; + } +} diff --git a/assets/style/scss/custom/library/_floatingvue.scss b/assets/style/scss/custom/library/_floatingvue.scss new file mode 100644 index 0000000..74f6ed4 --- /dev/null +++ b/assets/style/scss/custom/library/_floatingvue.scss @@ -0,0 +1,19 @@ +.v-popper--theme-dropdown .v-popper__inner { + background: rgb(var(--bg-2)) !important; + border: 0px !important; + color: rgb(var(--text-color)) !important; +} + +// Disable arrow +.v-popper__arrow-container { + display: none; +} + +// .v-popper--theme-my-theme .v-popper__inner { +// background: #fff000; +// color: black; +// padding: 24px; +// border-radius: 6px; +// border: 1px solid #ddd; +// box-shadow: 0 6px 30px rgba(0, 0, 0, 0.1); +// } diff --git a/assets/style/scss/custom/library/_formkit.scss b/assets/style/scss/custom/library/_formkit.scss new file mode 100644 index 0000000..3c71f40 --- /dev/null +++ b/assets/style/scss/custom/library/_formkit.scss @@ -0,0 +1,237 @@ +$small: 640px; +$medium: 768px; +$large: 1024px; +$xlarge: 1280px; + +.formkit-form { + .form-wizard { + border-radius: 0.5rem; + } + + &.top-form { + .formkit-actions { + button[type="submit"] { + display: block; + margin-right: 0; + margin-left: auto; + } + } + ul.top-steps { + display: flex; + justify-content: space-evenly; + margin-bottom: 1rem; + gap: 1rem; + + @media screen and (max-width: $medium) { + flex-direction: column; + justify-content: start; + } + + li { + flex-grow: 1; + display: inline-block; + + .progress { + position: relative; + bottom: -8px; + width: 0%; + height: 8px; + border-radius: 10px; + background-color: rgb(var(--color-primary)); + transition: width 0.25s ease-in; + } + + .step--errors { + display: inline-flex; + justify-content: center; + align-items: center; + float: right; + width: 20px; + height: 20px; + border-radius: 50%; + background-color: #f23131; + color: #fff; + font-size: 12px; + } + + .counter { + display: inline-block; + } + + &:after { + content: ""; + display: block; + width: 100%; + height: 8px; + border-radius: 10px; + background-color: rgb(var(--bg-1)); + } + + &[data-step-active="true"] { + color: rgb(var(--color-primary)); + font-weight: 600; + + .progress { + width: 100%; + } + } + + &[data-step-active="false"] { + color: rgb(var(--bg-1)); + .progress { + width: 0%; + } + } + + &[data-step-completed="true"] { + color: rgb(var(--color-primary)); + font-weight: 600; + .progress { + width: 100%; + } + } + } + } + } + + &.left-form { + display: grid; + gap: 1rem; + grid-template-columns: 230px auto; + + @media screen and (max-width: $medium) { + grid-template-columns: repeat(1, minmax(0, 1fr)); + gap: 0rem; + } + + .formkit-actions { + grid-column: span 2 / span 2; + + @media screen and (max-width: $medium) { + grid-column: span 1 / span 1; + } + + button[type="submit"] { + float: right; + } + } + + ul.left-steps { + display: block; + li { + margin-bottom: 1rem; + .progress { + position: relative; + bottom: -8px; + width: 0%; + height: 8px; + border-radius: 10px; + background-color: rgb(var(--color-primary)); + transition: width 0.25s ease-in; + } + + .step--errors { + display: inline-flex; + justify-content: center; + align-items: center; + float: right; + width: 20px; + height: 20px; + border-radius: 50%; + background-color: #f23131; + color: #fff; + font-size: 12px; + } + + .counter { + display: inline-block; + } + + &:after { + content: ""; + display: block; + width: 100%; + height: 8px; + border-radius: 10px; + background-color: rgb(var(--bg-1)); + } + + &[data-step-active="true"] { + color: rgb(var(--color-primary)); + font-weight: 600; + + .progress { + width: 100%; + } + } + + &[data-step-active="false"] { + color: rgb(var(--bg-1)); + .progress { + width: 0%; + } + } + + &[data-step-completed="true"] { + color: rgb(var(--color-primary)); + font-weight: 600; + .progress { + width: 100%; + } + } + } + } + } +} + +// Custom Formkit Input for VSelect +.formkit-vselect { + margin-bottom: 1rem; + + .vs__dropdown-menu { + background: rgb(var(--bg-2)); + } + + .vs__dropdown-menu li { + background: rgb(var(--bg-1)); + color: rgb(var(--text-color)); + } + + .vs__dropdown-toggle { + min-height: 2.5rem; + padding-left: 0.75rem; + padding-right: 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + color: rgb(var(--color-primary)); + + border-width: 1px; + border-radius: 0.5rem; + margin-bottom: 0px; + border-color: rgb(var(--fk-border-color)); + + .vs__selected { + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; + + background-color: rgb(var(--color-primary)); + color: white; + + border: 0; + border-radius: 0.5rem; + + gap: 0.25rem; + margin-right: 0.35rem; + margin-left: 0; + } + } +} + +// Custom Decorator +input[type="checkbox"]:checked.icon-check + .formkit-decorator::before { + content: url('data:image/svg+xml;charset=UTF-8,'); + position: absolute; + top: -1px; +} diff --git a/assets/style/scss/custom/library/_fullcalendar.scss b/assets/style/scss/custom/library/_fullcalendar.scss new file mode 100644 index 0000000..ae7af69 --- /dev/null +++ b/assets/style/scss/custom/library/_fullcalendar.scss @@ -0,0 +1,114 @@ +$small: 640px; +$medium: 768px; +$large: 1024px; +$xlarge: 1280px; + +.fc-theme-standard td, +.fc-theme-standard th { + border-color: rgb(var(--bg-1)) !important; +} + +// Overwrite fullcalendar styles light +.fc { + .fc-scrollgrid { + border: 1px solid rgb(var(--bg-1)) !important; + } + + .fc-toolbar { + @media screen and (max-width: $medium) { + flex-direction: column; + align-items: flex-start !important; + gap: 10px; + } + + .fc-toolbar-chunk { + display: flex; + align-items: center; + } + } + + .fc-button { + padding: 0.75rem 1rem !important; + + &.fc-button-primary { + background-color: transparent !important; + color: rgb(var(--color-primary)); + border-color: rgb(var(--color-primary)) !important; + } + + &.fc-button-active { + background-color: rgb(var(--color-primary)) !important; + } + + &:hover { + background-color: rgb(var(--color-primary)) !important; + color: white !important; + } + + &:focus { + box-shadow: 0 0 0 0.05rem rgba(255, 113, 133, 0.5) !important; + background-color: rgb(var(--color-primary)) !important; + color: white !important; + } + } + + .fc-view-harness { + table { + &.fc-col-header { + td, + th { + border-color: rgb(var(--bg-1)) !important; + } + + .fc-col-header-cell { + padding: 0.5rem; + } + } + } + + .fc-daygrid-day { + &.fc-day-today { + background-color: rgb(var(--bg-1)); + background: rgb(var(--bg-1)); + } + } + + .fc-daygrid-day-top { + color: #6b727f !important; + } + + .fc-more-link { + color: rgb(var(--color-primary)); + } + } + + .fc-daygrid-event-harness { + .fc-daygrid-event { + padding: 0.5rem 1rem; + } + + .fc-h-event { + &.fc-event-start { + border-color: rgb(var(--color-primary)); + background-color: rgb(var(--color-primary)); + } + } + } + .fc-list { + .fc-list-event-dot { + background-color: rgb(var(--color-primary)); + border: 5px solid #f3f4f6; + border-color: rgb(var(--color-primary)) !important; + } + + .fc-list-day-cushion { + background-color: #f3f4f6; + padding: 0.5rem 1rem; + } + } + + .fc-popover-header { + padding: 0.5rem !important; + background: #f3f4f6; + } +} diff --git a/assets/style/scss/custom/library/_nprogress.scss b/assets/style/scss/custom/library/_nprogress.scss new file mode 100644 index 0000000..3a8cd29 --- /dev/null +++ b/assets/style/scss/custom/library/_nprogress.scss @@ -0,0 +1,81 @@ +/* Make clicks pass-through */ +#nprogress { + pointer-events: none; +} + +#nprogress .bar { + background: #fb7185; + + position: fixed; + z-index: 1031; + top: 0; + left: 0; + + width: 100%; + height: 3px; +} + +/* Fancy blur effect */ +#nprogress .peg { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px #fb7185, 0 0 5px #fb7185; + opacity: 1; + + -webkit-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); +} + +/* Remove these to get rid of the spinner */ +#nprogress .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 15px; + right: 15px; +} + +#nprogress .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + + border: solid 2px transparent; + border-top-color: #fb7185; + border-left-color: #fb7185; + border-radius: 50%; + + -webkit-animation: nprogress-spinner 400ms linear infinite; + animation: nprogress-spinner 400ms linear infinite; +} + +.nprogress-custom-parent { + overflow: hidden; + position: relative; +} + +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { + position: absolute; +} + +@-webkit-keyframes nprogress-spinner { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + } +} +@keyframes nprogress-spinner { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/assets/style/scss/custom/library/_swiper.scss b/assets/style/scss/custom/library/_swiper.scss new file mode 100644 index 0000000..2c94c55 --- /dev/null +++ b/assets/style/scss/custom/library/_swiper.scss @@ -0,0 +1,18 @@ +.swiper-button-next, +.swiper-button-prev { + color: #4B5563 !important; + padding: 1.5rem; +} + +.swiper-button-next:after, +.swiper-button-prev:after { + font-size: 1.5rem !important; +} + +.swiper-pagination-bullet { + background-color: #8b98a9 !important; +} + +.swiper-pagination-bullet-active { + background: #4B5563 !important; +} diff --git a/assets/style/scss/custom/library/_vuecountryflag.scss b/assets/style/scss/custom/library/_vuecountryflag.scss new file mode 100644 index 0000000..e396551 --- /dev/null +++ b/assets/style/scss/custom/library/_vuecountryflag.scss @@ -0,0 +1,7 @@ +.flag.normal-flag { + margin: 0em -1em -0em -1em !important; + transform: scale(0.38) !important; + -ms-transform: scale(0.38) !important; + -webkit-transform: scale(0.38) !important; + -moz-transform: scale(0.38) !important; +} diff --git a/assets/style/scss/custom/library/_vuetoastification.scss b/assets/style/scss/custom/library/_vuetoastification.scss new file mode 100644 index 0000000..8a40068 --- /dev/null +++ b/assets/style/scss/custom/library/_vuetoastification.scss @@ -0,0 +1,3 @@ +.Vue-Toastification__toast { + padding: 18px 21px; +} diff --git a/assets/style/scss/custom/scrollbar/scrollbar.scss b/assets/style/scss/custom/scrollbar/scrollbar.scss new file mode 100644 index 0000000..664be81 --- /dev/null +++ b/assets/style/scss/custom/scrollbar/scrollbar.scss @@ -0,0 +1,21 @@ +/* width */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +/* Track */ +::-webkit-scrollbar-track { + background-color: transparent; +} + +/* Handle */ +::-webkit-scrollbar-thumb { + background-color: rgb(var(--scroll-color)); + border-radius: 6px; +} + +/* Handle on hover */ +::-webkit-scrollbar-thumb:hover { + background: rgb(var(--scroll-hover-color)); +} diff --git a/assets/style/scss/custom/transition/fade-up.scss b/assets/style/scss/custom/transition/fade-up.scss new file mode 100644 index 0000000..89342c2 --- /dev/null +++ b/assets/style/scss/custom/transition/fade-up.scss @@ -0,0 +1,12 @@ +// Animation for transition fade +.fade-up-enter-active, +.fade-up-leave-active { + transition: transform 0.4s cubic-bezier(0.17, 0.67, 0.84, 0.79), + opacity 0.3s linear; +} + +.fade-up-enter-from, +.fade-up-leave-to { + opacity: 0; + transform: translateY(-10%); +} diff --git a/assets/style/scss/custom/transition/fade.scss b/assets/style/scss/custom/transition/fade.scss new file mode 100644 index 0000000..0f3ba9b --- /dev/null +++ b/assets/style/scss/custom/transition/fade.scss @@ -0,0 +1,10 @@ +// Animation for transition fade +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.3s ease; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} diff --git a/assets/style/scss/custom/transition/page.scss b/assets/style/scss/custom/transition/page.scss new file mode 100644 index 0000000..904190a --- /dev/null +++ b/assets/style/scss/custom/transition/page.scss @@ -0,0 +1,11 @@ +// Animation for transition fade +.page-enter-active, +.page-leave-active { + transition: transform 0.3s ease, opacity 0.4s ease; +} + +.page-enter-from, +.page-leave-to { + transform: scale(1.02); + opacity: 0; +} diff --git a/assets/style/scss/custom/transition/slide-fade.scss b/assets/style/scss/custom/transition/slide-fade.scss new file mode 100644 index 0000000..70b6742 --- /dev/null +++ b/assets/style/scss/custom/transition/slide-fade.scss @@ -0,0 +1,17 @@ +/* + Enter and leave animations can use different + durations and timing functions. +*/ +.slide-fade-enter-active { + transition: all 0.3s ease-out; +} + +.slide-fade-leave-active { + transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1); +} + +.slide-fade-enter-from, +.slide-fade-leave-to { + transform: translateX(20px); + opacity: 0; +} diff --git a/assets/style/scss/custom/transition/slide.scss b/assets/style/scss/custom/transition/slide.scss new file mode 100644 index 0000000..6b6bca5 --- /dev/null +++ b/assets/style/scss/custom/transition/slide.scss @@ -0,0 +1,10 @@ +.slide-enter-active, +.slide-leave-active { + transition: translateY, opacity 0.2s ease; +} + +.slide-enter-from, +.slide-leave-to { + transform: translateY(0px); + opacity: 0; +} diff --git a/assets/style/scss/main.scss b/assets/style/scss/main.scss new file mode 100644 index 0000000..9175286 --- /dev/null +++ b/assets/style/scss/main.scss @@ -0,0 +1,54 @@ +/*================================================================================ + Notes: This file is the main entry point for the SCSS stylesheet. + ================================================================================*/ + +@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap"); +html, +body { + height: 100%; +} + +#__nuxt { + font-family: "Space Grotesk", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-weight: 400; + font-size: 14px; +} + +// svg.icon{ +// width: 1.3rem; +// height: 1.3rem; +// vertical-align: middle; +// fill: currentColor; +// overflow: hidden; +// } + +code { + color: rgb(233, 74, 74); + background-color: rgba(146, 146, 146, 0.1); +} + +// Custom Layout SCSS +@import "./custom/layout/vertical"; +@import "./custom/layout/horizontal"; + +// Transition SCSS +@import "./custom/transition/page"; +@import "./custom/transition/fade"; +@import "./custom/transition/fade-up"; +@import "./custom/transition/slide"; +@import "./custom/transition/slide-fade"; + +// Scrollbar SCSS +@import "./custom/scrollbar/scrollbar"; + +// Custom SCSS library +@import "./custom/library/dropdown"; +@import "./custom/library/nprogress"; +@import "./custom/library/formkit"; +@import "./custom/library/vuetoastification"; +@import "./custom/library/swiper"; +@import "./custom/library/fullcalendar"; +@import "./custom/library/floatingvue"; +@import "./custom/library/vuecountryflag"; diff --git a/components/Breadcrumb.vue b/components/Breadcrumb.vue new file mode 100644 index 0000000..5ec033f --- /dev/null +++ b/components/Breadcrumb.vue @@ -0,0 +1,88 @@ + + + diff --git a/components/CodeEditor.vue b/components/CodeEditor.vue new file mode 100644 index 0000000..706c759 --- /dev/null +++ b/components/CodeEditor.vue @@ -0,0 +1,79 @@ + + + + + \ No newline at end of file diff --git a/components/Loading.vue b/components/Loading.vue new file mode 100644 index 0000000..7bf4e8a --- /dev/null +++ b/components/Loading.vue @@ -0,0 +1,54 @@ + + + diff --git a/components/RSCalendar.vue b/components/RSCalendar.vue new file mode 100644 index 0000000..3bf6d40 --- /dev/null +++ b/components/RSCalendar.vue @@ -0,0 +1,243 @@ + + + diff --git a/components/RsAlert.vue b/components/RsAlert.vue new file mode 100644 index 0000000..84bab74 --- /dev/null +++ b/components/RsAlert.vue @@ -0,0 +1,60 @@ + + + diff --git a/components/RsApiTester.vue b/components/RsApiTester.vue new file mode 100644 index 0000000..5f72e72 --- /dev/null +++ b/components/RsApiTester.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/components/RsBadge.vue b/components/RsBadge.vue new file mode 100644 index 0000000..029bca0 --- /dev/null +++ b/components/RsBadge.vue @@ -0,0 +1,33 @@ + + + diff --git a/components/RsButton.vue b/components/RsButton.vue new file mode 100644 index 0000000..19beb81 --- /dev/null +++ b/components/RsButton.vue @@ -0,0 +1,58 @@ + + + diff --git a/components/RsCard.vue b/components/RsCard.vue new file mode 100644 index 0000000..d811bbe --- /dev/null +++ b/components/RsCard.vue @@ -0,0 +1,16 @@ + + + diff --git a/components/RsCodeMirror.vue b/components/RsCodeMirror.vue new file mode 100644 index 0000000..1c5962a --- /dev/null +++ b/components/RsCodeMirror.vue @@ -0,0 +1,323 @@ + + + + + diff --git a/components/RsCollapse.vue b/components/RsCollapse.vue new file mode 100644 index 0000000..dd60650 --- /dev/null +++ b/components/RsCollapse.vue @@ -0,0 +1,24 @@ + + + diff --git a/components/RsCollapseItem.vue b/components/RsCollapseItem.vue new file mode 100644 index 0000000..54d24ca --- /dev/null +++ b/components/RsCollapseItem.vue @@ -0,0 +1,94 @@ + + + diff --git a/components/RsDropdown.vue b/components/RsDropdown.vue new file mode 100644 index 0000000..a6d223d --- /dev/null +++ b/components/RsDropdown.vue @@ -0,0 +1,222 @@ + + + diff --git a/components/RsDropdownItem.vue b/components/RsDropdownItem.vue new file mode 100644 index 0000000..6d715ee --- /dev/null +++ b/components/RsDropdownItem.vue @@ -0,0 +1,21 @@ + + + diff --git a/components/RsFieldset.vue b/components/RsFieldset.vue new file mode 100644 index 0000000..dba5bd9 --- /dev/null +++ b/components/RsFieldset.vue @@ -0,0 +1,45 @@ + + + diff --git a/components/RsModal.vue b/components/RsModal.vue new file mode 100644 index 0000000..c3d8471 --- /dev/null +++ b/components/RsModal.vue @@ -0,0 +1,149 @@ + + + diff --git a/components/RsProgressBar.vue b/components/RsProgressBar.vue new file mode 100644 index 0000000..3d7053a --- /dev/null +++ b/components/RsProgressBar.vue @@ -0,0 +1,63 @@ + + + diff --git a/components/RsTab.vue b/components/RsTab.vue new file mode 100644 index 0000000..cf9fc3b --- /dev/null +++ b/components/RsTab.vue @@ -0,0 +1,230 @@ + + + diff --git a/components/RsTabItem.vue b/components/RsTabItem.vue new file mode 100644 index 0000000..a0eec26 --- /dev/null +++ b/components/RsTabItem.vue @@ -0,0 +1,20 @@ + + + diff --git a/components/RsTable.vue b/components/RsTable.vue new file mode 100644 index 0000000..1635ab5 --- /dev/null +++ b/components/RsTable.vue @@ -0,0 +1,845 @@ + + + diff --git a/components/RsWizard.vue b/components/RsWizard.vue new file mode 100644 index 0000000..86ffb1b --- /dev/null +++ b/components/RsWizard.vue @@ -0,0 +1,228 @@ + + + diff --git a/components/draggable/nested.vue b/components/draggable/nested.vue new file mode 100644 index 0000000..1d0239e --- /dev/null +++ b/components/draggable/nested.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/components/draggable/sideMenuNested.vue b/components/draggable/sideMenuNested.vue new file mode 100644 index 0000000..0596c5b --- /dev/null +++ b/components/draggable/sideMenuNested.vue @@ -0,0 +1,533 @@ + + + diff --git a/components/formkit/DateTimePicker.vue b/components/formkit/DateTimePicker.vue new file mode 100644 index 0000000..6737d41 --- /dev/null +++ b/components/formkit/DateTimePicker.vue @@ -0,0 +1,13 @@ + + + diff --git a/components/formkit/FileDropzone.vue b/components/formkit/FileDropzone.vue new file mode 100644 index 0000000..57743b7 --- /dev/null +++ b/components/formkit/FileDropzone.vue @@ -0,0 +1,139 @@ + + + diff --git a/components/formkit/OneTimePassword.vue b/components/formkit/OneTimePassword.vue new file mode 100644 index 0000000..f141fde --- /dev/null +++ b/components/formkit/OneTimePassword.vue @@ -0,0 +1,83 @@ + + + diff --git a/components/formkit/TextMask.vue b/components/formkit/TextMask.vue new file mode 100644 index 0000000..55a1be8 --- /dev/null +++ b/components/formkit/TextMask.vue @@ -0,0 +1,23 @@ + + + diff --git a/components/layouts/Breadcrumb.vue b/components/layouts/Breadcrumb.vue new file mode 100644 index 0000000..855e644 --- /dev/null +++ b/components/layouts/Breadcrumb.vue @@ -0,0 +1,59 @@ + + + diff --git a/components/layouts/BreadcrumbV2.vue b/components/layouts/BreadcrumbV2.vue new file mode 100644 index 0000000..268a040 --- /dev/null +++ b/components/layouts/BreadcrumbV2.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/layouts/FormHeader.vue b/components/layouts/FormHeader.vue new file mode 100644 index 0000000..9f11cbf --- /dev/null +++ b/components/layouts/FormHeader.vue @@ -0,0 +1,20 @@ + + + diff --git a/components/layouts/Header.vue b/components/layouts/Header.vue new file mode 100644 index 0000000..2ae7b32 --- /dev/null +++ b/components/layouts/Header.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/components/layouts/configmenu/index.vue b/components/layouts/configmenu/index.vue new file mode 100644 index 0000000..acc60ec --- /dev/null +++ b/components/layouts/configmenu/index.vue @@ -0,0 +1,241 @@ + + + diff --git a/components/layouts/horizontal/index.vue b/components/layouts/horizontal/index.vue new file mode 100644 index 0000000..4322d41 --- /dev/null +++ b/components/layouts/horizontal/index.vue @@ -0,0 +1,7 @@ + + + + diff --git a/components/layouts/index.vue b/components/layouts/index.vue new file mode 100644 index 0000000..c6e9aa9 --- /dev/null +++ b/components/layouts/index.vue @@ -0,0 +1,25 @@ + + + diff --git a/components/layouts/sidemenu/Item.vue b/components/layouts/sidemenu/Item.vue new file mode 100644 index 0000000..55d039f --- /dev/null +++ b/components/layouts/sidemenu/Item.vue @@ -0,0 +1,173 @@ + + + diff --git a/components/layouts/sidemenu/ItemChild.vue b/components/layouts/sidemenu/ItemChild.vue new file mode 100644 index 0000000..c010246 --- /dev/null +++ b/components/layouts/sidemenu/ItemChild.vue @@ -0,0 +1,152 @@ + + + diff --git a/components/layouts/sidemenu/index.vue b/components/layouts/sidemenu/index.vue new file mode 100644 index 0000000..460099d --- /dev/null +++ b/components/layouts/sidemenu/index.vue @@ -0,0 +1,52 @@ + + + diff --git a/components/layouts/vertical/index.vue b/components/layouts/vertical/index.vue new file mode 100644 index 0000000..8983836 --- /dev/null +++ b/components/layouts/vertical/index.vue @@ -0,0 +1,41 @@ + + + diff --git a/composables/codemirrorThemes.js b/composables/codemirrorThemes.js new file mode 100644 index 0000000..3cb5ef5 --- /dev/null +++ b/composables/codemirrorThemes.js @@ -0,0 +1,284 @@ +export default function () { + return [ + { + name: "3024-day", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/3024-day.png", + }, + { + name: "3024-night", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/3024-night.png", + }, + { + name: "abcdef", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/abcdef.png", + }, + { + name: "ambiance-mobile", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/ambiance-mobile.png", + }, + { + name: "ambiance", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/ambiance.png", + }, + { + name: "ayu-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/ayu-dark.png", + }, + { + name: "ayu-mirage", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/ayu-mirage.png", + }, + { + name: "base16-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/base16-dark.png", + }, + { + name: "base16-light", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/base16-light.png", + }, + { + name: "bespin", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/bespin.png", + }, + { + name: "blackboard", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/blackboard.png", + }, + { + name: "cobalt", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/cobalt.png", + }, + { + name: "colorforth", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/colorforth.png", + }, + { + name: "dracula", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/dracula.png", + }, + { + name: "duotone-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/duotone-dark.png", + }, + { + name: "duotone-light", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/duotone-light.png", + }, + { + name: "eclipse", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/eclipse.png", + }, + { + name: "elegant", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/elegant.png", + }, + { + name: "erlang-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/erlang-dark.png", + }, + { + name: "gruvbox-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/gruvbox-dark.png", + }, + { + name: "hopscotch", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/hopscotch.png", + }, + { + name: "icecoder", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/icecoder.png", + }, + { + name: "idea", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/idea.png", + }, + { + name: "isotope", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/isotope.png", + }, + { + name: "lesser-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/lesser-dark.png", + }, + { + name: "liquibyte", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/liquibyte.png", + }, + { + name: "lucario", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/lucario.png", + }, + { + name: "material", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/material.png", + }, + { + name: "mbo", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/mbo.png", + }, + { + name: "mdn-like", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/mdn-like.png", + }, + { + name: "midnight", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/midnight.png", + }, + { + name: "monokai", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/monokai.png", + }, + { + name: "neat", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/neat.png", + }, + { + name: "neo", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/neo.png", + }, + { + name: "night", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/night.png", + }, + { + name: "oceanic-next", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/oceanic-next.png", + }, + { + name: "panda-syntax", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/panda-syntax.png", + }, + { + name: "paraiso-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/paraiso-dark.png", + }, + { + name: "paraiso-light", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/paraiso-light.png", + }, + { + name: "pastel-on-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/pastel-on-dark.png", + }, + { + name: "railscasts", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/railscasts.png", + }, + { + name: "rubyblue", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/rubyblue.png", + }, + { + name: "seti", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/seti.png", + }, + { + name: "shadowfox", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/shadowfox.png", + }, + { + name: "solarized", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/solarized.png", + }, + { + name: "the-matrix", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/the-matrix.png", + }, + { + name: "tomorrow-night-bright", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/tomorrow-night-bright.png", + }, + { + name: "tomorrow-night-eighties", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/tomorrow-night-eighties.png", + }, + { + name: "ttcn", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/ttcn.png", + }, + { + name: "twilight", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/twilight.png", + }, + { + name: "vibrant-ink", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/vibrant-ink.png", + }, + { + name: "xq-dark", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/xq-dark.png", + }, + { + name: "xq-light", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/xq-light.png", + }, + { + name: "yeti", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/yeti.png", + }, + { + name: "yonce", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/yonce.png", + }, + { + name: "zenburn", + image: + "https://raw.githubusercontent.com/codemirror/CodeMirror/master/theme/zenburn.png", + }, + ]; +} diff --git a/composables/languageList.js b/composables/languageList.js new file mode 100644 index 0000000..3c14fa7 --- /dev/null +++ b/composables/languageList.js @@ -0,0 +1,20 @@ +export default function () { + return [ + { + name: "English", + value: "en", + flagCode: "GB", + default: true, + }, + { + name: "Malay", + value: "ms", + flagCode: "MY", + }, + { + name: "Chinese", + value: "cn", + flagCode: "CN", + } + ]; +} diff --git a/composables/themeList.js b/composables/themeList.js new file mode 100644 index 0000000..744d855 --- /dev/null +++ b/composables/themeList.js @@ -0,0 +1,72 @@ +export default function () { + return [ + { + theme: "default", + colors: [ + { + name: "primary", + value: "243, 88, 106", + }, + { + name: "secondary", + value: "240, 122, 37", + }, + { + name: "accent", + value: "243, 244, 246", + }, + ], + }, + { + theme: "dark", + colors: [ + { + name: "primary", + value: "243, 88, 106", + }, + { + name: "secondary", + value: "240, 122, 37", + }, + { + name: "accent", + value: "15, 23, 42", + }, + ], + }, + { + theme: "nier", + colors: [ + { + name: "primary", + value: "99, 95, 84", + }, + { + name: "secondary", + value: "207, 107, 83", + }, + { + name: "accent", + value: "243, 88, 106", + }, + ], + }, + { + theme: "custom1", + colors: [ + { + name: "primary", + value: "9, 76, 90", + }, + { + name: "secondary", + value: "62, 72, 83", + }, + { + name: "accent", + value: "0, 103, 236", + }, + ], + }, + ]; +} diff --git a/ecosystem.config.js b/ecosystem.config.js new file mode 100644 index 0000000..6f4f8c7 --- /dev/null +++ b/ecosystem.config.js @@ -0,0 +1,13 @@ +// For running pm2 | ecosystem.config.js + +module.exports = { + apps: [ + { + name: "corrad", + port: "3000", + exec_mode: "cluster", + instances: "max", + script: "./.output/server/index.mjs", + }, + ], +}; diff --git a/error.vue b/error.vue new file mode 100644 index 0000000..7736c76 --- /dev/null +++ b/error.vue @@ -0,0 +1,70 @@ + + + diff --git a/formkit.config.js b/formkit.config.js new file mode 100644 index 0000000..8c8c188 --- /dev/null +++ b/formkit.config.js @@ -0,0 +1,118 @@ +import { generateClasses } from "@formkit/themes"; +import defaultTheme from "@/assets/js/formkit-theme.js"; +import customInput from "@/assets/js/formkit-custom.js"; + +// ----------------- Addons --------------------------- // + +// https://formkit.com/plugins/auto-animate +import { createAutoAnimatePlugin } from "@formkit/addons"; + +// https://formkit.com/plugins/floating-labels +import { createFloatingLabelsPlugin } from "@formkit/addons"; +import "@formkit/addons/css/floatingLabels"; + +// https://formkit.com/plugins/multi-step +import { createMultiStepPlugin } from "@formkit/addons"; +import "@formkit/addons/css/multistep"; + +// https://formkit.com/plugins/auto-height-textarea +import { createAutoHeightTextareaPlugin } from "@formkit/addons"; + +// https://formkit.com/plugins/local-storage +import { createLocalStoragePlugin } from "@formkit/addons"; + +const legends = ["checkbox_multi", "radio_multi", "repeater", "transferlist"]; + +function addAsteriskPlugin(node) { + if ( + ["button", "submit", "hidden", "group", "list", "meta"].includes( + node.props.type + ) + ) + return; + + const isRequired = + node.props?.validation === "required" || + (Array.isArray(node.props?.validation) && + node.props.validation.some( + (rule) => Array.isArray(rule) && rule.includes("required") + )); + + if (isRequired) { + node.on("created", () => { + // Determine if we should use legend or label + const legendOrLabel = legends.includes( + `${node.props.type}${node.props.options ? "_multi" : ""}` + ) + ? "legend" + : "label"; + + // Update schema memo key with proper suffix + if (node.props.definition.schemaMemoKey) { + node.props.definition.schemaMemoKey += `${ + node.props.options ? "_multi" : "" + }_add_asterisk`; + } + + const originalSchemaFn = node.props.definition.schema; + node.props.definition.schema = (sectionsSchema = {}) => { + // Initialize the proper section (legend or label) + if (!sectionsSchema[legendOrLabel]) { + sectionsSchema[legendOrLabel] = {}; + } + if (!sectionsSchema[legendOrLabel].attrs) { + sectionsSchema[legendOrLabel].attrs = {}; + } + sectionsSchema[legendOrLabel].attrs["data-required"] = true; + + // Add children array for the proper section + sectionsSchema[legendOrLabel].children = [ + "$label", + { + $el: "span", + attrs: { + class: "formkit-asterisk", + title: node.props?.requiredText || "diperlukan", + }, + children: ["*"], + }, + ]; + + const schema = originalSchemaFn(sectionsSchema); + + if (!schema.attrs) schema.attrs = {}; + schema.attrs["data-required"] = true; + + return schema; + }; + }); + } +} + +export default { + plugins: [ + addAsteriskPlugin, + createFloatingLabelsPlugin({ + useAsDefault: false, // defaults to false + }), + createAutoAnimatePlugin({ + // optional config + }), + createMultiStepPlugin(), + createAutoHeightTextareaPlugin(), + createLocalStoragePlugin({ + // plugin defaults: + prefix: "formkit", + key: undefined, + control: undefined, + maxAge: 3600000, // 1 hour + debounce: 200, + beforeSave: undefined, + beforeLoad: undefined, + }), + ], + config: { + classes: generateClasses(defaultTheme), + }, + inputs: customInput, +}; diff --git a/layouts/default.vue b/layouts/default.vue new file mode 100644 index 0000000..0f04a1d --- /dev/null +++ b/layouts/default.vue @@ -0,0 +1,11 @@ + + + diff --git a/layouts/empty.vue b/layouts/empty.vue new file mode 100644 index 0000000..8bc6805 --- /dev/null +++ b/layouts/empty.vue @@ -0,0 +1,7 @@ + + + diff --git a/middleware/auth.js b/middleware/auth.js new file mode 100644 index 0000000..4a124c6 --- /dev/null +++ b/middleware/auth.js @@ -0,0 +1,26 @@ +export default defineNuxtRouteMiddleware(async (to, from) => { + const { $swal } = useNuxtApp(); + + if (process.client) { + // Validate every request to every page + const { data: validateUser } = await useFetch("/api/auth/validate", { + method: "GET", + }); + + // If user is not logged in, redirect to logout page + if (validateUser.value.statusCode === 401) { + $swal + .fire({ + title: "Session Expired", + text: "Your session has expired. Please login again.", + icon: "warning", + confirmButtonText: "OK", + }) + .then(() => { + return window.location.replace("/logout"); + }); + } + + return true; + } +}); diff --git a/middleware/dashboard.js b/middleware/dashboard.js new file mode 100644 index 0000000..08091f2 --- /dev/null +++ b/middleware/dashboard.js @@ -0,0 +1,11 @@ +export default defineNuxtRouteMiddleware(async (to, from) => { + // Validate every request to every page + const { data: validateUser } = await useFetch("/api/auth/validate", { + method: "GET", + }); + + // If user is not logged in, redirect to logout page + if (validateUser.value.statusCode === 401) return true; + + return navigateTo("/dashboard"); +}); diff --git a/middleware/forbidden.js b/middleware/forbidden.js new file mode 100644 index 0000000..da4fe40 --- /dev/null +++ b/middleware/forbidden.js @@ -0,0 +1,4 @@ +export default defineNuxtRouteMiddleware(async (to, from) => { + // Throw error to page 404 not found + throw new Error("Forbidden"); +}); diff --git a/middleware/main.js b/middleware/main.js new file mode 100644 index 0000000..b70e2fa --- /dev/null +++ b/middleware/main.js @@ -0,0 +1,3 @@ +export default defineNuxtRouteMiddleware((to, from) => { + return navigateTo("/login"); +}); \ No newline at end of file diff --git a/navigation/index.js b/navigation/index.js new file mode 100644 index 0000000..10d51ea --- /dev/null +++ b/navigation/index.js @@ -0,0 +1,114 @@ +export default [ + { + "header": "", + "description": "", + "child": [ + { + "title": "Dashboard", + "path": "/dashboard", + "icon": "ic:outline-dashboard", + "child": [], + "meta": {} + } + ] + }, + { + "header": "Administration", + "description": "Manage your application", + "child": [ + { + "title": "Configuration", + "icon": "ic:outline-settings", + "child": [ + { + "title": "Environment", + "path": "/devtool/config/environment" + } + ] + }, + { + "title": "Menu Editor", + "icon": "ci:menu-alt-03", + "path": "/devtool/menu-editor", + "child": [] + }, + { + "title": "Manage Users", + "path": "/devtool/user-management", + "icon": "ph:user-circle-gear", + "child": [ + { + "title": "User List", + "path": "/devtool/user-management/user", + "icon": "", + "child": [] + }, + { + "title": "Role List", + "path": "/devtool/user-management/role", + "icon": "", + "child": [] + } + ] + }, + { + "title": "Content", + "icon": "mdi:pencil-ruler", + "child": [ + { + "title": "Editor", + "path": "/devtool/content-editor" + }, + { + "title": "Template", + "path": "/devtool/content-editor/template" + } + ] + }, + { + "title": "API Editor", + "path": "/devtool/api-editor", + "icon": "material-symbols:api-rounded", + "child": [] + }, + { + "title": "Code Playground", + "path": "/devtool/code-playground", + "icon": "mdi:code-braces", + "child": [] + } + ], + "meta": { + "auth": { + "role": [ + "Developer" + ] + } + } + }, + { + "header": "Help", + "description": "Help and documentation", + "child": [ + { + "title": "Documentation", + "icon": "solar:book-bookmark-minimalistic-bold", + "path": "https://manual.corrad.ai", + "external": true + }, + { + "title": "UI Components", + "icon": "material-symbols:settings-input-component-outline-rounded", + "path": "https://ui.corrad.ai", + "external": true + } + ], + "meta": { + "auth": { + "role": [ + "Developer" + ] + } + } + } +]; \ No newline at end of file diff --git a/nuxt.config.js b/nuxt.config.js new file mode 100644 index 0000000..fdf7bae --- /dev/null +++ b/nuxt.config.js @@ -0,0 +1,551 @@ +// https://v3.nuxtjs.org/api/configuration/nuxt.config +export default defineNuxtConfig({ + runtimeConfig: { + auth: { + secretAccess: process.env.NUXT_ACCESS_TOKEN_SECRET, + secretRefresh: process.env.NUXT_REFRESH_TOKEN_SECRET, + }, + }, + modules: [ + "@nuxtjs/tailwindcss", + "@formkit/nuxt", + "@vite-pwa/nuxt", + "@vueuse/nuxt", + "floating-vue/nuxt", + "@pinia/nuxt", + "@pinia-plugin-persistedstate/nuxt", + "nuxt-security", + "nuxt-typed-router", + "nuxt-icon", + "@davestewart/nuxt-scrollbar", + ], + app: { + pageTransition: { name: "page", mode: "out-in" }, + }, + vite:{ + server:{ + watch: { + usePolling: true, + interval: 1000, + }, + }, + }, + head: { + title: "corrad", + meta: [ + { charset: "utf-8" }, + { name: "viewport", content: "width=device-width, initial-scale=1" }, + { + hid: "description", + name: "description", + content: "corrad", + }, + ], + link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" }], + }, + css: ["~/assets/style/scss/main.scss"], + tailwindcss: { + cssPath: "~/assets/style/css/tailwind.css", + configPath: "tailwind.config", + exposeConfig: false, + config: {}, + injectPosition: 0, + viewer: false, + }, + formkit: { + defaultConfig: true, + }, + pwa: { + registerType: "autoUpdate", + workbox: { + navigateFallback: "/", + globPatterns: [ + "**/*.{js,json,css,html,txt,svg,png,ico,webp,woff,woff2,ttf,eot,otf,wasm}", + ], + }, + devOptions: { + enabled: false, + type: "module", + }, + manifest: { + name: "corrad", + short_name: "corrad", + theme_color: "#202D3B", + background_color: "#FAFAFA", + display: "standalone", + scope: "./", + start_url: "./", + icons: [ + { + src: "icons/windows11/SmallTile.scale-100.png", + sizes: "71x71", + }, + { + src: "icons/windows11/SmallTile.scale-125.png", + sizes: "89x89", + }, + { + src: "icons/windows11/SmallTile.scale-150.png", + sizes: "107x107", + }, + { + src: "icons/windows11/SmallTile.scale-200.png", + sizes: "142x142", + }, + { + src: "icons/windows11/SmallTile.scale-400.png", + sizes: "284x284", + }, + { + src: "icons/windows11/Square150x150Logo.scale-100.png", + sizes: "150x150", + }, + { + src: "icons/windows11/Square150x150Logo.scale-125.png", + sizes: "188x188", + }, + { + src: "icons/windows11/Square150x150Logo.scale-150.png", + sizes: "225x225", + }, + { + src: "icons/windows11/Square150x150Logo.scale-200.png", + sizes: "300x300", + }, + { + src: "icons/windows11/Square150x150Logo.scale-400.png", + sizes: "600x600", + }, + { + src: "icons/windows11/Wide310x150Logo.scale-100.png", + sizes: "310x150", + }, + { + src: "icons/windows11/Wide310x150Logo.scale-125.png", + sizes: "388x188", + }, + { + src: "icons/windows11/Wide310x150Logo.scale-150.png", + sizes: "465x225", + }, + { + src: "icons/windows11/Wide310x150Logo.scale-200.png", + sizes: "620x300", + }, + { + src: "icons/windows11/Wide310x150Logo.scale-400.png", + sizes: "1240x600", + }, + { + src: "icons/windows11/LargeTile.scale-100.png", + sizes: "310x310", + }, + { + src: "icons/windows11/LargeTile.scale-125.png", + sizes: "388x388", + }, + { + src: "icons/windows11/LargeTile.scale-150.png", + sizes: "465x465", + }, + { + src: "icons/windows11/LargeTile.scale-200.png", + sizes: "620x620", + }, + { + src: "icons/windows11/LargeTile.scale-400.png", + sizes: "1240x1240", + }, + { + src: "icons/windows11/Square44x44Logo.scale-100.png", + sizes: "44x44", + }, + { + src: "icons/windows11/Square44x44Logo.scale-125.png", + sizes: "55x55", + }, + { + src: "icons/windows11/Square44x44Logo.scale-150.png", + sizes: "66x66", + }, + { + src: "icons/windows11/Square44x44Logo.scale-200.png", + sizes: "88x88", + }, + { + src: "icons/windows11/Square44x44Logo.scale-400.png", + sizes: "176x176", + }, + { + src: "icons/windows11/StoreLogo.scale-100.png", + sizes: "50x50", + }, + { + src: "icons/windows11/StoreLogo.scale-125.png", + sizes: "63x63", + }, + { + src: "icons/windows11/StoreLogo.scale-150.png", + sizes: "75x75", + }, + { + src: "icons/windows11/StoreLogo.scale-200.png", + sizes: "100x100", + }, + { + src: "icons/windows11/StoreLogo.scale-400.png", + sizes: "200x200", + }, + { + src: "icons/windows11/SplashScreen.scale-100.png", + sizes: "620x300", + }, + { + src: "icons/windows11/SplashScreen.scale-125.png", + sizes: "775x375", + }, + { + src: "icons/windows11/SplashScreen.scale-150.png", + sizes: "930x450", + }, + { + src: "icons/windows11/SplashScreen.scale-200.png", + sizes: "1240x600", + }, + { + src: "icons/windows11/SplashScreen.scale-400.png", + sizes: "2480x1200", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-16.png", + sizes: "16x16", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-20.png", + sizes: "20x20", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-24.png", + sizes: "24x24", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-30.png", + sizes: "30x30", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-32.png", + sizes: "32x32", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-36.png", + sizes: "36x36", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-40.png", + sizes: "40x40", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-44.png", + sizes: "44x44", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-48.png", + sizes: "48x48", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-60.png", + sizes: "60x60", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-64.png", + sizes: "64x64", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-72.png", + sizes: "72x72", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-80.png", + sizes: "80x80", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-96.png", + sizes: "96x96", + }, + { + src: "icons/windows11/Square44x44Logo.targetsize-256.png", + sizes: "256x256", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-16.png", + sizes: "16x16", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-20.png", + sizes: "20x20", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-24.png", + sizes: "24x24", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-30.png", + sizes: "30x30", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-32.png", + sizes: "32x32", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-36.png", + sizes: "36x36", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-40.png", + sizes: "40x40", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-44.png", + sizes: "44x44", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-48.png", + sizes: "48x48", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-60.png", + sizes: "60x60", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-64.png", + sizes: "64x64", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-72.png", + sizes: "72x72", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-80.png", + sizes: "80x80", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-96.png", + sizes: "96x96", + }, + { + src: "icons/windows11/Square44x44Logo.altform-unplated_targetsize-256.png", + sizes: "256x256", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png", + sizes: "16x16", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png", + sizes: "20x20", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png", + sizes: "24x24", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png", + sizes: "30x30", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png", + sizes: "32x32", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png", + sizes: "36x36", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png", + sizes: "40x40", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png", + sizes: "44x44", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png", + sizes: "48x48", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png", + sizes: "60x60", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png", + sizes: "64x64", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png", + sizes: "72x72", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png", + sizes: "80x80", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png", + sizes: "96x96", + }, + { + src: "icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png", + sizes: "256x256", + }, + { + src: "icons/android/android-launchericon-512-512.png", + sizes: "512x512", + }, + { + src: "icons/android/android-launchericon-192-192.png", + sizes: "192x192", + }, + { + src: "icons/android/android-launchericon-144-144.png", + sizes: "144x144", + }, + { + src: "icons/android/android-launchericon-96-96.png", + sizes: "96x96", + }, + { + src: "icons/android/android-launchericon-72-72.png", + sizes: "72x72", + }, + { + src: "icons/android/android-launchericon-48-48.png", + sizes: "48x48", + }, + { + src: "icons/ios/16.png", + sizes: "16x16", + }, + { + src: "icons/ios/20.png", + sizes: "20x20", + }, + { + src: "icons/ios/29.png", + sizes: "29x29", + }, + { + src: "icons/ios/32.png", + sizes: "32x32", + }, + { + src: "icons/ios/40.png", + sizes: "40x40", + }, + { + src: "icons/ios/50.png", + sizes: "50x50", + }, + { + src: "icons/ios/57.png", + sizes: "57x57", + }, + { + src: "icons/ios/58.png", + sizes: "58x58", + }, + { + src: "icons/ios/60.png", + sizes: "60x60", + }, + { + src: "icons/ios/64.png", + sizes: "64x64", + }, + { + src: "icons/ios/72.png", + sizes: "72x72", + }, + { + src: "icons/ios/76.png", + sizes: "76x76", + }, + { + src: "icons/ios/80.png", + sizes: "80x80", + }, + { + src: "icons/ios/87.png", + sizes: "87x87", + }, + { + src: "icons/ios/100.png", + sizes: "100x100", + }, + { + src: "icons/ios/114.png", + sizes: "114x114", + }, + { + src: "icons/ios/120.png", + sizes: "120x120", + }, + { + src: "icons/ios/128.png", + sizes: "128x128", + }, + { + src: "icons/ios/144.png", + sizes: "144x144", + }, + { + src: "icons/ios/152.png", + sizes: "152x152", + }, + { + src: "icons/ios/167.png", + sizes: "167x167", + }, + { + src: "icons/ios/180.png", + sizes: "180x180", + }, + { + src: "icons/ios/192.png", + sizes: "192x192", + }, + { + src: "icons/ios/256.png", + sizes: "256x256", + }, + { + src: "icons/ios/512.png", + sizes: "512x512", + }, + { + src: "icons/ios/1024.png", + sizes: "1024x1024", + }, + ], + }, + }, + security: { + // GLOBAL SECURITY OPTIONS + + // Allow 200 requests per hour (the Twitter search limit). Also understands + // 'second', 'minute', 'day', or a number of milliseconds + rateLimiter: { + tokensPerInterval: 200, + interval: "minute", + fireImmediately: false, + throwError: true, // optional + }, + headers: false, + }, + routeRules: { + "/api/devtool/**": { + security: { + xssValidator: false, + requestSizeLimiter: false, + }, + }, + }, +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..5afccef --- /dev/null +++ b/package.json @@ -0,0 +1,86 @@ +{ + "private": true, + "scripts": { + "build": "nuxt build", + "build:new": "node pre-build.js && nuxt build && node post-build.js", + "dev": "nuxt dev", + "generate": "nuxt generate", + "preview": "nuxt preview", + "postinstall": "nuxt prepare", + "prisma": "npx prisma db pull && npx prisma generate && nuxt dev" + }, + "devDependencies": { + "@nuxtjs/tailwindcss": "^6.8.0", + "@pinia-plugin-persistedstate/nuxt": "^1.1.1", + "@vite-pwa/nuxt": "^0.1.0", + "eslint": "^8.39.0", + "eslint-plugin-vue": "^9.16.1", + "nuxt": "^3.6.5", + "nuxt-icon": "^0.1.7", + "nuxt-security": "^0.13.0", + "nuxt-typed-router": "^3.2.5", + "postcss-import": "^15.1.0" + }, + "dependencies": { + "@babel/eslint-parser": "^7.19.1", + "@codemirror/lang-html": "^6.4.3", + "@codemirror/lang-javascript": "^6.1.6", + "@codemirror/lang-vue": "^0.1.1", + "@codemirror/theme-one-dark": "^6.1.2", + "@davestewart/nuxt-scrollbar": "^1.0.0", + "@formkit/addons": "^1.0.0", + "@formkit/auto-animate": "^0.7.0", + "@formkit/nuxt": "^1.0.0", + "@formkit/pro": "^0.115.3", + "@formkit/themes": "^1.0.0", + "@fullcalendar/core": "^5.11.3", + "@fullcalendar/daygrid": "^5.11.3", + "@fullcalendar/interaction": "^5.11.3", + "@fullcalendar/list": "^5.11.3", + "@fullcalendar/luxon2": "^5.11.3", + "@fullcalendar/scrollgrid": "^5.11.3", + "@fullcalendar/timegrid": "^5.11.3", + "@fullcalendar/vue3": "^5.11.2", + "@kiwicom/eslint-config": "^12.7.3", + "@pinia/nuxt": "^0.4.11", + "@popperjs/core": "^2.11.8", + "@prisma/client": "^5.1.1", + "@shimyshack/uid": "^0.1.7", + "@sweetalert2/theme-dark": "^5.0.14", + "@vueup/vue-quill": "^1.0.0", + "@vueuse/core": "^9.5.0", + "@vueuse/nuxt": "^9.5.0", + "apexcharts": "^3.36.0", + "chart.js": "^3.9.1", + "codemirror": "^6.0.1", + "cross-env": "^7.0.3", + "crypto-js": "^4.1.1", + "floating-vue": "^2.0.0-beta.24", + "jsonwebtoken": "^8.5.1", + "luxon": "^3.1.0", + "maska": "^1.5.0", + "pinia": "^2.1.6", + "prettier": "^3.3.3", + "prettier-plugin-vue": "^1.1.6", + "prisma": "^5.1.1", + "prisma-json-schema-generator": "^5.1.5", + "sass": "^1.62.0", + "swiper": "^8.4.4", + "thememirror": "^2.0.1", + "uuid": "^10.0.0", + "v-calendar": "^3.0.3", + "vue-chart-3": "^3.1.8", + "vue-code-highlight": "^0.7.8", + "vue-codemirror": "^6.1.1", + "vue-country-flag-next": "^2.3.2", + "vue-fullscreen": "^3.1.1", + "vue-select": "^4.0.0-beta.5", + "vue-sweetalert2": "^5.0.5", + "vue-toastification": "^2.0.0-rc.5", + "vue-window-size": "^1.0.8", + "vue3-apexcharts": "^1.4.1", + "vue3-click-away": "^1.2.4", + "vue3-dropzone": "^2.0.1", + "vuedraggable": "^4.1.0" + } +} diff --git a/pages/dashboard/index.vue b/pages/dashboard/index.vue new file mode 100644 index 0000000..ca65688 --- /dev/null +++ b/pages/dashboard/index.vue @@ -0,0 +1,479 @@ + + + diff --git a/pages/devtool/api-editor/code/index.vue b/pages/devtool/api-editor/code/index.vue new file mode 100644 index 0000000..d7a2ee0 --- /dev/null +++ b/pages/devtool/api-editor/code/index.vue @@ -0,0 +1,244 @@ + + + + + diff --git a/pages/devtool/api-editor/index.vue b/pages/devtool/api-editor/index.vue new file mode 100644 index 0000000..e632c55 --- /dev/null +++ b/pages/devtool/api-editor/index.vue @@ -0,0 +1,327 @@ + + diff --git a/pages/devtool/code-playground/index.vue b/pages/devtool/code-playground/index.vue new file mode 100644 index 0000000..caba3ee --- /dev/null +++ b/pages/devtool/code-playground/index.vue @@ -0,0 +1,425 @@ + + + + \ No newline at end of file diff --git a/pages/devtool/config/application-log/index.vue b/pages/devtool/config/application-log/index.vue new file mode 100644 index 0000000..677f24b --- /dev/null +++ b/pages/devtool/config/application-log/index.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/pages/devtool/config/environment/index.vue b/pages/devtool/config/environment/index.vue new file mode 100644 index 0000000..77bcd0a --- /dev/null +++ b/pages/devtool/config/environment/index.vue @@ -0,0 +1,27 @@ + + + diff --git a/pages/devtool/config/index.vue b/pages/devtool/config/index.vue new file mode 100644 index 0000000..677f24b --- /dev/null +++ b/pages/devtool/config/index.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/pages/devtool/content-editor/code/index.vue b/pages/devtool/content-editor/code/index.vue new file mode 100644 index 0000000..223aea6 --- /dev/null +++ b/pages/devtool/content-editor/code/index.vue @@ -0,0 +1,226 @@ + + + diff --git a/pages/devtool/content-editor/index.vue b/pages/devtool/content-editor/index.vue new file mode 100644 index 0000000..884e783 --- /dev/null +++ b/pages/devtool/content-editor/index.vue @@ -0,0 +1,247 @@ + + + + diff --git a/pages/devtool/content-editor/template/index.vue b/pages/devtool/content-editor/template/index.vue new file mode 100644 index 0000000..8b18c25 --- /dev/null +++ b/pages/devtool/content-editor/template/index.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/pages/devtool/content-editor/template/view/[id]/index.vue b/pages/devtool/content-editor/template/view/[id]/index.vue new file mode 100644 index 0000000..e332bda --- /dev/null +++ b/pages/devtool/content-editor/template/view/[id]/index.vue @@ -0,0 +1,33 @@ + + + diff --git a/pages/devtool/menu-editor/index.vue b/pages/devtool/menu-editor/index.vue new file mode 100644 index 0000000..edcbce9 --- /dev/null +++ b/pages/devtool/menu-editor/index.vue @@ -0,0 +1,799 @@ + + + + + diff --git a/pages/devtool/orm/index.vue b/pages/devtool/orm/index.vue new file mode 100644 index 0000000..7ab6ae1 --- /dev/null +++ b/pages/devtool/orm/index.vue @@ -0,0 +1,169 @@ + + + diff --git a/pages/devtool/orm/table/create/index.vue b/pages/devtool/orm/table/create/index.vue new file mode 100644 index 0000000..13bdac5 --- /dev/null +++ b/pages/devtool/orm/table/create/index.vue @@ -0,0 +1,315 @@ + + + diff --git a/pages/devtool/orm/table/modify/[table].vue b/pages/devtool/orm/table/modify/[table].vue new file mode 100644 index 0000000..b2e8855 --- /dev/null +++ b/pages/devtool/orm/table/modify/[table].vue @@ -0,0 +1,360 @@ + + + diff --git a/pages/devtool/orm/view/[table]/index.vue b/pages/devtool/orm/view/[table]/index.vue new file mode 100644 index 0000000..6d984cc --- /dev/null +++ b/pages/devtool/orm/view/[table]/index.vue @@ -0,0 +1,79 @@ + + + diff --git a/pages/devtool/user-management/role/index.vue b/pages/devtool/user-management/role/index.vue new file mode 100644 index 0000000..74212ef --- /dev/null +++ b/pages/devtool/user-management/role/index.vue @@ -0,0 +1,499 @@ + + diff --git a/pages/devtool/user-management/user/index.vue b/pages/devtool/user-management/user/index.vue new file mode 100644 index 0000000..b157201 --- /dev/null +++ b/pages/devtool/user-management/user/index.vue @@ -0,0 +1,497 @@ + + diff --git a/pages/forgot-password/index.vue b/pages/forgot-password/index.vue new file mode 100644 index 0000000..e8e74c0 --- /dev/null +++ b/pages/forgot-password/index.vue @@ -0,0 +1,42 @@ + + + diff --git a/pages/index.vue b/pages/index.vue new file mode 100644 index 0000000..0cf6a06 --- /dev/null +++ b/pages/index.vue @@ -0,0 +1,10 @@ + + + diff --git a/pages/login/index.vue b/pages/login/index.vue new file mode 100644 index 0000000..dcac272 --- /dev/null +++ b/pages/login/index.vue @@ -0,0 +1,140 @@ + + + diff --git a/pages/logout/index.vue b/pages/logout/index.vue new file mode 100644 index 0000000..6bc920b --- /dev/null +++ b/pages/logout/index.vue @@ -0,0 +1,28 @@ + + + diff --git a/pages/register/index.vue b/pages/register/index.vue new file mode 100644 index 0000000..c06c2c7 --- /dev/null +++ b/pages/register/index.vue @@ -0,0 +1,96 @@ + + + diff --git a/pages/reset-password/index.vue b/pages/reset-password/index.vue new file mode 100644 index 0000000..7299244 --- /dev/null +++ b/pages/reset-password/index.vue @@ -0,0 +1,42 @@ + + + diff --git a/plugins/apex-chart.client.js b/plugins/apex-chart.client.js new file mode 100644 index 0000000..343d647 --- /dev/null +++ b/plugins/apex-chart.client.js @@ -0,0 +1,5 @@ +import VueApexCharts from "vue3-apexcharts"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.component("VueApexCharts", VueApexCharts); +}); diff --git a/plugins/chart-js.client.js b/plugins/chart-js.client.js new file mode 100644 index 0000000..e9eda5b --- /dev/null +++ b/plugins/chart-js.client.js @@ -0,0 +1,7 @@ +// Workaround because chart.js doesn't provide an default export +import * as ChartJs from "chart.js"; +const { Chart, registerables } = ChartJs; + +export default defineNuxtPlugin(() => { + Chart.register(...registerables); +}); diff --git a/plugins/formkit-auto-animate.js b/plugins/formkit-auto-animate.js new file mode 100644 index 0000000..37dd775 --- /dev/null +++ b/plugins/formkit-auto-animate.js @@ -0,0 +1,5 @@ +import { autoAnimatePlugin } from "@formkit/auto-animate/vue"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.use(autoAnimatePlugin); +}); diff --git a/plugins/full-calendar.client.js b/plugins/full-calendar.client.js new file mode 100644 index 0000000..986bf69 --- /dev/null +++ b/plugins/full-calendar.client.js @@ -0,0 +1,27 @@ +import "@fullcalendar/core/vdom"; // solve problem with Vite +import FullCalendar from "@fullcalendar/vue3"; +import interactionPlugin from "@fullcalendar/interaction"; +import dayGridPlugin from "@fullcalendar/daygrid"; +import timeGridPlugin from "@fullcalendar/timegrid"; +import listPlugin from "@fullcalendar/list"; +import scrollGrid from "@fullcalendar/scrollgrid"; +import luxon2Plugin from "@fullcalendar/luxon2"; + +FullCalendar.options = { + plugins: [ + interactionPlugin, + dayGridPlugin, + timeGridPlugin, + listPlugin, + scrollGrid, + luxon2Plugin, + ], +}; + +export default defineNuxtPlugin((/* nuxtApp */) => { + return { + provide: { + FullCalendar, + }, + }; +}); diff --git a/plugins/maska.js b/plugins/maska.js new file mode 100644 index 0000000..169859f --- /dev/null +++ b/plugins/maska.js @@ -0,0 +1,5 @@ +import Maska from "maska"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.use(Maska); +}); diff --git a/plugins/swiper.js b/plugins/swiper.js new file mode 100644 index 0000000..722898a --- /dev/null +++ b/plugins/swiper.js @@ -0,0 +1,7 @@ +import { Swiper, SwiperSlide } from "swiper/vue"; +import "swiper/css/bundle"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.component("Swiper", Swiper); + nuxtApp.vueApp.component("SwiperSlide", SwiperSlide); +}); diff --git a/plugins/uid-plugin.js b/plugins/uid-plugin.js new file mode 100644 index 0000000..24e036d --- /dev/null +++ b/plugins/uid-plugin.js @@ -0,0 +1,5 @@ +import { UidPlugin } from "@shimyshack/uid"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.use(UidPlugin); +}); diff --git a/plugins/v-select.js b/plugins/v-select.js new file mode 100644 index 0000000..ede656d --- /dev/null +++ b/plugins/v-select.js @@ -0,0 +1,6 @@ +import vSelect from "vue-select"; +import "vue-select/dist/vue-select.css"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.component("v-select", vSelect); +}); diff --git a/plugins/vue-calendar.js b/plugins/vue-calendar.js new file mode 100644 index 0000000..eb1c2f5 --- /dev/null +++ b/plugins/vue-calendar.js @@ -0,0 +1,5 @@ +import VCalendar from "v-calendar"; +import "v-calendar/style.css"; +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.use(VCalendar); +}); diff --git a/plugins/vue-code-highlight.js b/plugins/vue-code-highlight.js new file mode 100644 index 0000000..ef0ec1f --- /dev/null +++ b/plugins/vue-code-highlight.js @@ -0,0 +1,8 @@ +import VueCodeHighlight from "vue-code-highlight"; + +import "vue-code-highlight/themes/prism-okaidia.css"; +import "vue-code-highlight/themes/window.css"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.use(VueCodeHighlight); +}); diff --git a/plugins/vue-codemirror.js b/plugins/vue-codemirror.js new file mode 100644 index 0000000..82838fc --- /dev/null +++ b/plugins/vue-codemirror.js @@ -0,0 +1,6 @@ +import { Codemirror } from "vue-codemirror"; + +// Install plugin +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.component("CodeMirror", Codemirror); +}); diff --git a/plugins/vue-country-flag.js b/plugins/vue-country-flag.js new file mode 100644 index 0000000..c0e9a9b --- /dev/null +++ b/plugins/vue-country-flag.js @@ -0,0 +1,7 @@ +// Import vue 3 plugin here +import CountryFlag from "vue-country-flag-next"; + +// Install the plugin +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.component("CountryFlag", CountryFlag); +}); diff --git a/plugins/vue-draggable.client.js b/plugins/vue-draggable.client.js new file mode 100644 index 0000000..58d50a0 --- /dev/null +++ b/plugins/vue-draggable.client.js @@ -0,0 +1,5 @@ +import draggable from "vuedraggable"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.component("draggable", draggable); +}); diff --git a/plugins/vue-fullscreen.js b/plugins/vue-fullscreen.js new file mode 100644 index 0000000..7b50e15 --- /dev/null +++ b/plugins/vue-fullscreen.js @@ -0,0 +1,5 @@ +import VueFullscreen from "vue-fullscreen"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.use(VueFullscreen); +}); diff --git a/plugins/vue-quill.client.js b/plugins/vue-quill.client.js new file mode 100644 index 0000000..db49b28 --- /dev/null +++ b/plugins/vue-quill.client.js @@ -0,0 +1,7 @@ +import { QuillEditor } from "@vueup/vue-quill"; +import "@vueup/vue-quill/dist/vue-quill.snow.css"; // Add css for snow theme +// import '@vueup/vue-quill/dist/vue-quill.bubble.css'; // for bubble theme + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.component("QuillEditor", QuillEditor); +}); diff --git a/plugins/vue-sweetalert2.js b/plugins/vue-sweetalert2.js new file mode 100644 index 0000000..0297888 --- /dev/null +++ b/plugins/vue-sweetalert2.js @@ -0,0 +1,6 @@ +import Swal from "sweetalert2"; +import "sweetalert2/dist/sweetalert2.min.css"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.provide("swal", Swal); +}); diff --git a/plugins/vue-toastification.client.js b/plugins/vue-toastification.client.js new file mode 100644 index 0000000..ca46118 --- /dev/null +++ b/plugins/vue-toastification.client.js @@ -0,0 +1,12 @@ +import Toast from "vue-toastification"; +import "vue-toastification/dist/index.css"; + +export default defineNuxtPlugin((nuxtApp) => { + const options = { + transition: "Vue-Toastification__bounce", + maxToasts: 20, + newestOnTop: true, + }; + + nuxtApp.vueApp.use(Toast, options); +}); diff --git a/post-build.js b/post-build.js new file mode 100644 index 0000000..58badd7 --- /dev/null +++ b/post-build.js @@ -0,0 +1,7 @@ +const { execSync } = require("child_process"); + +// Revert changes using git +execSync("git checkout -- pages/devtool navigation/index.js", { + stdio: "inherit", +}); +console.log("Changes reverted"); diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..a5a6ff8 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: { + "postcss-import": {}, + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/pre-build.js b/pre-build.js new file mode 100644 index 0000000..4d779c4 --- /dev/null +++ b/pre-build.js @@ -0,0 +1,25 @@ +const fs = require("fs"); +const path = require("path"); + +// Remove devtool folder +const devtoolPath = path.join(__dirname, "pages", "devtool"); +if (fs.existsSync(devtoolPath)) { + fs.rmSync(devtoolPath, { recursive: true, force: true }); + console.log("Devtool folder removed"); +} + +// Modify navigation.js +const navigationPath = path.join(__dirname, "navigation", "index.js"); +let navigationContent = fs.readFileSync(navigationPath, "utf8"); + +// Remove any child items with path containing 'devtool' +const modifiedNavigation = navigationContent.replace( + /\{[^}]*path:\s*['"]\/devtool[^}]*\},?/g, + "" +); + +// Remove empty child arrays +const cleanedNavigation = modifiedNavigation.replace(/child:\s*\[\s*\],?/g, ""); + +fs.writeFileSync(navigationPath, cleanedNavigation); +console.log("Navigation file updated"); diff --git a/prisma/json/json-schema.json b/prisma/json/json-schema.json new file mode 100644 index 0000000..04149bb --- /dev/null +++ b/prisma/json/json-schema.json @@ -0,0 +1,254 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "audit": { + "type": "object", + "properties": { + "auditID": { + "type": "integer" + }, + "auditIP": { + "type": [ + "string", + "null" + ] + }, + "auditURL": { + "type": [ + "string", + "null" + ] + }, + "auditURLMethod": { + "type": [ + "string", + "null" + ] + }, + "auditURLPayload": { + "type": [ + "string", + "null" + ] + }, + "auditCreatedDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + } + }, + "user": { + "type": "object", + "properties": { + "userID": { + "type": "integer" + }, + "userSecretKey": { + "type": [ + "string", + "null" + ] + }, + "userUsername": { + "type": [ + "string", + "null" + ] + }, + "userPassword": { + "type": [ + "string", + "null" + ] + }, + "userFullName": { + "type": [ + "string", + "null" + ] + }, + "userEmail": { + "type": [ + "string", + "null" + ] + }, + "userPhone": { + "type": [ + "string", + "null" + ] + }, + "userStatus": { + "type": [ + "string", + "null" + ] + }, + "userCreatedDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "userModifiedDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "userrole": { + "type": "array", + "items": { + "$ref": "#/definitions/userrole" + } + } + } + }, + "role": { + "type": "object", + "properties": { + "roleID": { + "type": "integer" + }, + "roleName": { + "type": [ + "string", + "null" + ] + }, + "roleDescription": { + "type": [ + "string", + "null" + ] + }, + "roleStatus": { + "type": [ + "string", + "null" + ] + }, + "roleCreatedDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "roleModifiedDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "userrole": { + "type": "array", + "items": { + "$ref": "#/definitions/userrole" + } + } + } + }, + "lookup": { + "type": "object", + "properties": { + "lookupID": { + "type": "integer" + }, + "lookupOrder": { + "type": [ + "integer", + "null" + ] + }, + "lookupTitle": { + "type": [ + "string", + "null" + ] + }, + "lookupRefCode": { + "type": [ + "string", + "null" + ] + }, + "lookupValue": { + "type": [ + "string", + "null" + ] + }, + "lookupType": { + "type": [ + "string", + "null" + ] + }, + "lookupStatus": { + "type": [ + "string", + "null" + ] + }, + "lookupCreatedDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "lookupModifiedDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + } + } + }, + "userrole": { + "type": "object", + "properties": { + "userRoleID": { + "type": "integer" + }, + "userRoleCreatedDate": { + "type": "string", + "format": "date-time" + }, + "role": { + "$ref": "#/definitions/role" + }, + "user": { + "$ref": "#/definitions/user" + } + } + } + }, + "type": "object", + "properties": { + "audit": { + "$ref": "#/definitions/audit" + }, + "user": { + "$ref": "#/definitions/user" + }, + "role": { + "$ref": "#/definitions/role" + }, + "lookup": { + "$ref": "#/definitions/lookup" + }, + "userrole": { + "$ref": "#/definitions/userrole" + } + } +} \ No newline at end of file diff --git a/prisma/migrations/20230808013656_initialize/migration.sql b/prisma/migrations/20230808013656_initialize/migration.sql new file mode 100644 index 0000000..c611a65 --- /dev/null +++ b/prisma/migrations/20230808013656_initialize/migration.sql @@ -0,0 +1,72 @@ +-- CreateTable +CREATE TABLE `audit` ( + `auditID` INTEGER NOT NULL AUTO_INCREMENT, + `auditIP` VARCHAR(255) NULL, + `auditURL` VARCHAR(255) NULL, + `auditURLMethod` VARCHAR(255) NULL, + `auditURLPayload` VARCHAR(255) NULL, + `auditCreatedDate` DATETIME(0) NULL, + + PRIMARY KEY (`auditID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `user` ( + `userID` INTEGER NOT NULL AUTO_INCREMENT, + `userSecretKey` VARCHAR(255) NULL, + `userUsername` VARCHAR(255) NULL, + `userPassword` VARCHAR(255) NULL, + `userFullName` VARCHAR(255) NULL, + `userEmail` VARCHAR(255) NULL, + `userPhone` VARCHAR(255) NULL, + `userStatus` VARCHAR(255) NULL, + `userCreatedDate` DATETIME(0) NULL, + `userModifiedDate` DATETIME(0) NULL, + + PRIMARY KEY (`userID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `role` ( + `roleID` INTEGER NOT NULL AUTO_INCREMENT, + `roleName` VARCHAR(255) NULL, + `roleDescription` VARCHAR(255) NULL, + `roleStatus` VARCHAR(255) NULL, + `roleCreatedDate` DATETIME(0) NULL, + `roleModifiedDate` DATETIME(0) NULL, + + PRIMARY KEY (`roleID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `lookup` ( + `lookupID` INTEGER NOT NULL AUTO_INCREMENT, + `lookupOrder` INTEGER NULL, + `lookupTitle` VARCHAR(255) NULL, + `lookupRefCode` VARCHAR(255) NULL, + `lookupValue` VARCHAR(255) NULL, + `lookupType` VARCHAR(255) NULL, + `lookupStatus` VARCHAR(255) NULL, + `lookupCreatedDate` DATETIME(0) NULL, + `lookupModifiedDate` DATETIME(0) NULL, + + PRIMARY KEY (`lookupID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `userrole` ( + `userRoleID` INTEGER NOT NULL AUTO_INCREMENT, + `userRoleUserID` INTEGER NOT NULL DEFAULT 0, + `userRoleRoleID` INTEGER NOT NULL DEFAULT 0, + `userRoleCreatedDate` DATETIME(0) NOT NULL, + + INDEX `FK_userrole_role`(`userRoleRoleID`), + INDEX `FK_userrole_user`(`userRoleUserID`), + PRIMARY KEY (`userRoleID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `userrole` ADD CONSTRAINT `FK_userrole_role` FOREIGN KEY (`userRoleRoleID`) REFERENCES `role`(`roleID`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- AddForeignKey +ALTER TABLE `userrole` ADD CONSTRAINT `FK_userrole_user` FOREIGN KEY (`userRoleUserID`) REFERENCES `user`(`userID`) ON DELETE NO ACTION ON UPDATE NO ACTION; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..e5a788a --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "mysql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..8a63dd7 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,70 @@ +generator client { + provider = "prisma-client-js" +} + +generator jsonSchema { + provider = "prisma-json-schema-generator" + output = "./json" +} + +datasource db { + provider = "mysql" + url = env("DATABASE_URL") +} + +model audit { + auditID Int @id @default(autoincrement()) + auditIP String? @db.VarChar(255) + auditURL String? @db.VarChar(255) + auditURLMethod String? @db.VarChar(255) + auditURLPayload String? @db.VarChar(255) + auditCreatedDate DateTime? @db.DateTime(0) +} + +model user { + userID Int @id @default(autoincrement()) + userSecretKey String? @db.VarChar(255) + userUsername String? @db.VarChar(255) + userPassword String? @db.VarChar(255) + userFullName String? @db.VarChar(255) + userEmail String? @db.VarChar(255) + userPhone String? @db.VarChar(255) + userStatus String? @db.VarChar(255) + userCreatedDate DateTime? @db.DateTime(0) + userModifiedDate DateTime? @db.DateTime(0) + userrole userrole[] +} + +model role { + roleID Int @id @default(autoincrement()) + roleName String? @db.VarChar(255) + roleDescription String? @db.VarChar(255) + roleStatus String? @db.VarChar(255) + roleCreatedDate DateTime? @db.DateTime(0) + roleModifiedDate DateTime? @db.DateTime(0) + userrole userrole[] +} + +model lookup { + lookupID Int @id @default(autoincrement()) + lookupOrder Int? + lookupTitle String? @db.VarChar(255) + lookupRefCode String? @db.VarChar(255) + lookupValue String? @db.VarChar(255) + lookupType String? @db.VarChar(255) + lookupStatus String? @db.VarChar(255) + lookupCreatedDate DateTime? @db.DateTime(0) + lookupModifiedDate DateTime? @db.DateTime(0) +} + +model userrole { + userRoleID Int @id @default(autoincrement()) + userRoleUserID Int @default(0) + userRoleRoleID Int @default(0) + userRoleCreatedDate DateTime @db.DateTime(0) + role role @relation(fields: [userRoleRoleID], references: [roleID], onDelete: NoAction, onUpdate: NoAction, map: "FK_userrole_role") + user user @relation(fields: [userRoleUserID], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "FK_userrole_user") + + @@index([userRoleRoleID], map: "FK_userrole_role") + @@index([userRoleUserID], map: "FK_userrole_user") +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..f544b53 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/icons/android/android-launchericon-144-144.png b/public/icons/android/android-launchericon-144-144.png new file mode 100644 index 0000000..d1745df Binary files /dev/null and b/public/icons/android/android-launchericon-144-144.png differ diff --git a/public/icons/android/android-launchericon-192-192.png b/public/icons/android/android-launchericon-192-192.png new file mode 100644 index 0000000..c658e96 Binary files /dev/null and b/public/icons/android/android-launchericon-192-192.png differ diff --git a/public/icons/android/android-launchericon-48-48.png b/public/icons/android/android-launchericon-48-48.png new file mode 100644 index 0000000..94789a3 Binary files /dev/null and b/public/icons/android/android-launchericon-48-48.png differ diff --git a/public/icons/android/android-launchericon-512-512.png b/public/icons/android/android-launchericon-512-512.png new file mode 100644 index 0000000..0f32288 Binary files /dev/null and b/public/icons/android/android-launchericon-512-512.png differ diff --git a/public/icons/android/android-launchericon-72-72.png b/public/icons/android/android-launchericon-72-72.png new file mode 100644 index 0000000..874557d Binary files /dev/null and b/public/icons/android/android-launchericon-72-72.png differ diff --git a/public/icons/android/android-launchericon-96-96.png b/public/icons/android/android-launchericon-96-96.png new file mode 100644 index 0000000..33e573a Binary files /dev/null and b/public/icons/android/android-launchericon-96-96.png differ diff --git a/public/icons/ios/100.png b/public/icons/ios/100.png new file mode 100644 index 0000000..f72f31c Binary files /dev/null and b/public/icons/ios/100.png differ diff --git a/public/icons/ios/1024.png b/public/icons/ios/1024.png new file mode 100644 index 0000000..7316ff7 Binary files /dev/null and b/public/icons/ios/1024.png differ diff --git a/public/icons/ios/114.png b/public/icons/ios/114.png new file mode 100644 index 0000000..a58d8d8 Binary files /dev/null and b/public/icons/ios/114.png differ diff --git a/public/icons/ios/120.png b/public/icons/ios/120.png new file mode 100644 index 0000000..a624062 Binary files /dev/null and b/public/icons/ios/120.png differ diff --git a/public/icons/ios/128.png b/public/icons/ios/128.png new file mode 100644 index 0000000..8dc9761 Binary files /dev/null and b/public/icons/ios/128.png differ diff --git a/public/icons/ios/144.png b/public/icons/ios/144.png new file mode 100644 index 0000000..d1745df Binary files /dev/null and b/public/icons/ios/144.png differ diff --git a/public/icons/ios/152.png b/public/icons/ios/152.png new file mode 100644 index 0000000..8a8d828 Binary files /dev/null and b/public/icons/ios/152.png differ diff --git a/public/icons/ios/16.png b/public/icons/ios/16.png new file mode 100644 index 0000000..bf1e8dc Binary files /dev/null and b/public/icons/ios/16.png differ diff --git a/public/icons/ios/167.png b/public/icons/ios/167.png new file mode 100644 index 0000000..557eab1 Binary files /dev/null and b/public/icons/ios/167.png differ diff --git a/public/icons/ios/180.png b/public/icons/ios/180.png new file mode 100644 index 0000000..1221b67 Binary files /dev/null and b/public/icons/ios/180.png differ diff --git a/public/icons/ios/192.png b/public/icons/ios/192.png new file mode 100644 index 0000000..c658e96 Binary files /dev/null and b/public/icons/ios/192.png differ diff --git a/public/icons/ios/20.png b/public/icons/ios/20.png new file mode 100644 index 0000000..1e94680 Binary files /dev/null and b/public/icons/ios/20.png differ diff --git a/public/icons/ios/256.png b/public/icons/ios/256.png new file mode 100644 index 0000000..191ff36 Binary files /dev/null and b/public/icons/ios/256.png differ diff --git a/public/icons/ios/29.png b/public/icons/ios/29.png new file mode 100644 index 0000000..66f379c Binary files /dev/null and b/public/icons/ios/29.png differ diff --git a/public/icons/ios/32.png b/public/icons/ios/32.png new file mode 100644 index 0000000..eeeb3f8 Binary files /dev/null and b/public/icons/ios/32.png differ diff --git a/public/icons/ios/40.png b/public/icons/ios/40.png new file mode 100644 index 0000000..b26761b Binary files /dev/null and b/public/icons/ios/40.png differ diff --git a/public/icons/ios/50.png b/public/icons/ios/50.png new file mode 100644 index 0000000..555d6ed Binary files /dev/null and b/public/icons/ios/50.png differ diff --git a/public/icons/ios/512.png b/public/icons/ios/512.png new file mode 100644 index 0000000..0f32288 Binary files /dev/null and b/public/icons/ios/512.png differ diff --git a/public/icons/ios/57.png b/public/icons/ios/57.png new file mode 100644 index 0000000..a014f64 Binary files /dev/null and b/public/icons/ios/57.png differ diff --git a/public/icons/ios/58.png b/public/icons/ios/58.png new file mode 100644 index 0000000..abf29d3 Binary files /dev/null and b/public/icons/ios/58.png differ diff --git a/public/icons/ios/60.png b/public/icons/ios/60.png new file mode 100644 index 0000000..972dfb1 Binary files /dev/null and b/public/icons/ios/60.png differ diff --git a/public/icons/ios/64.png b/public/icons/ios/64.png new file mode 100644 index 0000000..5d3034c Binary files /dev/null and b/public/icons/ios/64.png differ diff --git a/public/icons/ios/72.png b/public/icons/ios/72.png new file mode 100644 index 0000000..874557d Binary files /dev/null and b/public/icons/ios/72.png differ diff --git a/public/icons/ios/76.png b/public/icons/ios/76.png new file mode 100644 index 0000000..9f0b0cf Binary files /dev/null and b/public/icons/ios/76.png differ diff --git a/public/icons/ios/80.png b/public/icons/ios/80.png new file mode 100644 index 0000000..c65629c Binary files /dev/null and b/public/icons/ios/80.png differ diff --git a/public/icons/ios/87.png b/public/icons/ios/87.png new file mode 100644 index 0000000..f6e49b3 Binary files /dev/null and b/public/icons/ios/87.png differ diff --git a/public/icons/windows11/LargeTile.scale-100.png b/public/icons/windows11/LargeTile.scale-100.png new file mode 100644 index 0000000..a8fa884 Binary files /dev/null and b/public/icons/windows11/LargeTile.scale-100.png differ diff --git a/public/icons/windows11/LargeTile.scale-125.png b/public/icons/windows11/LargeTile.scale-125.png new file mode 100644 index 0000000..bf7b6a7 Binary files /dev/null and b/public/icons/windows11/LargeTile.scale-125.png differ diff --git a/public/icons/windows11/LargeTile.scale-150.png b/public/icons/windows11/LargeTile.scale-150.png new file mode 100644 index 0000000..e539dec Binary files /dev/null and b/public/icons/windows11/LargeTile.scale-150.png differ diff --git a/public/icons/windows11/LargeTile.scale-200.png b/public/icons/windows11/LargeTile.scale-200.png new file mode 100644 index 0000000..9014e81 Binary files /dev/null and b/public/icons/windows11/LargeTile.scale-200.png differ diff --git a/public/icons/windows11/LargeTile.scale-400.png b/public/icons/windows11/LargeTile.scale-400.png new file mode 100644 index 0000000..4a8f5f3 Binary files /dev/null and b/public/icons/windows11/LargeTile.scale-400.png differ diff --git a/public/icons/windows11/SmallTile.scale-100.png b/public/icons/windows11/SmallTile.scale-100.png new file mode 100644 index 0000000..f7fafd3 Binary files /dev/null and b/public/icons/windows11/SmallTile.scale-100.png differ diff --git a/public/icons/windows11/SmallTile.scale-125.png b/public/icons/windows11/SmallTile.scale-125.png new file mode 100644 index 0000000..601b774 Binary files /dev/null and b/public/icons/windows11/SmallTile.scale-125.png differ diff --git a/public/icons/windows11/SmallTile.scale-150.png b/public/icons/windows11/SmallTile.scale-150.png new file mode 100644 index 0000000..9b3edad Binary files /dev/null and b/public/icons/windows11/SmallTile.scale-150.png differ diff --git a/public/icons/windows11/SmallTile.scale-200.png b/public/icons/windows11/SmallTile.scale-200.png new file mode 100644 index 0000000..f28a5e2 Binary files /dev/null and b/public/icons/windows11/SmallTile.scale-200.png differ diff --git a/public/icons/windows11/SmallTile.scale-400.png b/public/icons/windows11/SmallTile.scale-400.png new file mode 100644 index 0000000..b94a642 Binary files /dev/null and b/public/icons/windows11/SmallTile.scale-400.png differ diff --git a/public/icons/windows11/SplashScreen.scale-100.png b/public/icons/windows11/SplashScreen.scale-100.png new file mode 100644 index 0000000..5f4626d Binary files /dev/null and b/public/icons/windows11/SplashScreen.scale-100.png differ diff --git a/public/icons/windows11/SplashScreen.scale-125.png b/public/icons/windows11/SplashScreen.scale-125.png new file mode 100644 index 0000000..a1e00a6 Binary files /dev/null and b/public/icons/windows11/SplashScreen.scale-125.png differ diff --git a/public/icons/windows11/SplashScreen.scale-150.png b/public/icons/windows11/SplashScreen.scale-150.png new file mode 100644 index 0000000..1a8c6b6 Binary files /dev/null and b/public/icons/windows11/SplashScreen.scale-150.png differ diff --git a/public/icons/windows11/SplashScreen.scale-200.png b/public/icons/windows11/SplashScreen.scale-200.png new file mode 100644 index 0000000..741809a Binary files /dev/null and b/public/icons/windows11/SplashScreen.scale-200.png differ diff --git a/public/icons/windows11/SplashScreen.scale-400.png b/public/icons/windows11/SplashScreen.scale-400.png new file mode 100644 index 0000000..dd84d5b Binary files /dev/null and b/public/icons/windows11/SplashScreen.scale-400.png differ diff --git a/public/icons/windows11/Square150x150Logo.scale-100.png b/public/icons/windows11/Square150x150Logo.scale-100.png new file mode 100644 index 0000000..71ac343 Binary files /dev/null and b/public/icons/windows11/Square150x150Logo.scale-100.png differ diff --git a/public/icons/windows11/Square150x150Logo.scale-125.png b/public/icons/windows11/Square150x150Logo.scale-125.png new file mode 100644 index 0000000..4f6ee48 Binary files /dev/null and b/public/icons/windows11/Square150x150Logo.scale-125.png differ diff --git a/public/icons/windows11/Square150x150Logo.scale-150.png b/public/icons/windows11/Square150x150Logo.scale-150.png new file mode 100644 index 0000000..f4944fa Binary files /dev/null and b/public/icons/windows11/Square150x150Logo.scale-150.png differ diff --git a/public/icons/windows11/Square150x150Logo.scale-200.png b/public/icons/windows11/Square150x150Logo.scale-200.png new file mode 100644 index 0000000..26d3bc0 Binary files /dev/null and b/public/icons/windows11/Square150x150Logo.scale-200.png differ diff --git a/public/icons/windows11/Square150x150Logo.scale-400.png b/public/icons/windows11/Square150x150Logo.scale-400.png new file mode 100644 index 0000000..1398d62 Binary files /dev/null and b/public/icons/windows11/Square150x150Logo.scale-400.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png new file mode 100644 index 0000000..367fc8d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png new file mode 100644 index 0000000..56f7b65 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png new file mode 100644 index 0000000..13a7348 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png new file mode 100644 index 0000000..53b4463 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png new file mode 100644 index 0000000..c8081cd Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png new file mode 100644 index 0000000..b4d7faa Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png new file mode 100644 index 0000000..7dc7f30 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png new file mode 100644 index 0000000..90bc051 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png new file mode 100644 index 0000000..340fd9e Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png new file mode 100644 index 0000000..cf3a14d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png new file mode 100644 index 0000000..cc5e37d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png new file mode 100644 index 0000000..ae2282a Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png new file mode 100644 index 0000000..b97a6ae Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png new file mode 100644 index 0000000..3962cca Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png new file mode 100644 index 0000000..8ccbb27 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-16.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-16.png new file mode 100644 index 0000000..367fc8d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-16.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-20.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-20.png new file mode 100644 index 0000000..56f7b65 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-20.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-24.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-24.png new file mode 100644 index 0000000..13a7348 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-24.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-256.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-256.png new file mode 100644 index 0000000..53b4463 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-256.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-30.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-30.png new file mode 100644 index 0000000..c8081cd Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-30.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-32.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-32.png new file mode 100644 index 0000000..b4d7faa Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-32.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-36.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-36.png new file mode 100644 index 0000000..7dc7f30 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-36.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-40.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-40.png new file mode 100644 index 0000000..90bc051 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-40.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-44.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-44.png new file mode 100644 index 0000000..340fd9e Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-44.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-48.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-48.png new file mode 100644 index 0000000..cf3a14d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-48.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-60.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-60.png new file mode 100644 index 0000000..cc5e37d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-60.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-64.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-64.png new file mode 100644 index 0000000..ae2282a Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-64.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-72.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-72.png new file mode 100644 index 0000000..b97a6ae Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-72.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-80.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-80.png new file mode 100644 index 0000000..3962cca Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-80.png differ diff --git a/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-96.png b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-96.png new file mode 100644 index 0000000..8ccbb27 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.altform-unplated_targetsize-96.png differ diff --git a/public/icons/windows11/Square44x44Logo.scale-100.png b/public/icons/windows11/Square44x44Logo.scale-100.png new file mode 100644 index 0000000..340fd9e Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.scale-100.png differ diff --git a/public/icons/windows11/Square44x44Logo.scale-125.png b/public/icons/windows11/Square44x44Logo.scale-125.png new file mode 100644 index 0000000..78fbfbd Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.scale-125.png differ diff --git a/public/icons/windows11/Square44x44Logo.scale-150.png b/public/icons/windows11/Square44x44Logo.scale-150.png new file mode 100644 index 0000000..e18f5e6 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.scale-150.png differ diff --git a/public/icons/windows11/Square44x44Logo.scale-200.png b/public/icons/windows11/Square44x44Logo.scale-200.png new file mode 100644 index 0000000..5240c8e Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.scale-200.png differ diff --git a/public/icons/windows11/Square44x44Logo.scale-400.png b/public/icons/windows11/Square44x44Logo.scale-400.png new file mode 100644 index 0000000..42b2456 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.scale-400.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-16.png b/public/icons/windows11/Square44x44Logo.targetsize-16.png new file mode 100644 index 0000000..367fc8d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-16.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-20.png b/public/icons/windows11/Square44x44Logo.targetsize-20.png new file mode 100644 index 0000000..56f7b65 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-20.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-24.png b/public/icons/windows11/Square44x44Logo.targetsize-24.png new file mode 100644 index 0000000..13a7348 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-24.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-256.png b/public/icons/windows11/Square44x44Logo.targetsize-256.png new file mode 100644 index 0000000..53b4463 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-256.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-30.png b/public/icons/windows11/Square44x44Logo.targetsize-30.png new file mode 100644 index 0000000..c8081cd Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-30.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-32.png b/public/icons/windows11/Square44x44Logo.targetsize-32.png new file mode 100644 index 0000000..b4d7faa Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-32.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-36.png b/public/icons/windows11/Square44x44Logo.targetsize-36.png new file mode 100644 index 0000000..7dc7f30 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-36.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-40.png b/public/icons/windows11/Square44x44Logo.targetsize-40.png new file mode 100644 index 0000000..90bc051 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-40.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-44.png b/public/icons/windows11/Square44x44Logo.targetsize-44.png new file mode 100644 index 0000000..340fd9e Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-44.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-48.png b/public/icons/windows11/Square44x44Logo.targetsize-48.png new file mode 100644 index 0000000..cf3a14d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-48.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-60.png b/public/icons/windows11/Square44x44Logo.targetsize-60.png new file mode 100644 index 0000000..cc5e37d Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-60.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-64.png b/public/icons/windows11/Square44x44Logo.targetsize-64.png new file mode 100644 index 0000000..ae2282a Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-64.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-72.png b/public/icons/windows11/Square44x44Logo.targetsize-72.png new file mode 100644 index 0000000..b97a6ae Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-72.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-80.png b/public/icons/windows11/Square44x44Logo.targetsize-80.png new file mode 100644 index 0000000..3962cca Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-80.png differ diff --git a/public/icons/windows11/Square44x44Logo.targetsize-96.png b/public/icons/windows11/Square44x44Logo.targetsize-96.png new file mode 100644 index 0000000..8ccbb27 Binary files /dev/null and b/public/icons/windows11/Square44x44Logo.targetsize-96.png differ diff --git a/public/icons/windows11/StoreLogo.scale-100.png b/public/icons/windows11/StoreLogo.scale-100.png new file mode 100644 index 0000000..555d6ed Binary files /dev/null and b/public/icons/windows11/StoreLogo.scale-100.png differ diff --git a/public/icons/windows11/StoreLogo.scale-125.png b/public/icons/windows11/StoreLogo.scale-125.png new file mode 100644 index 0000000..10895f8 Binary files /dev/null and b/public/icons/windows11/StoreLogo.scale-125.png differ diff --git a/public/icons/windows11/StoreLogo.scale-150.png b/public/icons/windows11/StoreLogo.scale-150.png new file mode 100644 index 0000000..e02db47 Binary files /dev/null and b/public/icons/windows11/StoreLogo.scale-150.png differ diff --git a/public/icons/windows11/StoreLogo.scale-200.png b/public/icons/windows11/StoreLogo.scale-200.png new file mode 100644 index 0000000..f72f31c Binary files /dev/null and b/public/icons/windows11/StoreLogo.scale-200.png differ diff --git a/public/icons/windows11/StoreLogo.scale-400.png b/public/icons/windows11/StoreLogo.scale-400.png new file mode 100644 index 0000000..283f165 Binary files /dev/null and b/public/icons/windows11/StoreLogo.scale-400.png differ diff --git a/public/icons/windows11/Wide310x150Logo.scale-100.png b/public/icons/windows11/Wide310x150Logo.scale-100.png new file mode 100644 index 0000000..24f2702 Binary files /dev/null and b/public/icons/windows11/Wide310x150Logo.scale-100.png differ diff --git a/public/icons/windows11/Wide310x150Logo.scale-125.png b/public/icons/windows11/Wide310x150Logo.scale-125.png new file mode 100644 index 0000000..67f1006 Binary files /dev/null and b/public/icons/windows11/Wide310x150Logo.scale-125.png differ diff --git a/public/icons/windows11/Wide310x150Logo.scale-150.png b/public/icons/windows11/Wide310x150Logo.scale-150.png new file mode 100644 index 0000000..50f6e73 Binary files /dev/null and b/public/icons/windows11/Wide310x150Logo.scale-150.png differ diff --git a/public/icons/windows11/Wide310x150Logo.scale-200.png b/public/icons/windows11/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000..5f4626d Binary files /dev/null and b/public/icons/windows11/Wide310x150Logo.scale-200.png differ diff --git a/public/icons/windows11/Wide310x150Logo.scale-400.png b/public/icons/windows11/Wide310x150Logo.scale-400.png new file mode 100644 index 0000000..741809a Binary files /dev/null and b/public/icons/windows11/Wide310x150Logo.scale-400.png differ diff --git a/public/img/background/bg1.jpg b/public/img/background/bg1.jpg new file mode 100644 index 0000000..863c587 Binary files /dev/null and b/public/img/background/bg1.jpg differ diff --git a/public/img/background/bg2.jpg b/public/img/background/bg2.jpg new file mode 100644 index 0000000..09ca735 Binary files /dev/null and b/public/img/background/bg2.jpg differ diff --git a/public/img/template/form1.jpg b/public/img/template/form1.jpg new file mode 100644 index 0000000..754419c Binary files /dev/null and b/public/img/template/form1.jpg differ diff --git a/server/api/auth/login.post.js b/server/api/auth/login.post.js new file mode 100644 index 0000000..2a1d95f --- /dev/null +++ b/server/api/auth/login.post.js @@ -0,0 +1,93 @@ +import sha256 from "crypto-js/sha256.js"; +import jwt from "jsonwebtoken"; + +const ENV = useRuntimeConfig(); + +export default defineEventHandler(async (event) => { + try { + const { username, password } = await readBody(event); + + if (!username || !password) { + return { + statusCode: 400, + message: "Username and password are required", + }; + } + + const user = await prisma.user.findFirst({ + where: { + userUsername: username, + }, + }); + + if (!user) { + return { + statusCode: 404, + message: "User does not exist", + }; + } + + const hashedPassword = sha256(password).toString(); + if (user.userPassword !== hashedPassword) { + return { + statusCode: 401, + message: "Invalid password", + }; + } + + // Get user roles + const roles = await prisma.userrole.findMany({ + where: { + userRoleUserID: user.userID, + }, + select: { + role: { + select: { + roleName: true, + }, + }, + }, + }); + + const roleNames = roles.map((r) => r.role.roleName); + + const accessToken = generateAccessToken({ + username: user.userUsername, + roles: roleNames, + }); + + const refreshToken = generateRefreshToken({ + username: user.userUsername, + roles: roleNames, + }); + + // Set cookie httpOnly + event.res.setHeader("Set-Cookie", [ + `accessToken=${accessToken}; HttpOnly; Secure; SameSite=Lax; Path=/`, + `refreshToken=${refreshToken}; HttpOnly; Secure; SameSite=Lax; Path=/`, + ]); + + return { + statusCode: 200, + message: "Login success", + data: { + username: user.userUsername, + roles: roleNames, + }, + }; + } catch (error) { + console.log(error); + return { + statusCode: 500, + message: "Internal server error", + }; + } +}); + +function generateAccessToken(user) { + return jwt.sign(user, ENV.auth.secretAccess, { expiresIn: "1d" }); +} + +function generateRefreshToken(user) { + return jwt.sign(user, ENV.auth.secretRefresh, { expiresIn: "30d" }); +} diff --git a/server/api/auth/logout.get.js b/server/api/auth/logout.get.js new file mode 100644 index 0000000..c7e14d1 --- /dev/null +++ b/server/api/auth/logout.get.js @@ -0,0 +1,19 @@ +export default defineEventHandler(async (event) => { + try { + event.res.setHeader("Set-Cookie", [ + `accessToken=; HttpOnly; Secure; SameSite=Lax; Path=/`, + `refreshToken=; HttpOnly; Secure; SameSite=Lax; Path=/`, + ]); + + return { + statusCode: 200, + message: "Logout success", + }; + } catch (error) { + console.log(error); + return { + statusCode: 400, + message: "Server error", + }; + } +}); diff --git a/server/api/auth/validate.get.js b/server/api/auth/validate.get.js new file mode 100644 index 0000000..a5014e9 --- /dev/null +++ b/server/api/auth/validate.get.js @@ -0,0 +1,34 @@ +export default defineEventHandler(async (event) => { + try { + const { userID } = event.context.user; + + if (userID == null) { + return { + statusCode: 401, + message: "Unauthorized", + }; + } + + const validatedUser = await prisma.user.findFirst({ + where: { + userID: parseInt(userID), + }, + }); + if (!validatedUser) { + return { + statusCode: 401, + message: "Unauthorized", + }; + } + + return { + statusCode: 200, + message: "Authorized", + }; + } catch (error) { + return { + statusCode: 401, + message: "Unauthorized", + }; + } +}); diff --git a/server/api/devtool/api/file-code.js b/server/api/devtool/api/file-code.js new file mode 100644 index 0000000..d2fbfe7 --- /dev/null +++ b/server/api/devtool/api/file-code.js @@ -0,0 +1,24 @@ +import fs from "fs"; +import path from "path"; + +export default defineEventHandler(async (event) => { + const query = await getQuery(event); + + try { + // Get vue code from path in query + const filePath = path.join(process.cwd() + "/server/", query.path + ".js"); + const code = fs.readFileSync(filePath, "utf8"); + + return { + statusCode: 200, + message: "Code successfully loaded", + data: code, + }; + } catch (error) { + // console.log(error); + return { + statusCode: 500, + message: "File not found", + }; + } +}); diff --git a/server/api/devtool/api/linter.js b/server/api/devtool/api/linter.js new file mode 100644 index 0000000..32572eb --- /dev/null +++ b/server/api/devtool/api/linter.js @@ -0,0 +1,191 @@ +// import esline vue +import { ESLint } from "eslint"; + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + try { + if (body.code === undefined) { + return { + statusCode: 400, + message: "Bad Request", + }; + } + + // run linter + const code = body.code; + const validateNitroCode = (code) => { + // Check if this is a server route file + const isServerRoute = code.includes("defineEventHandler"); + + if (isServerRoute) { + let lineNumber = 1; + + // 1. Validate event handler structure + if (!code.includes("export default defineEventHandler")) { + throw { + message: + "Nitro route handlers must use 'export default defineEventHandler'", + line: 1, + column: 0, + }; + } + + // 2. Check for proper request handling + const hasRequestBody = code.includes("await readBody(event)"); + const hasRequestQuery = code.includes("getQuery(event)"); + const usesEventWithoutImport = + code.includes("event.") && !hasRequestBody && !hasRequestQuery; + + if (usesEventWithoutImport) { + // Find the line where event is improperly used + const lines = code.split("\n"); + for (let i = 0; i < lines.length; i++) { + if ( + lines[i].includes("event.") && + !lines[i].includes("readBody") && + !lines[i].includes("getQuery") + ) { + throw { + message: + "Use 'readBody(event)' for POST data or 'getQuery(event)' for query parameters", + line: i + 1, + column: lines[i].indexOf("event."), + }; + } + } + } + + // 3. Validate response structure + const responseRegex = /return\s+{([^}]+)}/g; + let match; + let lastIndex = 0; + + while ((match = responseRegex.exec(code)) !== null) { + lineNumber += (code.slice(lastIndex, match.index).match(/\n/g) || []) + .length; + lastIndex = match.index; + + const responseContent = match[1]; + + // Check for required response properties + if (!responseContent.includes("statusCode")) { + throw { + message: "API responses must include a 'statusCode' property", + line: lineNumber, + column: match.index - code.lastIndexOf("\n", match.index), + }; + } + + // Validate status code usage + const statusMatch = responseContent.match(/statusCode:\s*(\d+)/); + if (statusMatch) { + const statusCode = parseInt(statusMatch[1]); + if (![200, 201, 400, 401, 403, 404, 500].includes(statusCode)) { + throw { + message: `Invalid status code: ${statusCode}. Use standard HTTP status codes.`, + line: lineNumber, + column: statusMatch.index, + }; + } + } + } + + // 4. Check error handling + if (code.includes("try") && !code.includes("catch")) { + throw { + message: + "Missing error handling. Add a catch block for try statements.", + line: + code.split("\n").findIndex((line) => line.includes("try")) + 1, + column: 0, + }; + } + + // 5. Validate async/await usage + const asyncLines = code.match(/async.*=>/g) || []; + const awaitLines = code.match(/await\s+/g) || []; + + if (awaitLines.length > 0 && asyncLines.length === 0) { + throw { + message: "Using 'await' requires an async function", + line: + code.split("\n").findIndex((line) => line.includes("await")) + 1, + column: 0, + }; + } + + // // 6. Check for proper imports + // const requiredImports = new Set(); + // if (hasRequestBody) requiredImports.add("readBody"); + // if (hasRequestQuery) requiredImports.add("getQuery"); + + // const importLines = code.match(/import.*from/g) || []; + // requiredImports.forEach((imp) => { + // if (!importLines.some((line) => line.includes(imp))) { + // throw { + // message: `Missing import for '${imp}' utility`, + // line: 1, + // column: 0, + // }; + // } + // }); + } + }; + + try { + validateNitroCode(code); + + const eslint = new ESLint({ + overrideConfig: { + parser: "@babel/eslint-parser", + extends: ["@kiwicom"], + parserOptions: { + requireConfigFile: false, + ecmaVersion: 2020, + sourceType: "module", + }, + }, + useEslintrc: false, + }); + + const results = await eslint.lintText(code); + + if (results[0].messages.length > 0) { + const messages = results[0].messages[0]; + + if (messages.fatal === true) { + return { + statusCode: 400, + message: "Bad Linter Test", + data: messages, + }; + } + + return { + statusCode: 200, + message: "Good Linter test", + data: messages, + }; + } + } catch (error) { + console.log(error); + return { + statusCode: 400, + message: "Bad Linter Test", + data: { + message: error.message, + line: error.line || 1, + column: error.column || 0, + }, + }; + } + } catch (error) { + console.log(error); + return { + statusCode: 500, + message: "Internal Server Error", + errror: error, + }; + } +}); diff --git a/server/api/devtool/api/list.js b/server/api/devtool/api/list.js new file mode 100644 index 0000000..903ff37 --- /dev/null +++ b/server/api/devtool/api/list.js @@ -0,0 +1,77 @@ +import fs from "fs"; +import path from "path"; + +export default defineEventHandler(async (event) => { + try { + // get api folder path from server root folder and its files and folders inside it + const apiFolderPath = path.join(process.cwd() + "/server/api"); + const apis = fs.readdirSync(apiFolderPath); + + const apiList = getFilesAndFolders(apiFolderPath); + + const apiUrls = getApiUrls(apiList); + const jsonObject = JSON.parse(JSON.stringify(apiUrls)); + + return { + statusCode: 200, + message: "API List successfully fetched", + data: jsonObject, + }; + } catch (error) { + return { + statusCode: 500, + message: error.message, + }; + } +}); + +function getFilesAndFolders(folderPath) { + const folderFiles = fs.readdirSync(folderPath); + const files = []; + const folders = []; + const apiURL = "/api"; + + folderFiles.forEach((file) => { + const filePath = path.join(folderPath + "/" + file); + if (file == "devtool") return; + if (fs.lstatSync(filePath).isDirectory()) { + folders.push(getFilesAndFolders(filePath)); + } else { + const processPath = path.join(process.cwd() + "/server/api"); + const apiUrl = filePath + .replace(processPath, apiURL) + .replace(/\\/g, "/") + .replace(".js", ""); + const fileName = file.replace(".js", ""); + const parentFolder = folderPath + .replace(processPath, "") + .replace(/\\/g, ""); + + files.push({ + name: fileName, + parentName: parentFolder, + url: apiUrl, + }); + } + }); + + return { files, folders }; +} + +function getApiUrls(folder) { + const apiUrls = []; + + folder.files.forEach((file) => { + apiUrls.push({ + name: file.name, + parentName: file.parentName, + url: file.url, + }); + }); + + folder.folders.forEach((nestedFolder) => { + apiUrls.push(...getApiUrls(nestedFolder)); + }); + + return apiUrls; +} diff --git a/server/api/devtool/api/prettier-format.js b/server/api/devtool/api/prettier-format.js new file mode 100644 index 0000000..f8f4bb2 --- /dev/null +++ b/server/api/devtool/api/prettier-format.js @@ -0,0 +1,27 @@ +import prettier from "prettier"; + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + try { + if (body.code === undefined) { + return { + statusCode: 400, + message: "Bad Request", + }; + } + + const code = prettier.format(body.code, { semi: false, parser: "babel" }); + + return { + statusCode: 200, + message: "Code successfully formatted", + data: code, + }; + } catch (error) { + return { + statusCode: 500, + message: "Internal Server Error", + }; + } +}); diff --git a/server/api/devtool/api/save.js b/server/api/devtool/api/save.js new file mode 100644 index 0000000..567ff59 --- /dev/null +++ b/server/api/devtool/api/save.js @@ -0,0 +1,71 @@ +import fs from "fs"; +import path from "path"; + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + try { + const codeDefault = ` + export default defineEventHandler(async (event) => { + + // const query = await getQuery(event); // Get Params from URL + // const body = await readBody(event); // Get Body Data + + return { + statusCode: 200, + message: "API Route Created", + }; + + });`; + + // Overwrite vue code from path in body with new code + const filePath = path.join(process.cwd() + "/server/", body.path + ".js"); + + if (body.type == "update") { + fs.writeFileSync(filePath, body.code, "utf8"); + } else if (body.type == "add") { + // if the folder doesn't exist, create it + if (!fs.existsSync(path.dirname(filePath))) { + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + } + + fs.writeFileSync(filePath, codeDefault, "utf8"); + } else if (body.type == "edit") { + // if the folder doesn't exist, create it + if (!fs.existsSync(path.dirname(filePath))) { + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + } + + // Copy the file from the default path to the new path + const oldPath = path.join( + process.cwd() + "/server/", + body.oldPath + ".js" + ); + + // Copy file + fs.copyFileSync(oldPath, filePath); + + // Delete old file + fs.unlinkSync(oldPath); + } else if (body.type == "delete") { + // Delete file from path + fs.unlinkSync(filePath); + + return { + statusCode: 200, + message: "Code successfully deleted", + }; + } + + return { + statusCode: 200, + message: "Code successfully saved", + }; + } catch (error) { + console.log(error); + return { + statusCode: 500, + message: "Internal Server Error", + }; + } +}); diff --git a/server/api/devtool/config/env.js b/server/api/devtool/config/env.js new file mode 100644 index 0000000..557c0c9 --- /dev/null +++ b/server/api/devtool/config/env.js @@ -0,0 +1,22 @@ +import fs from "fs"; +import path from "path"; + +export default defineEventHandler(async (event) => { + // Get .env file, parse and return + const envFile = path.join(process.cwd(), ".env"); + + if (!fs.existsSync(envFile)) { + return { + statusCode: 404, + message: "File not found", + }; + } + + const env = fs.readFileSync(envFile, "utf-8"); + + return { + statusCode: 200, + message: "Success", + data: env, + }; +}); diff --git a/server/api/devtool/content/canvas/file-code.js b/server/api/devtool/content/canvas/file-code.js new file mode 100644 index 0000000..7a01349 --- /dev/null +++ b/server/api/devtool/content/canvas/file-code.js @@ -0,0 +1,48 @@ +import fs from "fs"; +import path from "path"; + +export default defineEventHandler(async (event) => { + const query = await getQuery(event); + + let code = ""; + // console.log(query.path); + + try { + // Get vue code from path in query + const filePath = path.join(process.cwd() + "/pages/", query.path + ".vue"); + try { + code = fs.readFileSync(filePath, "utf8"); + return { + statusCode: 200, + message: "Code successfully loaded", + data: code, + }; + } catch (error) {} + + // Check if there is path with index.vue + const filePathIndex = path.join( + process.cwd() + "/pages/", + query.path + "/index.vue" + ); + + code = fs.readFileSync(filePathIndex, "utf8"); + + // Only get the template part of the code and make sure its from the first template tag to the last template tag + code = code.substring( + code.indexOf("") + ); + + return { + statusCode: 200, + message: "Code successfully loaded", + data: code, + mode: "index", + }; + } catch (error) { + return { + statusCode: 500, + message: "File not found", + }; + } +}); diff --git a/server/api/devtool/content/code/file-code.js b/server/api/devtool/content/code/file-code.js new file mode 100644 index 0000000..84b752c --- /dev/null +++ b/server/api/devtool/content/code/file-code.js @@ -0,0 +1,42 @@ +import fs from "fs"; +import path from "path"; + +export default defineEventHandler(async (event) => { + const query = await getQuery(event); + + let code = ""; + // console.log(query.path); + + try { + // Get vue code from path in query + const filePath = path.join(process.cwd() + "/pages/", query.path + ".vue"); + try { + code = fs.readFileSync(filePath, "utf8"); + return { + statusCode: 200, + message: "Code successfully loaded", + data: code, + }; + } catch (error) {} + + // Check if there is path with index.vue + const filePathIndex = path.join( + process.cwd() + "/pages/", + query.path + "/index.vue" + ); + + code = fs.readFileSync(filePathIndex, "utf8"); + + return { + statusCode: 200, + message: "Code successfully loaded", + data: code, + mode: "index", + }; + } catch (error) { + return { + statusCode: 500, + message: "File not found", + }; + } +}); diff --git a/server/api/devtool/content/code/linter.js b/server/api/devtool/content/code/linter.js new file mode 100644 index 0000000..ad0f4b9 --- /dev/null +++ b/server/api/devtool/content/code/linter.js @@ -0,0 +1,433 @@ +import { ESLint } from "eslint"; + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + try { + if (body.code === undefined) { + return { + statusCode: 400, + message: "Bad Request", + }; + } + + const code = body.code; + + // Extract script and template content once + const scriptContent = + code.match(/]*>([\s\S]*?)<\/script>/)?.[1] || ""; + const templateContent = code.match(/