2024-11-10 19:16:58 +00:00
|
|
|
<template>
|
2024-11-14 07:25:06 +00:00
|
|
|
<Drawer v-model:visible="$appState.designerActive" header="Theme Designer" position="right" class="designer !w-screen md:!w-[48rem]" :modal="false" :dismissable="false" @after-show="onShow" @after-hide="onHide">
|
|
|
|
<Tabs v-model:value="activeTab" :lazy="deferredTabs">
|
2024-11-10 19:16:58 +00:00
|
|
|
<TabList>
|
2024-11-12 12:38:29 +00:00
|
|
|
<Tab value="0">Base</Tab>
|
|
|
|
<Tab value="1">Primitive</Tab>
|
|
|
|
<Tab value="2">Semantic</Tab>
|
|
|
|
<Tab value="3">Component</Tab>
|
2024-11-12 20:39:51 +00:00
|
|
|
<Tab value="4">Custom</Tab>
|
2024-11-10 19:16:58 +00:00
|
|
|
</TabList>
|
|
|
|
<TabPanels class="!px-0">
|
|
|
|
<TabPanel value="0">
|
2024-11-13 11:35:07 +00:00
|
|
|
<div class="text-lg font-semibold mb-2">Choose a Theme to Get Started</div>
|
|
|
|
<span class="block text-muted-color leading-6 mb-4">Begin by selecting a built-in theme as a foundation, continue editing your current theme, or import a Figma tokens file.</span>
|
|
|
|
<div class="flex flex-col">
|
2024-11-12 12:38:29 +00:00
|
|
|
<div class="flex flex-col gap-4 border border-surface-200 dark:border-surface-700 rounded-md p-4">
|
2024-11-13 11:35:07 +00:00
|
|
|
<span class="font-semibold">Base Theme</span>
|
|
|
|
<span class="text-muted-color">Variety of built-in themes with distinct characteristics.</span>
|
2024-11-12 12:38:29 +00:00
|
|
|
<SelectButton v-model="$appState.preset" @update:modelValue="onPresetChange" :options="presetOptions" optionLabel="label" optionValue="value" :allowEmpty="false" />
|
|
|
|
</div>
|
|
|
|
<Divider>OR</Divider>
|
2024-11-12 13:44:52 +00:00
|
|
|
<div class="flex flex-col gap-4 border border-surface-200 dark:border-surface-700 rounded-md p-4 items-start">
|
|
|
|
<span class="font-semibold">Load Theme</span>
|
|
|
|
<span class="text-muted-color">Continue editing the theme files stored locally.</span>
|
|
|
|
<Button label="Restore from local storage" class="!px-3 !py-2" severity="secondary" @click="loadFromLocalStorage" />
|
2024-11-12 12:38:29 +00:00
|
|
|
</div>
|
|
|
|
<Divider>OR</Divider>
|
2024-11-12 13:44:52 +00:00
|
|
|
<div class="flex flex-col gap-4 border border-surface-200 dark:border-surface-700 rounded-md p-4">
|
|
|
|
<div class="flex items-center gap-4">
|
|
|
|
<span class="font-semibold">Import Figma Tokens </span>
|
|
|
|
<Tag value="PRO" severity="contrast"></Tag>
|
|
|
|
</div>
|
|
|
|
<span class="text-muted-color leading-6">Export the token studio json file and import to the Visual Editor. This feature is currently under development.</span>
|
|
|
|
<FileUpload mode="basic" disabled pt:root:class="!justify-start" />
|
2024-11-12 12:38:29 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</TabPanel>
|
|
|
|
<TabPanel value="1">
|
2024-11-10 19:16:58 +00:00
|
|
|
<div class="flex flex-col gap-3">
|
2024-11-13 11:35:07 +00:00
|
|
|
<form @keydown="onKeyDown" class="flex flex-col gap-3">
|
2024-11-13 10:00:37 +00:00
|
|
|
<DesignBorderRadius />
|
|
|
|
<DesignColors />
|
|
|
|
</form>
|
2024-11-10 19:16:58 +00:00
|
|
|
</div>
|
|
|
|
</TabPanel>
|
2024-11-12 12:38:29 +00:00
|
|
|
<TabPanel value="2">
|
2024-11-10 19:16:58 +00:00
|
|
|
<Accordion :value="['0', '1']" multiple>
|
|
|
|
<AccordionPanel value="0">
|
|
|
|
<AccordionHeader>Common</AccordionHeader>
|
|
|
|
<AccordionContent>
|
|
|
|
<div class="flex flex-col gap-3">
|
2024-11-13 11:35:07 +00:00
|
|
|
<form @keydown="onKeyDown" class="flex flex-col gap-3">
|
2024-11-13 10:00:37 +00:00
|
|
|
<DesignGeneral />
|
|
|
|
<DesignFormField />
|
|
|
|
<DesignList />
|
|
|
|
<DesignNavigation />
|
|
|
|
<DesignOverlay />
|
|
|
|
</form>
|
2024-11-10 19:16:58 +00:00
|
|
|
</div>
|
|
|
|
</AccordionContent>
|
|
|
|
</AccordionPanel>
|
|
|
|
|
|
|
|
<AccordionPanel value="1">
|
|
|
|
<AccordionHeader>Color Scheme</AccordionHeader>
|
|
|
|
<AccordionContent>
|
|
|
|
<Tabs value="cs-0">
|
|
|
|
<TabList>
|
|
|
|
<Tab value="cs-0">Light</Tab>
|
|
|
|
<Tab value="cs-1">Dark</Tab>
|
|
|
|
</TabList>
|
|
|
|
<TabPanels class="!px-0">
|
|
|
|
<TabPanel value="cs-0">
|
2024-11-13 10:00:37 +00:00
|
|
|
<form @keydown="onKeyDown">
|
|
|
|
<DesignCS :value="preset.semantic.colorScheme.light" />
|
|
|
|
</form>
|
2024-11-10 19:16:58 +00:00
|
|
|
</TabPanel>
|
|
|
|
<TabPanel value="cs-1">
|
2024-11-13 10:00:37 +00:00
|
|
|
<form @keydown="onKeyDown">
|
|
|
|
<DesignCS :value="preset.semantic.colorScheme.dark" />
|
|
|
|
</form>
|
2024-11-10 19:16:58 +00:00
|
|
|
</TabPanel>
|
|
|
|
</TabPanels>
|
|
|
|
</Tabs>
|
|
|
|
</AccordionContent>
|
|
|
|
</AccordionPanel>
|
|
|
|
</Accordion>
|
|
|
|
</TabPanel>
|
2024-11-13 11:35:07 +00:00
|
|
|
<TabPanel value="3">
|
2024-11-13 12:30:17 +00:00
|
|
|
<span class="leading-6 text-muted-color">Component tokens are not supported by the Visual Editor at the moment and will be available with a future update. </span>
|
2024-11-13 11:35:07 +00:00
|
|
|
</TabPanel>
|
2024-11-12 20:39:51 +00:00
|
|
|
<TabPanel value="4">
|
2024-11-13 12:30:17 +00:00
|
|
|
<span class="leading-6 text-muted-color">Extend the theming system with your own design tokens e.g. <span class="font-medium">accent.color</span>. Do not use curly braces in the name field.</span>
|
2024-11-12 20:39:51 +00:00
|
|
|
<ul class="flex flex-col gap-4 list-none p-0 mx-0 my-4">
|
|
|
|
<li v-for="(token, index) of customTokens" :key="index" class="first:border-t border-b border-surface-200 dark:border-surface-300 py-2">
|
|
|
|
<div class="flex items-center gap-4">
|
|
|
|
<label class="flex items-center gap-2 flex-auto">
|
|
|
|
<span class="text-sm">Name</span>
|
|
|
|
<input v-model="token['name']" type="text" class="border border-surface-300 dark:border-surface-600 rounded-lg py-2 px-2 w-full" />
|
|
|
|
</label>
|
|
|
|
<label class="flex items-center gap-2 flex-auto">
|
|
|
|
<span class="text-sm">Value</span>
|
|
|
|
<input v-model="token['value']" type="text" class="border border-surface-300 dark:border-surface-600 rounded-lg py-2 px-2 w-full" />
|
|
|
|
</label>
|
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
@click="removeToken(index)"
|
2024-11-13 11:35:07 +00:00
|
|
|
class="cursor-pointer inline-flex items-center justify-center ms-auto w-8 h-8 rounded-full bg-red-50 hover:bg-red-100 text-red-600 dark:bg-red-400/10 dark:hover:bg-red-400/20 dark:text-red-400 transition-colors duration-200 focus:outline focus:outline-offset-2 focus:outline-red-600 focus:dark:outline-red-400"
|
2024-11-12 20:39:51 +00:00
|
|
|
>
|
|
|
|
<i class="pi pi-times" />
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
<div class="flex justify-between">
|
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
@click="addToken"
|
2024-11-13 11:35:07 +00:00
|
|
|
class="px-3 py-2 bg-zinc-950 hover:bg-zinc-800 text-white dark:bg-white dark:hover:bg-gray-100 dark:text-black rounded-md font-medium cursor-pointer transition-colors duration-200 focus:outline focus:outline-offset-2 focus:outline-zinc-950 focus:dark:outline-white"
|
2024-11-12 20:39:51 +00:00
|
|
|
>
|
|
|
|
Add New
|
|
|
|
</button>
|
|
|
|
<button
|
2024-11-13 11:35:07 +00:00
|
|
|
v-if="customTokens.length"
|
2024-11-12 20:39:51 +00:00
|
|
|
type="button"
|
|
|
|
@click="saveTokens"
|
2024-11-13 11:35:07 +00:00
|
|
|
class="px-3 py-2 bg-zinc-950 hover:bg-zinc-800 text-white dark:bg-white dark:hover:bg-gray-100 dark:text-black rounded-md font-medium cursor-pointer transition-colors duration-200 focus:outline focus:outline-offset-2 focus:outline-zinc-950 focus:dark:outline-white"
|
2024-11-12 20:39:51 +00:00
|
|
|
>
|
|
|
|
Save
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</TabPanel>
|
2024-11-10 19:16:58 +00:00
|
|
|
</TabPanels>
|
|
|
|
</Tabs>
|
|
|
|
|
|
|
|
<template #footer>
|
2024-11-12 09:56:37 +00:00
|
|
|
<div class="flex justify-between gap-2">
|
2024-11-12 14:33:35 +00:00
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
@click="download"
|
|
|
|
icon="pi pi-download"
|
2024-11-13 11:35:07 +00:00
|
|
|
class="px-3 py-2 bg-transparent border border-gray-200 dark:border-gray-700 hover:border-gray-800 dark:hover:border-gray-500 text-black dark:text-white rounded-md font-medium cursor-pointer transition-colors duration-200 focus:outline focus:outline-offset-2 focus:outline-zinc-950 focus:dark:outline-white"
|
2024-11-12 14:33:35 +00:00
|
|
|
>
|
|
|
|
Download
|
|
|
|
</button>
|
|
|
|
<button
|
2024-11-13 12:27:37 +00:00
|
|
|
v-if="activeTab !== '0'"
|
2024-11-12 14:33:35 +00:00
|
|
|
type="button"
|
|
|
|
@click="apply"
|
2024-11-13 11:35:07 +00:00
|
|
|
class="px-3 py-2 bg-zinc-950 hover:bg-zinc-800 text-white dark:bg-white dark:hover:bg-gray-100 dark:text-black rounded-md font-medium cursor-pointer transition-colors duration-200 focus:outline focus:outline-offset-2 focus:outline-zinc-950 focus:dark:outline-white"
|
2024-11-12 14:33:35 +00:00
|
|
|
>
|
|
|
|
Apply
|
|
|
|
</button>
|
2024-11-10 19:16:58 +00:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</Drawer>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
2024-11-14 03:58:28 +00:00
|
|
|
import { NoirPreset } from '@/themes/app-theme.js';
|
2024-11-14 08:16:00 +00:00
|
|
|
import { $dt, $t, updatePreset, usePreset } from '@primevue/themes';
|
2024-11-12 12:38:29 +00:00
|
|
|
import Aura from '@primevue/themes/aura';
|
|
|
|
import Lara from '@primevue/themes/lara';
|
|
|
|
import Material from '@primevue/themes/material';
|
|
|
|
import Nora from '@primevue/themes/nora';
|
|
|
|
import { computed } from 'vue';
|
|
|
|
|
|
|
|
const presets = {
|
|
|
|
Aura,
|
|
|
|
Material,
|
|
|
|
Lara,
|
|
|
|
Nora
|
|
|
|
};
|
2024-11-10 19:16:58 +00:00
|
|
|
|
|
|
|
export default {
|
|
|
|
provide() {
|
|
|
|
return {
|
2024-11-12 23:14:58 +00:00
|
|
|
$preset: computed(() => this.preset),
|
|
|
|
$acTokens: computed(() => this.acTokens)
|
2024-11-10 19:16:58 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
2024-11-13 12:27:37 +00:00
|
|
|
activeTab: '0',
|
2024-11-14 07:25:06 +00:00
|
|
|
deferredTabs: true,
|
2024-11-12 12:38:29 +00:00
|
|
|
preset: {
|
2024-11-14 03:58:28 +00:00
|
|
|
primitive: NoirPreset.primitive,
|
|
|
|
semantic: NoirPreset.semantic
|
2024-11-12 12:38:29 +00:00
|
|
|
},
|
|
|
|
presetOptions: [
|
|
|
|
{ label: 'Aura', value: 'Aura' },
|
|
|
|
{ label: 'Material', value: 'Material' },
|
|
|
|
{ label: 'Lara', value: 'Lara' },
|
|
|
|
{ label: 'Nora', value: 'Nora' }
|
|
|
|
],
|
2024-11-12 23:14:58 +00:00
|
|
|
customTokens: [],
|
|
|
|
acTokens: []
|
2024-11-10 19:16:58 +00:00
|
|
|
};
|
|
|
|
},
|
2024-11-10 19:53:33 +00:00
|
|
|
mounted() {
|
2024-11-12 23:11:11 +00:00
|
|
|
this.replaceColorPalette();
|
2024-11-12 23:36:24 +00:00
|
|
|
this.generateACTokens(null, this.preset);
|
2024-11-10 19:53:33 +00:00
|
|
|
},
|
2024-11-10 19:16:58 +00:00
|
|
|
methods: {
|
2024-11-14 03:58:28 +00:00
|
|
|
getPresetExt() {
|
|
|
|
const color = this.primaryColors.find((c) => c.name === this.selectedPrimaryColor);
|
|
|
|
|
|
|
|
if (color.name === 'noir') {
|
|
|
|
document.documentElement.style.setProperty('--logo-color', 'var(--text-secondary-color)');
|
|
|
|
|
|
|
|
return {
|
|
|
|
semantic: {
|
|
|
|
primary: {
|
|
|
|
50: '{surface.50}',
|
|
|
|
100: '{surface.100}',
|
|
|
|
200: '{surface.200}',
|
|
|
|
300: '{surface.300}',
|
|
|
|
400: '{surface.400}',
|
|
|
|
500: '{surface.500}',
|
|
|
|
600: '{surface.600}',
|
|
|
|
700: '{surface.700}',
|
|
|
|
800: '{surface.800}',
|
|
|
|
900: '{surface.900}',
|
|
|
|
950: '{surface.950}'
|
|
|
|
},
|
|
|
|
colorScheme: {
|
|
|
|
light: {
|
|
|
|
primary: {
|
|
|
|
color: '{primary.950}',
|
|
|
|
contrastColor: '#ffffff',
|
|
|
|
hoverColor: '{primary.800}',
|
|
|
|
activeColor: '{primary.700}'
|
|
|
|
},
|
|
|
|
highlight: {
|
|
|
|
background: '{primary.950}',
|
|
|
|
focusBackground: '{primary.700}',
|
|
|
|
color: '#ffffff',
|
|
|
|
focusColor: '#ffffff'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
dark: {
|
|
|
|
primary: {
|
|
|
|
color: '{primary.50}',
|
|
|
|
contrastColor: '{primary.950}',
|
|
|
|
hoverColor: '{primary.200}',
|
|
|
|
activeColor: '{primary.300}'
|
|
|
|
},
|
|
|
|
highlight: {
|
|
|
|
background: '{primary.50}',
|
|
|
|
focusBackground: '{primary.300}',
|
|
|
|
color: '{primary.950}',
|
|
|
|
focusColor: '{primary.950}'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
document.documentElement.style.setProperty('--logo-color', 'var(--primary-color)');
|
|
|
|
|
|
|
|
if (this.$appState.preset === 'Nora') {
|
|
|
|
return {
|
|
|
|
semantic: {
|
|
|
|
primary: color.palette,
|
|
|
|
colorScheme: {
|
|
|
|
light: {
|
|
|
|
primary: {
|
|
|
|
color: '{primary.600}',
|
|
|
|
contrastColor: '#ffffff',
|
|
|
|
hoverColor: '{primary.700}',
|
|
|
|
activeColor: '{primary.800}'
|
|
|
|
},
|
|
|
|
highlight: {
|
|
|
|
background: '{primary.600}',
|
|
|
|
focusBackground: '{primary.700}',
|
|
|
|
color: '#ffffff',
|
|
|
|
focusColor: '#ffffff'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
dark: {
|
|
|
|
primary: {
|
|
|
|
color: '{primary.500}',
|
|
|
|
contrastColor: '{surface.900}',
|
|
|
|
hoverColor: '{primary.400}',
|
|
|
|
activeColor: '{primary.300}'
|
|
|
|
},
|
|
|
|
highlight: {
|
|
|
|
background: '{primary.500}',
|
|
|
|
focusBackground: '{primary.400}',
|
|
|
|
color: '{surface.900}',
|
|
|
|
focusColor: '{surface.900}'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} else if (this.$appState.preset === 'Material') {
|
|
|
|
return {
|
|
|
|
semantic: {
|
|
|
|
primary: color.palette,
|
|
|
|
colorScheme: {
|
|
|
|
light: {
|
|
|
|
primary: {
|
|
|
|
color: '{primary.500}',
|
|
|
|
contrastColor: '#ffffff',
|
|
|
|
hoverColor: '{primary.400}',
|
|
|
|
activeColor: '{primary.300}'
|
|
|
|
},
|
|
|
|
highlight: {
|
|
|
|
background: 'color-mix(in srgb, {primary.color}, transparent 88%)',
|
|
|
|
focusBackground: 'color-mix(in srgb, {primary.color}, transparent 76%)',
|
|
|
|
color: '{primary.700}',
|
|
|
|
focusColor: '{primary.800}'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
dark: {
|
|
|
|
primary: {
|
|
|
|
color: '{primary.400}',
|
|
|
|
contrastColor: '{surface.900}',
|
|
|
|
hoverColor: '{primary.300}',
|
|
|
|
activeColor: '{primary.200}'
|
|
|
|
},
|
|
|
|
highlight: {
|
|
|
|
background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
|
|
|
|
focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
|
|
|
|
color: 'rgba(255,255,255,.87)',
|
|
|
|
focusColor: 'rgba(255,255,255,.87)'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return {
|
|
|
|
semantic: {
|
|
|
|
primary: color.palette,
|
|
|
|
colorScheme: {
|
|
|
|
light: {
|
|
|
|
primary: {
|
|
|
|
color: '{primary.500}',
|
|
|
|
contrastColor: '#ffffff',
|
|
|
|
hoverColor: '{primary.600}',
|
|
|
|
activeColor: '{primary.700}'
|
|
|
|
},
|
|
|
|
highlight: {
|
|
|
|
background: '{primary.50}',
|
|
|
|
focusBackground: '{primary.100}',
|
|
|
|
color: '{primary.700}',
|
|
|
|
focusColor: '{primary.800}'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
dark: {
|
|
|
|
primary: {
|
|
|
|
color: '{primary.400}',
|
|
|
|
contrastColor: '{surface.900}',
|
|
|
|
hoverColor: '{primary.300}',
|
|
|
|
activeColor: '{primary.200}'
|
|
|
|
},
|
|
|
|
highlight: {
|
|
|
|
background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
|
|
|
|
focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
|
|
|
|
color: 'rgba(255,255,255,.87)',
|
|
|
|
focusColor: 'rgba(255,255,255,.87)'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2024-11-10 19:16:58 +00:00
|
|
|
apply() {
|
2024-11-12 12:38:29 +00:00
|
|
|
this.saveTheme();
|
2024-11-10 19:16:58 +00:00
|
|
|
updatePreset(this.preset);
|
2024-11-12 09:56:37 +00:00
|
|
|
},
|
|
|
|
download() {
|
2024-11-13 12:17:12 +00:00
|
|
|
const basePreset = this.$appState.preset;
|
2024-11-12 09:56:37 +00:00
|
|
|
const theme = JSON.stringify(this.preset, null, 4).replace(/"([^"]+)":/g, '$1:');
|
|
|
|
const textContent = `import { createApp } from "vue";
|
|
|
|
import PrimeVue from "primevue/config";
|
2024-11-13 12:17:12 +00:00
|
|
|
import {${basePreset}} from "@primevue/themes/${basePreset.toLowerCase()}";
|
2024-11-12 09:56:37 +00:00
|
|
|
import { definePreset } from "@primevue/themes";
|
|
|
|
|
|
|
|
const app = createApp(App);
|
|
|
|
|
2024-11-13 12:17:12 +00:00
|
|
|
const MyPreset = definePreset(${basePreset}, ${theme});
|
2024-11-12 09:56:37 +00:00
|
|
|
|
|
|
|
app.use(PrimeVue, {
|
|
|
|
theme: {
|
|
|
|
preset: MyPreset
|
|
|
|
},
|
|
|
|
});
|
|
|
|
app.mount("#app");
|
|
|
|
`;
|
|
|
|
const blob = new Blob([textContent], { type: 'text/plain' });
|
|
|
|
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
|
|
|
a.href = url;
|
|
|
|
a.download = 'mytheme.js';
|
|
|
|
document.body.appendChild(a);
|
|
|
|
a.click();
|
|
|
|
|
|
|
|
document.body.removeChild(a);
|
|
|
|
URL.revokeObjectURL(url);
|
2024-11-12 12:38:29 +00:00
|
|
|
},
|
|
|
|
onPresetChange(value) {
|
|
|
|
this.$appState.preset = value;
|
|
|
|
const newPreset = presets[value];
|
|
|
|
|
|
|
|
if (value === 'Material') {
|
|
|
|
document.body.classList.add('material');
|
|
|
|
this.$primevue.config.ripple = true;
|
|
|
|
} else {
|
|
|
|
document.body.classList.remove('material');
|
|
|
|
}
|
|
|
|
|
2024-11-14 03:58:28 +00:00
|
|
|
/*
|
|
|
|
@todo: ask to the team about this
|
2024-11-12 12:38:29 +00:00
|
|
|
this.preset = {
|
|
|
|
primitive: newPreset.primitive,
|
|
|
|
semantic: newPreset.semantic
|
|
|
|
};
|
2024-11-12 23:11:11 +00:00
|
|
|
|
|
|
|
this.preset.semantic.primary = this.preset.primitive.emerald;
|
|
|
|
this.preset.semantic.colorScheme.light.surface = { ...{ 0: '#ffffff' }, ...this.preset.primitive.slate };
|
|
|
|
this.preset.semantic.colorScheme.dark.surface = { ...{ 0: '#ffffff' }, ...this.preset.primitive.zinc };
|
|
|
|
|
|
|
|
usePreset(this.preset);
|
2024-11-14 03:58:28 +00:00
|
|
|
*/
|
|
|
|
const currentPreset = $t().preset(newPreset).preset(this.getPresetExt()).use({ useDefaultOptions: true }).preset;
|
|
|
|
|
|
|
|
this.preset = {
|
|
|
|
primitive: currentPreset.primitive,
|
|
|
|
semantic: currentPreset.semantic
|
|
|
|
};
|
2024-11-12 12:38:29 +00:00
|
|
|
},
|
|
|
|
saveTheme() {
|
2024-11-12 23:11:11 +00:00
|
|
|
const localState = {
|
|
|
|
themes: {
|
|
|
|
defaultTheme: {
|
|
|
|
preset: this.preset,
|
|
|
|
customTokens: this.customTokens
|
|
|
|
}
|
|
|
|
}
|
2024-11-12 12:38:29 +00:00
|
|
|
};
|
|
|
|
|
2024-11-12 23:11:11 +00:00
|
|
|
localStorage.setItem(this.$appState.designerKey, JSON.stringify(localState));
|
2024-11-12 13:44:52 +00:00
|
|
|
},
|
|
|
|
loadFromLocalStorage() {
|
2024-11-12 23:11:11 +00:00
|
|
|
const localState = localStorage.getItem(this.$appState.designerKey);
|
|
|
|
|
|
|
|
if (localState) {
|
|
|
|
const parsedLocalState = JSON.parse(localState);
|
2024-11-12 13:44:52 +00:00
|
|
|
|
2024-11-12 23:11:11 +00:00
|
|
|
if (parsedLocalState?.themes?.defaultTheme) {
|
|
|
|
const defaultTheme = parsedLocalState.themes.defaultTheme;
|
2024-11-12 20:39:51 +00:00
|
|
|
|
2024-11-12 23:11:11 +00:00
|
|
|
if (defaultTheme.preset) {
|
|
|
|
this.preset = defaultTheme.preset;
|
2024-11-13 11:35:07 +00:00
|
|
|
usePreset(this.preset);
|
2024-11-12 23:11:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (defaultTheme.customTokens) {
|
|
|
|
this.customTokens = defaultTheme.customTokens;
|
2024-11-12 23:39:09 +00:00
|
|
|
this.refreshACTokens();
|
2024-11-12 23:11:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.$toast.add({ severity: 'success', summary: 'Success', detail: 'Theme loaded to Designer', life: 3000 });
|
|
|
|
}
|
2024-11-12 13:44:52 +00:00
|
|
|
}
|
2024-11-12 20:39:51 +00:00
|
|
|
},
|
|
|
|
addToken() {
|
|
|
|
this.customTokens = [...this.customTokens, ...[{}]];
|
|
|
|
},
|
|
|
|
removeToken(index) {
|
|
|
|
this.customTokens.splice(index, 1);
|
|
|
|
},
|
|
|
|
saveTokens() {
|
2024-11-12 23:11:11 +00:00
|
|
|
this.preset.extend = {};
|
|
|
|
this.customTokens.forEach((token) => {
|
|
|
|
this.preset.extend[this.transformTokenName(token.name)] = token.value;
|
|
|
|
});
|
2024-11-12 20:39:51 +00:00
|
|
|
|
2024-11-12 23:39:09 +00:00
|
|
|
this.refreshACTokens();
|
2024-11-12 23:11:11 +00:00
|
|
|
this.saveTheme();
|
|
|
|
this.$toast.add({ severity: 'success', summary: 'Success', detail: 'Tokens saved', life: 3000 });
|
|
|
|
},
|
|
|
|
replaceColorPalette() {
|
2024-11-14 03:58:28 +00:00
|
|
|
/*
|
|
|
|
@todo: ask to the team about this
|
2024-11-12 23:11:11 +00:00
|
|
|
this.preset.semantic.primary = this.preset.primitive.emerald;
|
|
|
|
this.preset.semantic.colorScheme.light.surface = { ...{ 0: '#ffffff' }, ...this.preset.primitive.slate };
|
|
|
|
this.preset.semantic.colorScheme.dark.surface = { ...{ 0: '#ffffff' }, ...this.preset.primitive.zinc };
|
2024-11-14 03:58:28 +00:00
|
|
|
*/
|
2024-11-12 23:11:11 +00:00
|
|
|
},
|
|
|
|
transformTokenName(name) {
|
|
|
|
if (name && name.trim().length) {
|
|
|
|
let tokenNameSections = name.split('.');
|
|
|
|
let transformedName = '';
|
2024-11-12 20:39:51 +00:00
|
|
|
|
2024-11-12 23:11:11 +00:00
|
|
|
tokenNameSections.forEach((section, index) => {
|
|
|
|
transformedName += index === 0 ? section : section.charAt(0).toUpperCase() + section.substring(1);
|
|
|
|
});
|
2024-11-12 20:39:51 +00:00
|
|
|
|
2024-11-12 23:11:11 +00:00
|
|
|
return transformedName;
|
|
|
|
} else {
|
|
|
|
return name;
|
|
|
|
}
|
2024-11-12 23:14:58 +00:00
|
|
|
},
|
2024-11-12 23:36:24 +00:00
|
|
|
camelCaseToDotCase(name) {
|
2024-11-14 08:16:00 +00:00
|
|
|
return name.replace(/([a-z])([A-Z])/g, '$1.$2').toLowerCase();
|
2024-11-12 23:36:24 +00:00
|
|
|
},
|
|
|
|
generateACTokens(parentPath, obj) {
|
|
|
|
for (let key in obj) {
|
|
|
|
if (key === 'dark') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key === 'primitive' || key === 'semantic' || key === 'colorScheme' || key === 'light' || key === 'extend') {
|
|
|
|
this.generateACTokens(null, obj[key]);
|
|
|
|
} else {
|
|
|
|
if (typeof obj[key] === 'object') {
|
|
|
|
this.generateACTokens(parentPath ? parentPath + '.' + key : key, obj[key]);
|
|
|
|
} else {
|
2024-11-14 08:16:00 +00:00
|
|
|
const regex = /\.\d+$/;
|
|
|
|
const tokenName = this.camelCaseToDotCase(parentPath ? parentPath + '.' + key : key);
|
|
|
|
const tokenValue = $dt(tokenName).value;
|
|
|
|
const isColor = tokenName.includes('color') || tokenName.includes('background') || regex.test(tokenName);
|
|
|
|
|
|
|
|
this.acTokens.push({ token: tokenName, label: '{' + tokenName + '}', variable: $dt(tokenName).variable, value: tokenValue, isColor: isColor });
|
2024-11-12 23:36:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-11-12 23:39:09 +00:00
|
|
|
},
|
|
|
|
refreshACTokens() {
|
|
|
|
this.acTokens = [];
|
|
|
|
this.generateACTokens(null, this.preset);
|
2024-11-13 10:00:37 +00:00
|
|
|
},
|
|
|
|
onKeyDown(event) {
|
|
|
|
if (event.code === 'Enter' || event.code === 'NumpadEnter') {
|
|
|
|
this.apply();
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
2024-11-14 07:25:06 +00:00
|
|
|
},
|
|
|
|
onShow() {
|
|
|
|
this.deferredTabs = false;
|
|
|
|
},
|
|
|
|
onHide() {
|
|
|
|
this.deferredTabs = true;
|
2024-11-10 19:16:58 +00:00
|
|
|
}
|
2024-11-14 03:58:28 +00:00
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
selectedPrimaryColor() {
|
|
|
|
return this.$appState.primary;
|
|
|
|
},
|
|
|
|
selectedSurfaceColor() {
|
|
|
|
return this.$appState.surface;
|
|
|
|
},
|
|
|
|
primaryColors() {
|
|
|
|
const presetPalette = presets[this.$appState.preset].primitive;
|
|
|
|
const colors = ['emerald', 'green', 'lime', 'orange', 'amber', 'yellow', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose'];
|
|
|
|
const palettes = [{ name: 'noir', palette: {} }];
|
|
|
|
|
|
|
|
colors.forEach((color) => {
|
|
|
|
palettes.push({
|
|
|
|
name: color,
|
|
|
|
palette: presetPalette[color]
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return palettes;
|
|
|
|
}
|
2024-11-10 19:16:58 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|