init: чистый старт Laravel + Vuexy
This commit is contained in:
36
resources/ts/plugins/1.router/index.ts
Normal file
36
resources/ts/plugins/1.router/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { setupLayouts } from 'virtual:meta-layouts'
|
||||
import type { App } from 'vue'
|
||||
|
||||
import type { RouteRecordRaw } from 'vue-router/auto'
|
||||
|
||||
import { createRouter, createWebHistory } from 'vue-router/auto'
|
||||
|
||||
function recursiveLayouts(route: RouteRecordRaw): RouteRecordRaw {
|
||||
if (route.children) {
|
||||
for (let i = 0; i < route.children.length; i++)
|
||||
route.children[i] = recursiveLayouts(route.children[i])
|
||||
|
||||
return route
|
||||
}
|
||||
|
||||
return setupLayouts([route])[0]
|
||||
}
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
scrollBehavior(to) {
|
||||
if (to.hash)
|
||||
return { el: to.hash, behavior: 'smooth', top: 60 }
|
||||
|
||||
return { top: 0 }
|
||||
},
|
||||
extendRoutes: pages => [
|
||||
...[...pages].map(route => recursiveLayouts(route)),
|
||||
],
|
||||
})
|
||||
|
||||
export { router }
|
||||
|
||||
export default function (app: App) {
|
||||
app.use(router)
|
||||
}
|
||||
8
resources/ts/plugins/2.pinia.ts
Normal file
8
resources/ts/plugins/2.pinia.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { createPinia } from 'pinia'
|
||||
import type { App } from 'vue'
|
||||
|
||||
export const store = createPinia()
|
||||
|
||||
export default function (app: App) {
|
||||
app.use(store)
|
||||
}
|
||||
299
resources/ts/plugins/iconify/build-icons.ts
Normal file
299
resources/ts/plugins/iconify/build-icons.ts
Normal file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* This is an advanced example for creating icon bundles for Iconify SVG Framework.
|
||||
*
|
||||
* It creates a bundle from:
|
||||
* - All SVG files in a directory.
|
||||
* - Custom JSON files.
|
||||
* - Iconify icon sets.
|
||||
* - SVG framework.
|
||||
*
|
||||
* This example uses Iconify Tools to import and clean up icons.
|
||||
* For Iconify Tools documentation visit https://docs.iconify.design/tools/tools2/
|
||||
*/
|
||||
import { promises as fs } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
|
||||
// Installation: npm install --save-dev @iconify/tools @iconify/utils @iconify/json @iconify/iconify
|
||||
import { cleanupSVG, importDirectory, isEmptyColor, parseColors, runSVGO } from '@iconify/tools'
|
||||
import type { IconifyJSON } from '@iconify/types'
|
||||
import { getIcons, getIconsCSS, stringToIcon } from '@iconify/utils'
|
||||
|
||||
/**
|
||||
* Script configuration
|
||||
*/
|
||||
interface BundleScriptCustomSVGConfig {
|
||||
|
||||
// Path to SVG files
|
||||
dir: string
|
||||
|
||||
// True if icons should be treated as monotone: colors replaced with currentColor
|
||||
monotone: boolean
|
||||
|
||||
// Icon set prefix
|
||||
prefix: string
|
||||
}
|
||||
|
||||
interface BundleScriptCustomJSONConfig {
|
||||
|
||||
// Path to JSON file
|
||||
filename: string
|
||||
|
||||
// List of icons to import. If missing, all icons will be imported
|
||||
icons?: string[]
|
||||
}
|
||||
|
||||
interface BundleScriptConfig {
|
||||
|
||||
// Custom SVG to import and bundle
|
||||
svg?: BundleScriptCustomSVGConfig[]
|
||||
|
||||
// Icons to bundled from @iconify/json packages
|
||||
icons?: string[]
|
||||
|
||||
// List of JSON files to bundled
|
||||
// Entry can be a string, pointing to filename or a BundleScriptCustomJSONConfig object (see type above)
|
||||
// If entry is a string or object without 'icons' property, an entire JSON file will be bundled
|
||||
json?: (string | BundleScriptCustomJSONConfig)[]
|
||||
}
|
||||
|
||||
const sources: BundleScriptConfig = {
|
||||
|
||||
svg: [
|
||||
// {
|
||||
// dir: 'resources/images/iconify-svg',
|
||||
// monotone: true,
|
||||
// prefix: 'custom',
|
||||
// },
|
||||
|
||||
// {
|
||||
// dir: 'emojis',
|
||||
// monotone: false,
|
||||
// prefix: 'emoji',
|
||||
// },
|
||||
],
|
||||
|
||||
icons: [
|
||||
// 'mdi:home',
|
||||
// 'mdi:account',
|
||||
// 'mdi:login',
|
||||
// 'mdi:logout',
|
||||
// 'octicon:book-24',
|
||||
// 'octicon:code-square-24',
|
||||
],
|
||||
|
||||
json: [
|
||||
// Custom JSON file
|
||||
// 'json/gg.json',
|
||||
|
||||
// Iconify JSON file (@iconify/json is a package name, /json/ is directory where files are, then filename)
|
||||
require.resolve('@iconify-json/tabler/icons.json'),
|
||||
{
|
||||
filename: require.resolve('@iconify-json/mdi/icons.json'),
|
||||
icons: [
|
||||
'close-circle',
|
||||
'language-javascript',
|
||||
'language-typescript',
|
||||
],
|
||||
},
|
||||
{
|
||||
filename: require.resolve('@iconify-json/fa/icons.json'),
|
||||
icons: [
|
||||
'circle',
|
||||
],
|
||||
},
|
||||
|
||||
// Custom file with only few icons
|
||||
// {
|
||||
// filename: require.resolve('@iconify-json/line-md/icons.json'),
|
||||
// icons: [
|
||||
// 'home-twotone-alt',
|
||||
// 'github',
|
||||
// 'document-list',
|
||||
// 'document-code',
|
||||
// 'image-twotone',
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
}
|
||||
|
||||
// File to save bundle to
|
||||
const target = join(__dirname, 'icons.css')
|
||||
|
||||
/**
|
||||
* Do stuff!
|
||||
*/
|
||||
|
||||
;(async function () {
|
||||
// Create directory for output if missing
|
||||
const dir = dirname(target)
|
||||
try {
|
||||
await fs.mkdir(dir, {
|
||||
recursive: true,
|
||||
})
|
||||
}
|
||||
catch (err) {
|
||||
//
|
||||
}
|
||||
|
||||
const allIcons: IconifyJSON[] = []
|
||||
|
||||
/**
|
||||
* Convert sources.icons to sources.json
|
||||
*/
|
||||
if (sources.icons) {
|
||||
const sourcesJSON = sources.json ? sources.json : (sources.json = [])
|
||||
|
||||
// Sort icons by prefix
|
||||
const organizedList = organizeIconsList(sources.icons)
|
||||
|
||||
for (const prefix in organizedList) {
|
||||
const filename = require.resolve(`@iconify/json/json/${prefix}.json`)
|
||||
|
||||
sourcesJSON.push({
|
||||
filename,
|
||||
icons: organizedList[prefix],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bundle JSON files and collect icons
|
||||
*/
|
||||
if (sources.json) {
|
||||
for (let i = 0; i < sources.json.length; i++) {
|
||||
const item = sources.json[i]
|
||||
|
||||
// Load icon set
|
||||
const filename = typeof item === 'string' ? item : item.filename
|
||||
const content = JSON.parse(await fs.readFile(filename, 'utf8')) as IconifyJSON
|
||||
|
||||
for (const key in content) {
|
||||
if (key === 'prefix' && content.prefix === 'tabler') {
|
||||
for (const k in content.icons)
|
||||
content.icons[k].body = content.icons[k].body.replace(/stroke-width="2"/g, 'stroke-width="1.5"')
|
||||
}
|
||||
}
|
||||
|
||||
// Filter icons
|
||||
if (typeof item !== 'string' && item.icons?.length) {
|
||||
const filteredContent = getIcons(content, item.icons)
|
||||
|
||||
if (!filteredContent)
|
||||
throw new Error(`Cannot find required icons in ${filename}`)
|
||||
|
||||
// Collect filtered icons
|
||||
allIcons.push(filteredContent)
|
||||
}
|
||||
else {
|
||||
// Collect all icons from the JSON file
|
||||
allIcons.push(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bundle custom SVG icons and collect icons
|
||||
*/
|
||||
if (sources.svg) {
|
||||
for (let i = 0; i < sources.svg.length; i++) {
|
||||
const source = sources.svg[i]
|
||||
|
||||
// Import icons
|
||||
const iconSet = await importDirectory(source.dir, {
|
||||
prefix: source.prefix,
|
||||
})
|
||||
|
||||
// Validate, clean up, fix palette, etc.
|
||||
await iconSet.forEach(async (name, type) => {
|
||||
if (type !== 'icon')
|
||||
return
|
||||
|
||||
// Get SVG instance for parsing
|
||||
const svg = iconSet.toSVG(name)
|
||||
|
||||
if (!svg) {
|
||||
// Invalid icon
|
||||
iconSet.remove(name)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Clean up and optimise icons
|
||||
try {
|
||||
// Clean up icon code
|
||||
await cleanupSVG(svg)
|
||||
|
||||
if (source.monotone) {
|
||||
// Replace color with currentColor, add if missing
|
||||
// If icon is not monotone, remove this code
|
||||
await parseColors(svg, {
|
||||
defaultColor: 'currentColor',
|
||||
callback: (attr, colorStr, color) => {
|
||||
return !color || isEmptyColor(color) ? colorStr : 'currentColor'
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Optimise
|
||||
await runSVGO(svg)
|
||||
}
|
||||
catch (err) {
|
||||
// Invalid icon
|
||||
console.error(`Error parsing ${name} from ${source.dir}:`, err)
|
||||
iconSet.remove(name)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Update icon from SVG instance
|
||||
iconSet.fromSVG(name, svg)
|
||||
})
|
||||
|
||||
// Collect the SVG icon
|
||||
allIcons.push(iconSet.export())
|
||||
}
|
||||
}
|
||||
|
||||
// Generate CSS from collected icons
|
||||
const cssContent = allIcons
|
||||
.map(iconSet => getIconsCSS(
|
||||
iconSet,
|
||||
Object.keys(iconSet.icons),
|
||||
{
|
||||
iconSelector: '.{prefix}-{name}',
|
||||
mode: 'mask',
|
||||
},
|
||||
))
|
||||
.join('\n')
|
||||
|
||||
// Save the CSS to a file
|
||||
await fs.writeFile(target, cssContent, 'utf8')
|
||||
|
||||
console.log(`Saved CSS to ${target}!`)
|
||||
})().catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
|
||||
/**
|
||||
* Sort icon names by prefix
|
||||
*/
|
||||
function organizeIconsList(icons: string[]): Record<string, string[]> {
|
||||
const sorted: Record<string, string[]> = Object.create(null)
|
||||
|
||||
icons.forEach(icon => {
|
||||
const item = stringToIcon(icon)
|
||||
|
||||
if (!item)
|
||||
return
|
||||
|
||||
const prefix = item.prefix
|
||||
const prefixList = sorted[prefix] ? sorted[prefix] : (sorted[prefix] = [])
|
||||
|
||||
const name = item.name
|
||||
|
||||
if (!prefixList.includes(name))
|
||||
prefixList.push(name)
|
||||
})
|
||||
|
||||
return sorted
|
||||
}
|
||||
5
resources/ts/plugins/iconify/index.ts
Normal file
5
resources/ts/plugins/iconify/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import './icons.css'
|
||||
|
||||
export default function () {
|
||||
// This plugin just requires icons import
|
||||
}
|
||||
3
resources/ts/plugins/iconify/package.json
Normal file
3
resources/ts/plugins/iconify/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
14
resources/ts/plugins/layouts.ts
Normal file
14
resources/ts/plugins/layouts.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { App } from 'vue'
|
||||
|
||||
import type { PartialDeep } from 'type-fest/source/partial-deep'
|
||||
import { createLayouts } from '@layouts'
|
||||
|
||||
import { layoutConfig } from '@themeConfig'
|
||||
|
||||
// Styles
|
||||
import '@layouts/styles/index.scss'
|
||||
|
||||
export default function (app: App) {
|
||||
// ℹ️ We generate layout config from our themeConfig so you don't have to write config twice
|
||||
app.use(createLayouts(layoutConfig as PartialDeep<typeof layoutConfig, NonNullable<unknown>>))
|
||||
}
|
||||
191
resources/ts/plugins/vuetify/defaults.ts
Normal file
191
resources/ts/plugins/vuetify/defaults.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
export default {
|
||||
IconBtn: {
|
||||
icon: true,
|
||||
color: 'default',
|
||||
variant: 'text',
|
||||
},
|
||||
VAlert: {
|
||||
density: 'comfortable',
|
||||
VBtn: {
|
||||
color: undefined,
|
||||
},
|
||||
},
|
||||
VAvatar: {
|
||||
// ℹ️ Remove after next release
|
||||
variant: 'flat',
|
||||
},
|
||||
VBadge: {
|
||||
// set v-badge default color to primary
|
||||
color: 'primary',
|
||||
},
|
||||
VBtn: {
|
||||
// set v-btn default color to primary
|
||||
color: 'primary',
|
||||
},
|
||||
VChip: {
|
||||
label: true,
|
||||
},
|
||||
VDataTable: {
|
||||
VPagination: {
|
||||
showFirstLastPage: true,
|
||||
firstIcon: 'tabler-chevrons-left',
|
||||
lastIcon: 'tabler-chevrons-right',
|
||||
},
|
||||
},
|
||||
VDataTableServer: {
|
||||
VPagination: {
|
||||
showFirstLastPage: true,
|
||||
firstIcon: 'tabler-chevrons-left',
|
||||
lastIcon: 'tabler-chevrons-right',
|
||||
},
|
||||
},
|
||||
VExpansionPanel: {
|
||||
expandIcon: 'tabler-chevron-right',
|
||||
collapseIcon: 'tabler-chevron-right',
|
||||
},
|
||||
VExpansionPanelTitle: {
|
||||
expandIcon: 'tabler-chevron-right',
|
||||
collapseIcon: 'tabler-chevron-right',
|
||||
},
|
||||
VList: {
|
||||
color: 'primary',
|
||||
density: 'compact',
|
||||
VCheckboxBtn: {
|
||||
density: 'compact',
|
||||
},
|
||||
VListItem: {
|
||||
ripple: false,
|
||||
VAvatar: {
|
||||
size: 40,
|
||||
},
|
||||
},
|
||||
},
|
||||
VMenu: {
|
||||
offset: '2px',
|
||||
},
|
||||
VPagination: {
|
||||
density: 'comfortable',
|
||||
variant: 'tonal',
|
||||
},
|
||||
VTabs: {
|
||||
// set v-tabs default color to primary
|
||||
color: 'primary',
|
||||
density: 'comfortable',
|
||||
VSlideGroup: {
|
||||
showArrows: true,
|
||||
},
|
||||
},
|
||||
VTooltip: {
|
||||
// set v-tooltip default location to top
|
||||
location: 'top',
|
||||
},
|
||||
VCheckboxBtn: {
|
||||
color: 'primary',
|
||||
},
|
||||
VCheckbox: {
|
||||
// set v-checkbox default color to primary
|
||||
color: 'primary',
|
||||
density: 'comfortable',
|
||||
hideDetails: 'auto',
|
||||
},
|
||||
VRadioGroup: {
|
||||
color: 'primary',
|
||||
density: 'comfortable',
|
||||
hideDetails: 'auto',
|
||||
},
|
||||
VRadio: {
|
||||
density: 'comfortable',
|
||||
hideDetails: 'auto',
|
||||
},
|
||||
VSelect: {
|
||||
variant: 'outlined',
|
||||
color: 'primary',
|
||||
density: 'comfortable',
|
||||
hideDetails: 'auto',
|
||||
VChip: {
|
||||
label: true,
|
||||
},
|
||||
},
|
||||
VRangeSlider: {
|
||||
// set v-range-slider default color to primary
|
||||
color: 'primary',
|
||||
trackSize: 6,
|
||||
thumbSize: 22,
|
||||
density: 'comfortable',
|
||||
thumbLabel: true,
|
||||
hideDetails: 'auto',
|
||||
},
|
||||
VRating: {
|
||||
// set v-rating default color to primary
|
||||
color: 'warning',
|
||||
},
|
||||
VProgressLinear: {
|
||||
height: 6,
|
||||
roundedBar: true,
|
||||
rounded: true,
|
||||
bgColor: 'rgba(var(--v-track-bg))',
|
||||
},
|
||||
VSlider: {
|
||||
// set v-range-slider default color to primary
|
||||
color: 'primary',
|
||||
thumbLabel: true,
|
||||
hideDetails: 'auto',
|
||||
thumbSize: 22,
|
||||
trackSize: 6,
|
||||
elevation: 4,
|
||||
},
|
||||
VTextField: {
|
||||
variant: 'outlined',
|
||||
density: 'comfortable',
|
||||
color: 'primary',
|
||||
hideDetails: 'auto',
|
||||
},
|
||||
VAutocomplete: {
|
||||
variant: 'outlined',
|
||||
color: 'primary',
|
||||
density: 'comfortable',
|
||||
hideDetails: 'auto',
|
||||
menuProps: {
|
||||
contentClass: 'app-autocomplete__content v-autocomplete__content',
|
||||
},
|
||||
VChip: {
|
||||
label: true,
|
||||
},
|
||||
},
|
||||
VCombobox: {
|
||||
variant: 'outlined',
|
||||
density: 'comfortable',
|
||||
color: 'primary',
|
||||
hideDetails: 'auto',
|
||||
VChip: {
|
||||
label: true,
|
||||
},
|
||||
},
|
||||
VFileInput: {
|
||||
variant: 'outlined',
|
||||
density: 'comfortable',
|
||||
color: 'primary',
|
||||
hideDetails: 'auto',
|
||||
},
|
||||
VTextarea: {
|
||||
variant: 'outlined',
|
||||
density: 'comfortable',
|
||||
color: 'primary',
|
||||
hideDetails: 'auto',
|
||||
},
|
||||
VSnackbar: {
|
||||
VBtn: {
|
||||
density: 'comfortable',
|
||||
},
|
||||
},
|
||||
VSwitch: {
|
||||
// set v-switch default color to primary
|
||||
inset: true,
|
||||
color: 'primary',
|
||||
hideDetails: 'auto',
|
||||
ripple: false,
|
||||
},
|
||||
VNavigationDrawer: {
|
||||
touchless: true,
|
||||
},
|
||||
}
|
||||
84
resources/ts/plugins/vuetify/icons.ts
Normal file
84
resources/ts/plugins/vuetify/icons.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import type { IconAliases, IconProps } from 'vuetify'
|
||||
|
||||
import checkboxChecked from '@images/svg/checkbox-checked.svg'
|
||||
import checkboxIndeterminate from '@images/svg/checkbox-indeterminate.svg'
|
||||
import checkboxUnchecked from '@images/svg/checkbox-unchecked.svg'
|
||||
import radioChecked from '@images/svg/radio-checked.svg'
|
||||
import radioUnchecked from '@images/svg/radio-unchecked.svg'
|
||||
|
||||
const customIcons: Record<string, unknown> = {
|
||||
'mdi-checkbox-blank-outline': checkboxUnchecked,
|
||||
'mdi-checkbox-marked': checkboxChecked,
|
||||
'mdi-minus-box': checkboxIndeterminate,
|
||||
'mdi-radiobox-marked': radioChecked,
|
||||
'mdi-radiobox-blank': radioUnchecked,
|
||||
}
|
||||
|
||||
const aliases: Partial<IconAliases> = {
|
||||
calendar: 'tabler-calendar',
|
||||
collapse: 'tabler-chevron-up',
|
||||
complete: 'tabler-check',
|
||||
cancel: 'tabler-x',
|
||||
close: 'tabler-x',
|
||||
delete: 'tabler-circle-x-filled',
|
||||
clear: 'tabler-circle-x',
|
||||
success: 'tabler-circle-check',
|
||||
info: 'tabler-info-circle',
|
||||
warning: 'tabler-alert-triangle',
|
||||
error: 'tabler-alert-circle',
|
||||
prev: 'tabler-chevron-left',
|
||||
ratingEmpty: 'tabler-star',
|
||||
ratingFull: 'tabler-star-filled',
|
||||
ratingHalf: 'tabler-star-half-filled',
|
||||
next: 'tabler-chevron-right',
|
||||
delimiter: 'tabler-circle',
|
||||
sort: 'tabler-arrow-up',
|
||||
expand: 'tabler-chevron-down',
|
||||
menu: 'tabler-menu-2',
|
||||
subgroup: 'tabler-caret-down',
|
||||
dropdown: 'tabler-chevron-down',
|
||||
edit: 'tabler-pencil',
|
||||
loading: 'tabler-refresh',
|
||||
first: 'tabler-player-skip-back',
|
||||
last: 'tabler-player-skip-forward',
|
||||
unfold: 'tabler-arrows-move-vertical',
|
||||
file: 'tabler-paperclip',
|
||||
plus: 'tabler-plus',
|
||||
minus: 'tabler-minus',
|
||||
sortAsc: 'tabler-arrow-up',
|
||||
sortDesc: 'tabler-arrow-down',
|
||||
}
|
||||
|
||||
export const iconify = {
|
||||
component: (props: IconProps) => {
|
||||
// Load custom SVG directly instead of going through icon component
|
||||
if (typeof props.icon === 'string') {
|
||||
const iconComponent = customIcons[props.icon]
|
||||
|
||||
if (iconComponent)
|
||||
return h(iconComponent)
|
||||
}
|
||||
|
||||
return h(
|
||||
props.tag,
|
||||
{
|
||||
...props,
|
||||
|
||||
// As we are using class based icons
|
||||
class: [props.icon],
|
||||
|
||||
// Remove used props from DOM rendering
|
||||
tag: undefined,
|
||||
icon: undefined,
|
||||
},
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
export const icons = {
|
||||
defaultSet: 'iconify',
|
||||
aliases,
|
||||
sets: {
|
||||
iconify,
|
||||
},
|
||||
}
|
||||
47
resources/ts/plugins/vuetify/index.ts
Normal file
47
resources/ts/plugins/vuetify/index.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { deepMerge } from '@antfu/utils'
|
||||
import type { App } from 'vue'
|
||||
import { createVuetify } from 'vuetify'
|
||||
import { VBtn } from 'vuetify/components/VBtn'
|
||||
import defaults from './defaults'
|
||||
import { icons } from './icons'
|
||||
import { staticPrimaryColor, staticPrimaryDarkenColor, themes } from './theme'
|
||||
import { themeConfig } from '@themeConfig'
|
||||
|
||||
// Styles
|
||||
import { cookieRef } from '@/@layouts/stores/config'
|
||||
import '@core-scss/template/libs/vuetify/index.scss'
|
||||
import 'vuetify/styles'
|
||||
|
||||
export default function (app: App) {
|
||||
const cookieThemeValues = {
|
||||
defaultTheme: resolveVuetifyTheme(themeConfig.app.theme),
|
||||
themes: {
|
||||
light: {
|
||||
colors: {
|
||||
'primary': cookieRef('lightThemePrimaryColor', staticPrimaryColor).value,
|
||||
'primary-darken-1': cookieRef('lightThemePrimaryDarkenColor', staticPrimaryDarkenColor).value,
|
||||
},
|
||||
},
|
||||
dark: {
|
||||
colors: {
|
||||
'primary': cookieRef('darkThemePrimaryColor', staticPrimaryColor).value,
|
||||
'primary-darken-1': cookieRef('darkThemePrimaryDarkenColor', staticPrimaryDarkenColor).value,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const optionTheme = deepMerge({ themes }, cookieThemeValues)
|
||||
|
||||
const vuetify = createVuetify({
|
||||
aliases: {
|
||||
IconBtn: VBtn,
|
||||
},
|
||||
defaults,
|
||||
icons,
|
||||
theme: optionTheme,
|
||||
|
||||
})
|
||||
|
||||
app.use(vuetify)
|
||||
}
|
||||
155
resources/ts/plugins/vuetify/theme.ts
Normal file
155
resources/ts/plugins/vuetify/theme.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import type { ThemeDefinition } from 'vuetify'
|
||||
|
||||
export const staticPrimaryColor = '#7367F0'
|
||||
export const staticPrimaryDarkenColor = '#675DD8'
|
||||
|
||||
export const themes: Record<string, ThemeDefinition> = {
|
||||
light: {
|
||||
dark: false,
|
||||
colors: {
|
||||
'primary': staticPrimaryColor,
|
||||
'on-primary': '#fff',
|
||||
'primary-darken-1': '#675DD8',
|
||||
'secondary': '#808390',
|
||||
'on-secondary': '#fff',
|
||||
'secondary-darken-1': '#737682',
|
||||
'success': '#28C76F',
|
||||
'on-success': '#fff',
|
||||
'success-darken-1': '#24B364',
|
||||
'info': '#00BAD1',
|
||||
'on-info': '#fff',
|
||||
'info-darken-1': '#00A7BC',
|
||||
'warning': '#FF9F43',
|
||||
'on-warning': '#fff',
|
||||
'warning-darken-1': '#E68F3C',
|
||||
'error': '#FF4C51',
|
||||
'on-error': '#fff',
|
||||
'error-darken-1': '#E64449',
|
||||
'background': '#F8F7FA',
|
||||
'on-background': '#2F2B3D',
|
||||
'surface': '#fff',
|
||||
'on-surface': '#2F2B3D',
|
||||
'grey-50': '#FAFAFA',
|
||||
'grey-100': '#F5F5F5',
|
||||
'grey-200': '#EEEEEE',
|
||||
'grey-300': '#E0E0E0',
|
||||
'grey-400': '#BDBDBD',
|
||||
'grey-500': '#9E9E9E',
|
||||
'grey-600': '#757575',
|
||||
'grey-700': '#616161',
|
||||
'grey-800': '#424242',
|
||||
'grey-900': '#212121',
|
||||
'grey-light': '#FAFAFA',
|
||||
'perfect-scrollbar-thumb': '#DBDADE',
|
||||
'skin-bordered-background': '#fff',
|
||||
'skin-bordered-surface': '#fff',
|
||||
'expansion-panel-text-custom-bg': '#fafafa',
|
||||
},
|
||||
|
||||
variables: {
|
||||
'code-color': '#d400ff',
|
||||
'overlay-scrim-background': '#2F2B3D',
|
||||
'tooltip-background': '#2F2B3D',
|
||||
'overlay-scrim-opacity': 0.5,
|
||||
'hover-opacity': 0.06,
|
||||
'focus-opacity': 0.1,
|
||||
'selected-opacity': 0.08,
|
||||
'activated-opacity': 0.16,
|
||||
'pressed-opacity': 0.14,
|
||||
'dragged-opacity': 0.1,
|
||||
'disabled-opacity': 0.4,
|
||||
'border-color': '#2F2B3D',
|
||||
'border-opacity': 0.12,
|
||||
'table-header-color': '#EAEAEC',
|
||||
'high-emphasis-opacity': 0.9,
|
||||
'medium-emphasis-opacity': 0.7,
|
||||
'switch-opacity': 0.2,
|
||||
'switch-disabled-track-opacity': 0.3,
|
||||
'switch-disabled-thumb-opacity': 0.4,
|
||||
'switch-checked-disabled-opacity': 0.3,
|
||||
'track-bg': '#F1F0F2',
|
||||
|
||||
// Shadows
|
||||
'shadow-key-umbra-color': '#2F2B3D',
|
||||
'shadow-xs-opacity': 0.10,
|
||||
'shadow-sm-opacity': 0.12,
|
||||
'shadow-md-opacity': 0.14,
|
||||
'shadow-lg-opacity': 0.16,
|
||||
'shadow-xl-opacity': 0.18,
|
||||
},
|
||||
},
|
||||
dark: {
|
||||
dark: true,
|
||||
colors: {
|
||||
'primary': staticPrimaryColor,
|
||||
'on-primary': '#fff',
|
||||
'primary-darken-1': '#675DD8',
|
||||
'secondary': '#808390',
|
||||
'on-secondary': '#fff',
|
||||
'secondary-darken-1': '#737682',
|
||||
'success': '#28C76F',
|
||||
'on-success': '#fff',
|
||||
'success-darken-1': '#24B364',
|
||||
'info': '#00BAD1',
|
||||
'on-info': '#fff',
|
||||
'info-darken-1': '#00A7BC',
|
||||
'warning': '#FF9F43',
|
||||
'on-warning': '#fff',
|
||||
'warning-darken-1': '#E68F3C',
|
||||
'error': '#FF4C51',
|
||||
'on-error': '#fff',
|
||||
'error-darken-1': '#E64449',
|
||||
'background': '#25293C',
|
||||
'on-background': '#E1DEF5',
|
||||
'surface': '#2F3349',
|
||||
'on-surface': '#E1DEF5',
|
||||
'grey-50': '#26293A',
|
||||
'grey-100': '#2F3349',
|
||||
'grey-200': '#26293A',
|
||||
'grey-300': '#4A5072',
|
||||
'grey-400': '#5E6692',
|
||||
'grey-500': '#7983BB',
|
||||
'grey-600': '#AAB3DE',
|
||||
'grey-700': '#B6BEE3',
|
||||
'grey-800': '#CFD3EC',
|
||||
'grey-900': '#E7E9F6',
|
||||
'grey-light': '#353A52',
|
||||
'perfect-scrollbar-thumb': '#4A5072',
|
||||
'skin-bordered-background': '#2F3349',
|
||||
'skin-bordered-surface': '#2F3349',
|
||||
},
|
||||
variables: {
|
||||
'code-color': '#d400ff',
|
||||
'overlay-scrim-background': '#171925',
|
||||
'tooltip-background': '#F7F4FF',
|
||||
'overlay-scrim-opacity': 0.6,
|
||||
'hover-opacity': 0.06,
|
||||
'focus-opacity': 0.1,
|
||||
'selected-opacity': 0.08,
|
||||
'activated-opacity': 0.16,
|
||||
'pressed-opacity': 0.14,
|
||||
'dragged-opacity': 0.1,
|
||||
'disabled-opacity': 0.4,
|
||||
'border-color': '#E1DEF5',
|
||||
'border-opacity': 0.12,
|
||||
'table-header-color': '#535876',
|
||||
'high-emphasis-opacity': 0.9,
|
||||
'medium-emphasis-opacity': 0.7,
|
||||
'switch-opacity': 0.4,
|
||||
'switch-disabled-track-opacity': 0.4,
|
||||
'switch-disabled-thumb-opacity': 0.8,
|
||||
'switch-checked-disabled-opacity': 0.3,
|
||||
'track-bg': '#3A3F57',
|
||||
|
||||
// Shadows
|
||||
'shadow-key-umbra-color': '#131120',
|
||||
'shadow-xs-opacity': 0.16,
|
||||
'shadow-sm-opacity': 0.18,
|
||||
'shadow-md-opacity': 0.2,
|
||||
'shadow-lg-opacity': 0.22,
|
||||
'shadow-xl-opacity': 0.24,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default themes
|
||||
19
resources/ts/plugins/webfontloader.ts
Normal file
19
resources/ts/plugins/webfontloader.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* plugins/webfontloader.js
|
||||
*
|
||||
* webfontloader documentation: https://github.com/typekit/webfontloader
|
||||
*/
|
||||
|
||||
export async function loadFonts() {
|
||||
const webFontLoader = await import(/* webpackChunkName: "webfontloader" */'webfontloader')
|
||||
|
||||
webFontLoader.load({
|
||||
google: {
|
||||
families: ['Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap'],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export default function () {
|
||||
loadFonts()
|
||||
}
|
||||
Reference in New Issue
Block a user