├── .npmrc ├── public ├── robots.txt ├── icon.png ├── favicon.ico ├── starter.png └── icons │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── pwa-192x192.png │ ├── pwa-512x512.png │ ├── apple-touch-icon.png │ ├── pwa-maskable-192x192.png │ └── pwa-maskable-512x512.png ├── tsconfig.json ├── app.vue ├── layouts └── default.vue ├── .prettierrc ├── .github └── dependabot.yml ├── utils ├── defaults.ts ├── themes.ts ├── customIcons.ts ├── fluentIcons.ts └── tw-colors.ts ├── composables └── rules.ts ├── plugins └── vuetify.ts ├── package.json ├── LICENSE ├── pages ├── reset-password │ └── index.vue ├── index.vue └── signup │ └── index.vue ├── README.md ├── assets └── main.scss ├── nuxt.config.ts ├── .prettierignore └── .gitignore /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icon.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/starter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/starter.png -------------------------------------------------------------------------------- /public/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icons/favicon.ico -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://v3.nuxtjs.org/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /public/icons/pwa-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icons/pwa-192x192.png -------------------------------------------------------------------------------- /public/icons/pwa-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icons/pwa-512x512.png -------------------------------------------------------------------------------- /public/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /public/icons/pwa-maskable-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icons/pwa-maskable-192x192.png -------------------------------------------------------------------------------- /public/icons/pwa-maskable-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BayBreezy/nuxt3-vuetify3-starter/HEAD/public/icons/pwa-maskable-512x512.png -------------------------------------------------------------------------------- /app.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "endOfLine": "lf", 4 | "printWidth": 100, 5 | "semi": true, 6 | "singleQuote": false, 7 | "tabWidth": 2, 8 | "trailingComma": "es5", 9 | "useTabs": false 10 | } 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "npm" 7 | directories: 8 | - "/" 9 | schedule: 10 | interval: "weekly" 11 | day: "sunday" 12 | time: "06:00" 13 | timezone: "America/Jamaica" 14 | -------------------------------------------------------------------------------- /utils/defaults.ts: -------------------------------------------------------------------------------- 1 | import type { DefaultsInstance } from "vuetify"; 2 | 3 | /** 4 | * A few defaults that I like 5 | */ 6 | export const defaults: DefaultsInstance = { 7 | VAppBar: { 8 | elevation: 0, 9 | }, 10 | VBtn: { 11 | variant: "flat", 12 | height: 38, 13 | rounded: "lg", 14 | size: "small", 15 | }, 16 | VTextField: { 17 | color: "primary", 18 | variant: "outlined", 19 | density: "comfortable", 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /composables/rules.ts: -------------------------------------------------------------------------------- 1 | export const useFormRules = () => { 2 | return { 3 | ruleRequired: (v: any) => !!v || "Required", 4 | ruleEmail: (value: any) => { 5 | const pattern = 6 | /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 7 | return pattern.test(value) || "Enter a valid email"; 8 | }, 9 | rulePassLen: (v: string) => (!!v && v.length >= 6) || "Password must be 6 chars or more", 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /plugins/vuetify.ts: -------------------------------------------------------------------------------- 1 | import { createVuetify } from "vuetify"; 2 | 3 | export default defineNuxtPlugin((app) => { 4 | const vuetify = createVuetify({ 5 | ssr: true, 6 | defaults, 7 | // add theme 8 | theme: { 9 | defaultTheme: LIGHT_THEME, 10 | themes: { 11 | light, 12 | dark, 13 | }, 14 | // add color variations 15 | // variations: { 16 | // colors: ["primary", "secondary"], 17 | // lighten: 3, 18 | // darken: 3, 19 | // }, 20 | }, 21 | // Add the custom iconset 22 | icons: { 23 | defaultSet: "custom", 24 | aliases, 25 | sets: { 26 | custom, 27 | }, 28 | }, 29 | }); 30 | 31 | app.vueApp.use(vuetify); 32 | }); 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt3-vuetify3-starter", 3 | "private": false, 4 | "license": "MIT", 5 | "engines": { 6 | "node": ">=18.x" 7 | }, 8 | "scripts": { 9 | "build": "nuxt build", 10 | "dev": "nuxt dev", 11 | "generate": "nuxt generate", 12 | "reset": "rm -rf .nuxt node_modules .output package-lock.json && npm install", 13 | "preview": "nuxt preview", 14 | "postinstall": "nuxt prepare" 15 | }, 16 | "devDependencies": { 17 | "@iconify/vue": "^4.3.0", 18 | "@nuxtjs/google-fonts": "^3.2.0", 19 | "@vite-pwa/nuxt": "^0.10.6", 20 | "nuxt": "3.15.1", 21 | "sass": "^1.83.1", 22 | "vuetify": "^3.7.6" 23 | }, 24 | "dependencies": { 25 | "vite-plugin-vuetify": "^2.0.4", 26 | "vue": "latest", 27 | "vue-router": "latest" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /utils/themes.ts: -------------------------------------------------------------------------------- 1 | import type { ThemeDefinition } from "vuetify"; 2 | 3 | // String that represents the name of the theme I am using 4 | export const LIGHT_THEME = "light"; 5 | // Light mode theme 6 | export const light: ThemeDefinition = { 7 | dark: false, 8 | colors: { 9 | background: "#FFFFFF", 10 | surface: "#FFFFFF", 11 | primary: twColors.indigo[600], 12 | secondary: twColors.purple[600], 13 | error: twColors.red[500], 14 | info: twColors.blue[500], 15 | success: twColors.emerald[500], 16 | warning: twColors.amber[500], 17 | }, 18 | }; 19 | 20 | // String that represents the name of the dark theme I am using 21 | export const DARK_THEME = "dark"; 22 | // Dark mode theme 23 | export const dark: ThemeDefinition = { 24 | dark: true, 25 | colors: { 26 | background: twColors.slate[950], 27 | surface: twColors.slate[900], 28 | primary: twColors.indigo[500], 29 | secondary: twColors.purple[500], 30 | error: twColors.red[500], 31 | info: twColors.blue[500], 32 | success: twColors.emerald[500], 33 | warning: twColors.amber[500], 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Nuxt 3 - Vuetify 3 Starter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /utils/customIcons.ts: -------------------------------------------------------------------------------- 1 | import type { IconSet, IconAliases, IconProps } from "vuetify"; 2 | import { Icon } from "@iconify/vue"; 3 | 4 | const aliases: IconAliases = { 5 | collapse: "ph:caret-up", 6 | complete: "ph:check", 7 | cancel: "ph:x-circle", 8 | close: "ph:x", 9 | delete: "ph:trash", 10 | clear: "ph:x-circle", 11 | success: "ph:check-circle", 12 | info: "ph:info", 13 | warning: "ph:warning", 14 | error: "ph:x-circle", 15 | prev: "ph:caret-left", 16 | next: "ph:caret-right", 17 | checkboxOn: "ph:check-square-fill", 18 | checkboxOff: "ph:square", 19 | checkboxIndeterminate: "ph:square-logo-fill", 20 | delimiter: "ph:circle-fill", 21 | sort: "ph:arrows-down-up-fill", 22 | expand: "ph:caret-down", 23 | menu: "ph:list", 24 | subgroup: "ph:caret-down-fill", 25 | dropdown: "ph:caret-down-fill", 26 | radioOn: "ph:radio-button-fill", 27 | radioOff: "ph:circle", 28 | edit: "ph:note-pencil", 29 | ratingEmpty: "ph:star", 30 | ratingFull: "ph:star-fill", 31 | ratingHalf: "ph:star-half-fill", 32 | loading: "ph:spinner", 33 | first: "ph:caret-double-left-duotone", 34 | last: "ph:caret-double-right-duotone", 35 | unfold: "ph:arrows-down-up", 36 | file: "ph:paperclip", 37 | plus: "ph:plus", 38 | minus: "ph:minus", 39 | sortAsc: "ph:sort-ascending", 40 | sortDesc: "ph:sort-descending", 41 | calendar: "ph:calendar", 42 | }; 43 | 44 | const custom: IconSet = { 45 | // @ts-ignore 46 | component: (props: IconProps) => h(Icon, { ...props }), 47 | }; 48 | 49 | // export both aliases and the custom object created 50 | export { aliases, custom }; 51 | -------------------------------------------------------------------------------- /utils/fluentIcons.ts: -------------------------------------------------------------------------------- 1 | import type { IconSet, IconAliases, IconProps } from "vuetify"; 2 | import { Icon } from "@iconify/vue"; 3 | 4 | const fluentAliases: IconAliases = { 5 | collapse: "fluent:chevron-up-24-regular", 6 | complete: "fluent:checkmark-24-regular", 7 | cancel: "fluent:dismiss-circle-24-regular", 8 | close: "fluent:dismiss-24-regular", 9 | delete: "fluent:delete-24-regular", 10 | clear: "fluent:dismiss-circle-24-regular", 11 | success: "fluent:checkmark-circle-24-regular", 12 | info: "fluent:info-24-regular", 13 | warning: "fluent:warning-24-regular", 14 | error: "fluent:dismiss-circle-24-regular", 15 | prev: "fluent:chevron-left-24-regular", 16 | next: "fluent:chevron-right-24-regular", 17 | checkboxOn: "fluent:checkbox-checked-24-filled", 18 | checkboxOff: "fluent:square-24-regular", 19 | checkboxIndeterminate: "fluent:checkbox-indeterminate-24-regular", 20 | delimiter: "fluent:circle-24-filled", 21 | sort: "fluent:arrow-bidirectional-up-down-24-regular", 22 | expand: "fluent:chevron-down-24-regular", 23 | menu: "fluent:list-24-regular", 24 | subgroup: "fluent:caret-down-24-filled", 25 | dropdown: "fluent:caret-down-24-filled", 26 | radioOn: "fluent:radio-button-24-filled", 27 | radioOff: "fluent:radio-button-24-regular", 28 | edit: "fluent:pen-24-regular", 29 | ratingEmpty: "fluent:star-24-regular", 30 | ratingFull: "fluent:star-24-filled", 31 | ratingHalf: "fluent:star-half-24-regular", 32 | loading: "fluent:spinner-ios-20-regular", 33 | first: "fluent:chevron-double-left-20-regular", 34 | last: "fluent:chevron-double-right-20-regular", 35 | unfold: "fluent:chevron-up-down-24-regular", 36 | file: "fluent:attach-24-regular", 37 | plus: "fluent:add-24-regular", 38 | minus: "fluent:subtract-24-regular", 39 | sortAsc: "fluent:arrow-sort-up-24-regular", 40 | sortDesc: "fluent:arrow-sort-down-24-regular", 41 | calendar: "fluent:calendar-24-regular", 42 | }; 43 | 44 | const fluentCustom: IconSet = { 45 | // @ts-ignore 46 | component: (props: IconProps) => h(Icon, { ...props }), 47 | }; 48 | 49 | export { fluentAliases, fluentCustom }; 50 | -------------------------------------------------------------------------------- /pages/reset-password/index.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nuxt 3 + Vuetify 3 Starter 2 | 3 | ![Starter Image](/public/starter.png) 4 | Nuxt 3 is now stable. Vuetify 3 is now stable. I will be updating this template as we go along. Feel free to open an issue if you have any questions or suggestions. 5 | This template here will get you up & running with adding the two together :) 6 | 7 | ## Demo Here 8 | 9 | [Online Demo](https://vuetify3nuxt3starter.behonbaker.com) 10 | 11 | ## How to use 12 | 13 | As time passes, I will be updating this template. It will grow with some more pages. It all started with the login & register pages. I may keep a running list of pages added here. 14 | 15 | ### Pages 16 | 17 |
18 | Click to see the pages added & planned 19 | 20 | - [x] Login 21 | - [x] Register 22 | - [x] Reset Password 23 | 24 |
25 | 26 | ### Run the app 27 | 28 | 1. Install the deps 29 | 30 | ```bash 31 | npm install 32 | ``` 33 | 34 | 2. Run the app 35 | 36 | ```bash 37 | npm run dev 38 | ``` 39 | 40 | ### Stuff used 41 | 42 | - NuxtJS 43 | - Nuxt Icon 44 | - Sass 45 | - Vuetify 46 | - [@vite-pwa/nuxt](https://github.com/vite-pwa/nuxt) 47 | - Vite Plugin Vuetify 48 | 49 | ### Custom Sass File 50 | 51 | The `.scss` file that can be found in the `assets` folder have some gradients & other styles. They can be deleted or updated. 52 | 53 | ### ~~Helpers Folder~~ Utils Folder 54 | 55 | The ~~helper~~ utils folder contains the custom stuff for the Vuetify plugin 56 | 57 | #### Custom Icons - `customIcons.ts` 58 | 59 | So I switched from the nuxt-icon module to the @iconify/vue component [here](https://docs.iconify.design/icon-components/vue/). It plays better with Vuetify with custom icons 60 | 61 | Here is a link to the docs for this [Creating a custom iconset](https://next.vuetifyjs.com/en/features/icon-fonts/#creating-a-custom-icon-set) 62 | 63 | #### Global Defaults - `defaults.ts` 64 | 65 | This file here just set global props on different vuetify components. You can learn more here [Global Configuration](https://next.vuetifyjs.com/en/features/global-configuration/) 66 | 67 | #### Themes - `themes.ts` 68 | 69 | This file will hold all the different themes that you want to use in your app. Feel free to add more crazy schemes lol. Learn more here: [Vuetify Themes](https://next.vuetifyjs.com/en/features/theme/) 70 | 71 | #### Form Rules - Composable 72 | 73 | I added one composable for form rules. Add more here. You can even try integrating other validation packages like `yup` or `zod` 74 | 75 | #### Yup & Vee-Validate 76 | 77 | I will definitely be switching to vee-validate for dealing with forms. 78 | 79 | #### Icons 80 | 81 | The public folder contains a `favicon` & `icon`. Change these out for your app and be sure to tweak the pwa config inside the `nuxt.config` file to fit your app 82 | -------------------------------------------------------------------------------- /assets/main.scss: -------------------------------------------------------------------------------- 1 | $family: "Inter var", "Inter", apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, 2 | Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 3 | 4 | @use "vuetify" with ( 5 | $body-font-family: $family 6 | ); 7 | 8 | :root { 9 | font-family: "Inter", sans-serif; 10 | } 11 | @supports (font-variation-settings: normal) { 12 | :root { 13 | font-family: "Inter var", sans-serif; 14 | } 15 | } 16 | 17 | // Reset link styles 18 | a { 19 | color: inherit; 20 | text-decoration: none; 21 | } 22 | 23 | // Override the textfield's radius 24 | .v-text-field { 25 | .v-field__outline__start { 26 | border-radius: 10px 0 0 10px !important; 27 | } 28 | .v-field__outline__end { 29 | border-radius: 0 10px 10px 0 !important; 30 | } 31 | } 32 | 33 | .v-btn { 34 | font-weight: 700 !important; 35 | } 36 | .label { 37 | font-weight: 600; 38 | font-size: 15px; 39 | margin-bottom: 6px; 40 | display: inline-block; 41 | cursor: pointer; 42 | } 43 | // Theme gradients 44 | .gradient { 45 | &.primary { 46 | color: white; 47 | background: linear-gradient( 48 | 318deg, 49 | rgba(67, 56, 202, 1) 12%, 50 | rgba(79, 70, 229, 1) 38%, 51 | rgba(99, 102, 241, 1) 100% 52 | ) !important; 53 | } 54 | &.cancel { 55 | // color: #1e293b; 56 | background: linear-gradient( 57 | 318deg, 58 | rgba(203, 213, 225, 1) 12%, 59 | rgba(226, 232, 240, 1) 38%, 60 | rgba(241, 245, 249, 1) 100% 61 | ) !important; 62 | } 63 | &.success { 64 | color: white; 65 | background: linear-gradient( 66 | 318deg, 67 | rgba(21, 128, 61, 1) 12%, 68 | rgba(22, 163, 74, 1) 38%, 69 | rgba(34, 197, 94, 1) 100% 70 | ) !important; 71 | } 72 | &.info { 73 | color: white; 74 | background: linear-gradient( 75 | 318deg, 76 | rgba(30, 64, 175, 1) 12%, 77 | rgba(37, 99, 235, 1) 38%, 78 | rgba(59, 130, 246, 1) 100% 79 | ) !important; 80 | } 81 | &.warn { 82 | color: white; 83 | background: linear-gradient( 84 | 318deg, 85 | rgba(180, 83, 9, 1) 12%, 86 | rgba(217, 119, 6, 1) 38%, 87 | rgba(245, 158, 11, 1) 100% 88 | ) !important; 89 | } 90 | &.error { 91 | color: white; 92 | background: linear-gradient( 93 | 318deg, 94 | rgba(153, 27, 27, 1) 12%, 95 | rgba(220, 38, 38, 1) 38%, 96 | rgba(248, 113, 113, 1) 100% 97 | ) !important; 98 | } 99 | &.gray { 100 | color: white; 101 | background: linear-gradient( 102 | 318deg, 103 | rgba(30, 41, 59, 1) 12%, 104 | rgba(44, 55, 74, 1) 38%, 105 | rgba(71, 85, 105, 1) 100% 106 | ) !important; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 81 | -------------------------------------------------------------------------------- /pages/signup/index.vue: -------------------------------------------------------------------------------- 1 | 77 | 78 | 87 | -------------------------------------------------------------------------------- /nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import vuetify, { transformAssetUrls } from "vite-plugin-vuetify"; 2 | 3 | // PWA Config 4 | const title = "Vuetify 3 + Nuxt 3 Starter"; 5 | const shortTitle = "Vuetify 3 + Nuxt 3 Starter"; 6 | const description = "Template to get you up and running with Nuxt 3 & Vuetify 3"; 7 | const image = "https://vuetify3nuxt3starter.behonbaker.com/starter.png"; 8 | const url = "https://vuetify3nuxt3starter.behonbaker.com/"; 9 | const author = "Behon Baker"; 10 | const themeColor = "#4f46e5"; 11 | 12 | // https://v3.nuxtjs.org/api/configuration/nuxt.config 13 | export default defineNuxtConfig({ 14 | // import styles 15 | css: ["@/assets/main.scss"], 16 | 17 | devtools: { enabled: true }, 18 | 19 | // enable takeover mode 20 | typescript: { shim: false }, 21 | 22 | build: { transpile: ["vuetify"] }, 23 | 24 | // Based on docs found here - https://vuetifyjs.com/en/getting-started/installation/#using-nuxt-3 25 | vite: { 26 | vue: { 27 | template: { 28 | transformAssetUrls, 29 | }, 30 | }, 31 | }, 32 | 33 | modules: [ 34 | "@vite-pwa/nuxt", 35 | async (options, nuxt) => { 36 | nuxt.hooks.hook("vite:extendConfig", (config) => { 37 | config.plugins ||= []; 38 | config.plugins.push(vuetify()); 39 | }); 40 | }, 41 | ], 42 | 43 | app: { 44 | head: { 45 | title: "Vuetify 3 + Nuxt 3 Starter", 46 | titleTemplate: "%s | Vuetify 3 + Nuxt 3 Starter", 47 | link: [ 48 | { rel: "stylesheet", href: "https://rsms.me/inter/inter.css" }, 49 | { rel: "preconnect", href: "https://rsms.me/" }, 50 | { rel: "icon", type: "image/x-icon", href: "/favicon.ico" }, 51 | { rel: "canonical", href: url }, 52 | ], 53 | meta: [ 54 | { 55 | hid: "description", 56 | name: "description", 57 | content: description, 58 | }, 59 | { property: "og:site_name", content: title }, 60 | { hid: "og:type", property: "og:type", content: "website" }, 61 | { 62 | hid: "og:url", 63 | property: "og:url", 64 | content: url, 65 | }, 66 | { 67 | hid: "og:image:secure_url", 68 | property: "og:image:secure_url", 69 | content: image, 70 | }, 71 | { 72 | hid: "og:title", 73 | property: "og:title", 74 | content: title, 75 | }, 76 | { 77 | hid: "og:description", 78 | property: "og:description", 79 | content: description, 80 | }, 81 | { 82 | hid: "og:image", 83 | property: "og:image", 84 | content: image, 85 | }, 86 | //Twitter 87 | { name: "twitter:card", content: "summary_large_image" }, 88 | { 89 | hid: "twitter:url", 90 | name: "twitter:url", 91 | content: url, 92 | }, 93 | { 94 | hid: "twitter:title", 95 | name: "twitter:title", 96 | content: title, 97 | }, 98 | { 99 | hid: "twitter:description", 100 | name: "twitter:description", 101 | content: description, 102 | }, 103 | { 104 | hid: "twitter:image", 105 | name: "twitter:image", 106 | content: image, 107 | }, 108 | ], 109 | }, 110 | }, 111 | 112 | pwa: { 113 | includeAssets: ["favicon.ico", "robots.txt"], 114 | manifest: { 115 | name: shortTitle, 116 | short_name: shortTitle, 117 | description: description, 118 | theme_color: themeColor, 119 | lang: "en", 120 | background_color: "#ffffff", 121 | icons: [ 122 | { 123 | src: "/icons/pwa-192x192.png", 124 | sizes: "192x192", 125 | type: "image/png", 126 | purpose: "any", 127 | }, 128 | { 129 | src: "/icons/pwa-512x512.png", 130 | sizes: "512x512", 131 | type: "image/png", 132 | purpose: "any", 133 | }, 134 | { 135 | src: "/icons/pwa-maskable-192x192.png", 136 | sizes: "192x192", 137 | type: "image/png", 138 | purpose: "maskable", 139 | }, 140 | { 141 | src: "/icons/pwa-maskable-512x512.png", 142 | sizes: "512x512", 143 | type: "image/png", 144 | purpose: "maskable", 145 | }, 146 | ], 147 | }, 148 | }, 149 | 150 | compatibilityDate: "2024-07-15", 151 | }); -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,node,nuxtjs,windows 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,node,nuxtjs,windows 4 | 5 | ### macOS ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | 15 | # Thumbnails 16 | ._* 17 | 18 | # Files that might appear in the root of a volume 19 | .DocumentRevisions-V100 20 | .fseventsd 21 | .Spotlight-V100 22 | .TemporaryItems 23 | .Trashes 24 | .VolumeIcon.icns 25 | .com.apple.timemachine.donotpresent 26 | 27 | # Directories potentially created on remote AFP share 28 | .AppleDB 29 | .AppleDesktop 30 | Network Trash Folder 31 | Temporary Items 32 | .apdisk 33 | 34 | ### macOS Patch ### 35 | # iCloud generated files 36 | *.icloud 37 | 38 | ### Node ### 39 | # Logs 40 | logs 41 | *.log 42 | npm-debug.log* 43 | yarn-debug.log* 44 | yarn-error.log* 45 | lerna-debug.log* 46 | .pnpm-debug.log* 47 | 48 | # Diagnostic reports (https://nodejs.org/api/report.html) 49 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 50 | 51 | # Runtime data 52 | pids 53 | *.pid 54 | *.seed 55 | *.pid.lock 56 | 57 | # Directory for instrumented libs generated by jscoverage/JSCover 58 | lib-cov 59 | 60 | # Coverage directory used by tools like istanbul 61 | coverage 62 | *.lcov 63 | 64 | # nyc test coverage 65 | .nyc_output 66 | 67 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 68 | .grunt 69 | 70 | # Bower dependency directory (https://bower.io/) 71 | bower_components 72 | 73 | # node-waf configuration 74 | .lock-wscript 75 | 76 | # Compiled binary addons (https://nodejs.org/api/addons.html) 77 | build/Release 78 | 79 | # Dependency directories 80 | node_modules/ 81 | jspm_packages/ 82 | 83 | # Snowpack dependency directory (https://snowpack.dev/) 84 | web_modules/ 85 | 86 | # TypeScript cache 87 | *.tsbuildinfo 88 | 89 | # Optional npm cache directory 90 | .npm 91 | 92 | # Optional eslint cache 93 | .eslintcache 94 | 95 | # Optional stylelint cache 96 | .stylelintcache 97 | 98 | # Microbundle cache 99 | .rpt2_cache/ 100 | .rts2_cache_cjs/ 101 | .rts2_cache_es/ 102 | .rts2_cache_umd/ 103 | 104 | # Optional REPL history 105 | .node_repl_history 106 | 107 | # Output of 'npm pack' 108 | *.tgz 109 | 110 | # Yarn Integrity file 111 | .yarn-integrity 112 | 113 | # dotenv environment variable files 114 | .env 115 | .env.development.local 116 | .env.test.local 117 | .env.production.local 118 | .env.local 119 | 120 | # parcel-bundler cache (https://parceljs.org/) 121 | .cache 122 | .parcel-cache 123 | 124 | # Next.js build output 125 | .next 126 | out 127 | 128 | # Nuxt.js build / generate output 129 | .nuxt 130 | dist 131 | 132 | # Gatsby files 133 | .cache/ 134 | # Comment in the public line in if your project uses Gatsby and not Next.js 135 | # https://nextjs.org/blog/next-9-1#public-directory-support 136 | # public 137 | 138 | # vuepress build output 139 | .vuepress/dist 140 | 141 | # vuepress v2.x temp and cache directory 142 | .temp 143 | 144 | # Docusaurus cache and generated files 145 | .docusaurus 146 | 147 | # Serverless directories 148 | .serverless/ 149 | 150 | # FuseBox cache 151 | .fusebox/ 152 | 153 | # DynamoDB Local files 154 | .dynamodb/ 155 | 156 | # TernJS port file 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | .vscode-test 161 | 162 | # yarn v2 163 | .yarn/cache 164 | .yarn/unplugged 165 | .yarn/build-state.yml 166 | .yarn/install-state.gz 167 | .pnp.* 168 | 169 | ### Node Patch ### 170 | # Serverless Webpack directories 171 | .webpack/ 172 | 173 | # Optional stylelint cache 174 | 175 | # SvelteKit build / generate output 176 | .svelte-kit 177 | 178 | ### NuxtJS ### 179 | # Generated dirs 180 | .nuxt-* 181 | .output 182 | .gen 183 | 184 | # Node dependencies 185 | node_modules 186 | 187 | # System files 188 | 189 | ### VisualStudioCode ### 190 | .vscode/* 191 | !.vscode/settings.json 192 | !.vscode/tasks.json 193 | !.vscode/launch.json 194 | !.vscode/extensions.json 195 | !.vscode/*.code-snippets 196 | 197 | # Local History for Visual Studio Code 198 | .history/ 199 | 200 | # Built Visual Studio Code Extensions 201 | *.vsix 202 | 203 | ### VisualStudioCode Patch ### 204 | # Ignore all local history of files 205 | .history 206 | .ionide 207 | 208 | ### Windows ### 209 | # Windows thumbnail cache files 210 | Thumbs.db 211 | Thumbs.db:encryptable 212 | ehthumbs.db 213 | ehthumbs_vista.db 214 | 215 | # Dump file 216 | *.stackdump 217 | 218 | # Folder config file 219 | [Dd]esktop.ini 220 | 221 | # Recycle Bin used on file shares 222 | $RECYCLE.BIN/ 223 | 224 | # Windows Installer files 225 | *.cab 226 | *.msi 227 | *.msix 228 | *.msm 229 | *.msp 230 | 231 | # Windows shortcuts 232 | *.lnk 233 | 234 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,node,nuxtjs,windows 235 | 236 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 237 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .env 8 | dist 9 | .env 10 | 11 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 12 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,node,nuxtjs,windows 13 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,node,nuxtjs,windows 14 | 15 | ### macOS ### 16 | # General 17 | .DS_Store 18 | .AppleDouble 19 | .LSOverride 20 | 21 | # Icon must end with two \r 22 | Icon 23 | 24 | 25 | # Thumbnails 26 | ._* 27 | 28 | # Files that might appear in the root of a volume 29 | .DocumentRevisions-V100 30 | .fseventsd 31 | .Spotlight-V100 32 | .TemporaryItems 33 | .Trashes 34 | .VolumeIcon.icns 35 | .com.apple.timemachine.donotpresent 36 | 37 | # Directories potentially created on remote AFP share 38 | .AppleDB 39 | .AppleDesktop 40 | Network Trash Folder 41 | Temporary Items 42 | .apdisk 43 | 44 | ### macOS Patch ### 45 | # iCloud generated files 46 | *.icloud 47 | 48 | ### Node ### 49 | # Logs 50 | logs 51 | *.log 52 | npm-debug.log* 53 | yarn-debug.log* 54 | yarn-error.log* 55 | lerna-debug.log* 56 | .pnpm-debug.log* 57 | 58 | # Diagnostic reports (https://nodejs.org/api/report.html) 59 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 60 | 61 | # Runtime data 62 | pids 63 | *.pid 64 | *.seed 65 | *.pid.lock 66 | 67 | # Directory for instrumented libs generated by jscoverage/JSCover 68 | lib-cov 69 | 70 | # Coverage directory used by tools like istanbul 71 | coverage 72 | *.lcov 73 | 74 | # nyc test coverage 75 | .nyc_output 76 | 77 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 78 | .grunt 79 | 80 | # Bower dependency directory (https://bower.io/) 81 | bower_components 82 | 83 | # node-waf configuration 84 | .lock-wscript 85 | 86 | # Compiled binary addons (https://nodejs.org/api/addons.html) 87 | build/Release 88 | 89 | # Dependency directories 90 | node_modules/ 91 | jspm_packages/ 92 | 93 | # Snowpack dependency directory (https://snowpack.dev/) 94 | web_modules/ 95 | 96 | # TypeScript cache 97 | *.tsbuildinfo 98 | 99 | # Optional npm cache directory 100 | .npm 101 | 102 | # Optional eslint cache 103 | .eslintcache 104 | 105 | # Optional stylelint cache 106 | .stylelintcache 107 | 108 | # Microbundle cache 109 | .rpt2_cache/ 110 | .rts2_cache_cjs/ 111 | .rts2_cache_es/ 112 | .rts2_cache_umd/ 113 | 114 | # Optional REPL history 115 | .node_repl_history 116 | 117 | # Output of 'npm pack' 118 | *.tgz 119 | 120 | # Yarn Integrity file 121 | .yarn-integrity 122 | 123 | # dotenv environment variable files 124 | .env 125 | .env.development.local 126 | .env.test.local 127 | .env.production.local 128 | .env.local 129 | 130 | # parcel-bundler cache (https://parceljs.org/) 131 | .cache 132 | .parcel-cache 133 | 134 | # Next.js build output 135 | .next 136 | out 137 | 138 | # Nuxt.js build / generate output 139 | .nuxt 140 | dist 141 | 142 | # Gatsby files 143 | .cache/ 144 | # Comment in the public line in if your project uses Gatsby and not Next.js 145 | # https://nextjs.org/blog/next-9-1#public-directory-support 146 | # public 147 | 148 | # vuepress build output 149 | .vuepress/dist 150 | 151 | # vuepress v2.x temp and cache directory 152 | .temp 153 | 154 | # Docusaurus cache and generated files 155 | .docusaurus 156 | 157 | # Serverless directories 158 | .serverless/ 159 | 160 | # FuseBox cache 161 | .fusebox/ 162 | 163 | # DynamoDB Local files 164 | .dynamodb/ 165 | 166 | # TernJS port file 167 | .tern-port 168 | 169 | # Stores VSCode versions used for testing VSCode extensions 170 | .vscode-test 171 | 172 | # yarn v2 173 | .yarn/cache 174 | .yarn/unplugged 175 | .yarn/build-state.yml 176 | .yarn/install-state.gz 177 | .pnp.* 178 | 179 | ### Node Patch ### 180 | # Serverless Webpack directories 181 | .webpack/ 182 | 183 | # Optional stylelint cache 184 | 185 | # SvelteKit build / generate output 186 | .svelte-kit 187 | 188 | ### NuxtJS ### 189 | # Generated dirs 190 | .nuxt-* 191 | .output 192 | .gen 193 | 194 | # Node dependencies 195 | node_modules 196 | 197 | # System files 198 | 199 | ### VisualStudioCode ### 200 | .vscode/* 201 | !.vscode/settings.json 202 | !.vscode/tasks.json 203 | !.vscode/launch.json 204 | !.vscode/extensions.json 205 | !.vscode/*.code-snippets 206 | 207 | # Local History for Visual Studio Code 208 | .history/ 209 | 210 | # Built Visual Studio Code Extensions 211 | *.vsix 212 | 213 | ### VisualStudioCode Patch ### 214 | # Ignore all local history of files 215 | .history 216 | .ionide 217 | 218 | ### Windows ### 219 | # Windows thumbnail cache files 220 | Thumbs.db 221 | Thumbs.db:encryptable 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Dump file 226 | *.stackdump 227 | 228 | # Folder config file 229 | [Dd]esktop.ini 230 | 231 | # Recycle Bin used on file shares 232 | $RECYCLE.BIN/ 233 | 234 | # Windows Installer files 235 | *.cab 236 | *.msi 237 | *.msix 238 | *.msm 239 | *.msp 240 | 241 | # Windows shortcuts 242 | *.lnk 243 | 244 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,node,nuxtjs,windows 245 | 246 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 247 | -------------------------------------------------------------------------------- /utils/tw-colors.ts: -------------------------------------------------------------------------------- 1 | export const twColors = { 2 | black: "#000", 3 | white: "#fff", 4 | slate: { 5 | 50: "#f8fafc", 6 | 100: "#f1f5f9", 7 | 200: "#e2e8f0", 8 | 300: "#cbd5e1", 9 | 400: "#94a3b8", 10 | 500: "#64748b", 11 | 600: "#475569", 12 | 700: "#334155", 13 | 800: "#1e293b", 14 | 900: "#0f172a", 15 | 950: "#020617", 16 | }, 17 | gray: { 18 | 50: "#f9fafb", 19 | 100: "#f3f4f6", 20 | 200: "#e5e7eb", 21 | 300: "#d1d5db", 22 | 400: "#9ca3af", 23 | 500: "#6b7280", 24 | 600: "#4b5563", 25 | 700: "#374151", 26 | 800: "#1f2937", 27 | 900: "#111827", 28 | 950: "#030712", 29 | }, 30 | zinc: { 31 | 50: "#fafafa", 32 | 100: "#f4f4f5", 33 | 200: "#e4e4e7", 34 | 300: "#d4d4d8", 35 | 400: "#a1a1aa", 36 | 500: "#71717a", 37 | 600: "#52525b", 38 | 700: "#3f3f46", 39 | 800: "#27272a", 40 | 900: "#18181b", 41 | 950: "#09090b", 42 | }, 43 | neutral: { 44 | 50: "#fafafa", 45 | 100: "#f5f5f5", 46 | 200: "#e5e5e5", 47 | 300: "#d4d4d4", 48 | 400: "#a3a3a3", 49 | 500: "#737373", 50 | 600: "#525252", 51 | 700: "#404040", 52 | 800: "#262626", 53 | 900: "#171717", 54 | 950: "#0a0a0a", 55 | }, 56 | stone: { 57 | 50: "#fafaf9", 58 | 100: "#f5f5f4", 59 | 200: "#e7e5e4", 60 | 300: "#d6d3d1", 61 | 400: "#a8a29e", 62 | 500: "#78716c", 63 | 600: "#57534e", 64 | 700: "#44403c", 65 | 800: "#292524", 66 | 900: "#1c1917", 67 | 950: "#0c0a09", 68 | }, 69 | red: { 70 | 50: "#fef2f2", 71 | 100: "#fee2e2", 72 | 200: "#fecaca", 73 | 300: "#fca5a5", 74 | 400: "#f87171", 75 | 500: "#ef4444", 76 | 600: "#dc2626", 77 | 700: "#b91c1c", 78 | 800: "#991b1b", 79 | 900: "#7f1d1d", 80 | 950: "#450a0a", 81 | }, 82 | orange: { 83 | 50: "#fff7ed", 84 | 100: "#ffedd5", 85 | 200: "#fed7aa", 86 | 300: "#fdba74", 87 | 400: "#fb923c", 88 | 500: "#f97316", 89 | 600: "#ea580c", 90 | 700: "#c2410c", 91 | 800: "#9a3412", 92 | 900: "#7c2d12", 93 | 950: "#431407", 94 | }, 95 | amber: { 96 | 50: "#fffbeb", 97 | 100: "#fef3c7", 98 | 200: "#fde68a", 99 | 300: "#fcd34d", 100 | 400: "#fbbf24", 101 | 500: "#f59e0b", 102 | 600: "#d97706", 103 | 700: "#b45309", 104 | 800: "#92400e", 105 | 900: "#78350f", 106 | 950: "#451a03", 107 | }, 108 | yellow: { 109 | 50: "#fefce8", 110 | 100: "#fef9c3", 111 | 200: "#fef08a", 112 | 300: "#fde047", 113 | 400: "#facc15", 114 | 500: "#eab308", 115 | 600: "#ca8a04", 116 | 700: "#a16207", 117 | 800: "#854d0e", 118 | 900: "#713f12", 119 | 950: "#422006", 120 | }, 121 | lime: { 122 | 50: "#f7fee7", 123 | 100: "#ecfccb", 124 | 200: "#d9f99d", 125 | 300: "#bef264", 126 | 400: "#a3e635", 127 | 500: "#84cc16", 128 | 600: "#65a30d", 129 | 700: "#4d7c0f", 130 | 800: "#3f6212", 131 | 900: "#365314", 132 | 950: "#1a2e05", 133 | }, 134 | green: { 135 | 50: "#f0fdf4", 136 | 100: "#dcfce7", 137 | 200: "#bbf7d0", 138 | 300: "#86efac", 139 | 400: "#4ade80", 140 | 500: "#22c55e", 141 | 600: "#16a34a", 142 | 700: "#15803d", 143 | 800: "#166534", 144 | 900: "#14532d", 145 | 950: "#052e16", 146 | }, 147 | emerald: { 148 | 50: "#ecfdf5", 149 | 100: "#d1fae5", 150 | 200: "#a7f3d0", 151 | 300: "#6ee7b7", 152 | 400: "#34d399", 153 | 500: "#10b981", 154 | 600: "#059669", 155 | 700: "#047857", 156 | 800: "#065f46", 157 | 900: "#064e3b", 158 | 950: "#022c22", 159 | }, 160 | teal: { 161 | 50: "#f0fdfa", 162 | 100: "#ccfbf1", 163 | 200: "#99f6e4", 164 | 300: "#5eead4", 165 | 400: "#2dd4bf", 166 | 500: "#14b8a6", 167 | 600: "#0d9488", 168 | 700: "#0f766e", 169 | 800: "#115e59", 170 | 900: "#134e4a", 171 | 950: "#042f2e", 172 | }, 173 | cyan: { 174 | 50: "#ecfeff", 175 | 100: "#cffafe", 176 | 200: "#a5f3fc", 177 | 300: "#67e8f9", 178 | 400: "#22d3ee", 179 | 500: "#06b6d4", 180 | 600: "#0891b2", 181 | 700: "#0e7490", 182 | 800: "#155e75", 183 | 900: "#164e63", 184 | 950: "#083344", 185 | }, 186 | sky: { 187 | 50: "#f0f9ff", 188 | 100: "#e0f2fe", 189 | 200: "#bae6fd", 190 | 300: "#7dd3fc", 191 | 400: "#38bdf8", 192 | 500: "#0ea5e9", 193 | 600: "#0284c7", 194 | 700: "#0369a1", 195 | 800: "#075985", 196 | 900: "#0c4a6e", 197 | 950: "#082f49", 198 | }, 199 | blue: { 200 | 50: "#eff6ff", 201 | 100: "#dbeafe", 202 | 200: "#bfdbfe", 203 | 300: "#93c5fd", 204 | 400: "#60a5fa", 205 | 500: "#3b82f6", 206 | 600: "#2563eb", 207 | 700: "#1d4ed8", 208 | 800: "#1e40af", 209 | 900: "#1e3a8a", 210 | 950: "#172554", 211 | }, 212 | indigo: { 213 | 50: "#eef2ff", 214 | 100: "#e0e7ff", 215 | 200: "#c7d2fe", 216 | 300: "#a5b4fc", 217 | 400: "#818cf8", 218 | 500: "#6366f1", 219 | 600: "#4f46e5", 220 | 700: "#4338ca", 221 | 800: "#3730a3", 222 | 900: "#312e81", 223 | 950: "#1e1b4b", 224 | }, 225 | violet: { 226 | 50: "#f5f3ff", 227 | 100: "#ede9fe", 228 | 200: "#ddd6fe", 229 | 300: "#c4b5fd", 230 | 400: "#a78bfa", 231 | 500: "#8b5cf6", 232 | 600: "#7c3aed", 233 | 700: "#6d28d9", 234 | 800: "#5b21b6", 235 | 900: "#4c1d95", 236 | 950: "#2e1065", 237 | }, 238 | purple: { 239 | 50: "#faf5ff", 240 | 100: "#f3e8ff", 241 | 200: "#e9d5ff", 242 | 300: "#d8b4fe", 243 | 400: "#c084fc", 244 | 500: "#a855f7", 245 | 600: "#9333ea", 246 | 700: "#7e22ce", 247 | 800: "#6b21a8", 248 | 900: "#581c87", 249 | 950: "#3b0764", 250 | }, 251 | fuchsia: { 252 | 50: "#fdf4ff", 253 | 100: "#fae8ff", 254 | 200: "#f5d0fe", 255 | 300: "#f0abfc", 256 | 400: "#e879f9", 257 | 500: "#d946ef", 258 | 600: "#c026d3", 259 | 700: "#a21caf", 260 | 800: "#86198f", 261 | 900: "#701a75", 262 | 950: "#4a044e", 263 | }, 264 | pink: { 265 | 50: "#fdf2f8", 266 | 100: "#fce7f3", 267 | 200: "#fbcfe8", 268 | 300: "#f9a8d4", 269 | 400: "#f472b6", 270 | 500: "#ec4899", 271 | 600: "#db2777", 272 | 700: "#be185d", 273 | 800: "#9d174d", 274 | 900: "#831843", 275 | 950: "#500724", 276 | }, 277 | rose: { 278 | 50: "#fff1f2", 279 | 100: "#ffe4e6", 280 | 200: "#fecdd3", 281 | 300: "#fda4af", 282 | 400: "#fb7185", 283 | 500: "#f43f5e", 284 | 600: "#e11d48", 285 | 700: "#be123c", 286 | 800: "#9f1239", 287 | 900: "#881337", 288 | 950: "#4c0519", 289 | }, 290 | }; 291 | --------------------------------------------------------------------------------