Merge pull request #7277 from cagataycivici/master

Designer Updates
pull/7278/head
Cagatay Civici 2025-02-19 00:08:54 +03:00 committed by GitHub
commit df126faa28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 189 additions and 118 deletions

View File

@ -5,10 +5,6 @@ html {
line-height: normal; line-height: normal;
} }
.material {
font-family: "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
body { body {
margin: 0px; margin: 0px;
min-height: 100%; min-height: 100%;

View File

@ -13,6 +13,23 @@
cursor: pointer; cursor: pointer;
} }
input:focus-visible {
outline: 1px solid var(--designer-focus-outline-color);
outline-offset: 0px;
}
button:focus-visible {
outline: 1px solid var(--designer-focus-outline-color);
outline-offset: 2px;
}
.p-icon,
.pi {
font-size: 14px !important;
width: 14px !important;
height: 14px !important;
}
[type='color']::-webkit-color-swatch { [type='color']::-webkit-color-swatch {
border-radius: 4px; border-radius: 4px;
width: 24px; width: 24px;
@ -25,15 +42,15 @@
} }
&.p-drawer { &.p-drawer {
background: light-dark(var(--p-surface-0), var(--p-surface-900)); background: var(--overlay-background);
border-color: light-dark(var(--p-surface-200), var(--p-surface-700)); border-color: var(--border-color);
color: light-dark(#09090b, #ffffff); color: var(--high-contrast-text-color);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1); box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
} }
.p-fieldset { .p-fieldset {
background: transparent; background: transparent;
border-color: light-dark(var(--p-surface-200), var(--p-surface-700)); border-color: var(--border-color);
border-radius: 4px; border-radius: 4px;
color: inherit; color: inherit;
padding: 0 1.125rem 1.125rem 1.125rem; padding: 0 1.125rem 1.125rem 1.125rem;
@ -56,7 +73,11 @@
background: transparent; background: transparent;
border: 0 none; border: 0 none;
border-radius: 4px; border-radius: 4px;
outline-color: transparent;
&:focus-visible {
outline: 1px solid var(--designer-focus-outline-color);
outline-offset: -1px;
}
} }
.p-fieldset-toggle-icon { .p-fieldset-toggle-icon {
@ -84,37 +105,43 @@
.p-tablist-tab-list { .p-tablist-tab-list {
background: transparent; background: transparent;
border-style: solid; border-style: solid;
border-color: light-dark(var(--p-surface-200), var(--p-surface-700)); border-color: var(--border-color);
border-width: 0 0 1px 0; border-width: 0 0 1px 0;
} }
.p-tab { .p-tab {
background: transparent; background: transparent;
border-width: 0 0 1px 0; border-width: 0 0 1px 0;
border-color: light-dark(var(--p-surface-200), var(--p-surface-700)); border-color: var(--border-color);
color: light-dark(var(--p-surface-500), var(--p-surface-400)); color: var(--text-secondary-color);
padding: 1rem 1.125rem; padding: 1rem 1.125rem;
font-weight: 600; font-weight: 600;
transition: none; transition: none;
margin: 0 0 -1px 0; margin: 0 0 -1px 0;
&:focus-visible {
outline: 1px solid var(--designer-focus-outline-color);
outline-offset: -1px;
}
} }
.p-tab:not(.p-tab-active):not(.p-disabled):hover { .p-tab:not(.p-tab-active):not(.p-disabled):hover {
background: transparent; background: transparent;
border-color: transparent; border-color: transparent;
color: light-dark(var(--p-surface-700), var(--p-surface-0)); color: var(--high-contrast-text-color);
} }
.p-tab-active { .p-tab-active {
background: transparent; background: transparent;
border-color: transparent; border-color: var(--high-contrast-text-color);
color: light-dark(#09090b, #ffffff); color: var(--high-contrast-text-color);
} }
.p-tablist-active-bar { .p-tablist-active-bar {
display: none;
inset-block-end: -1px; inset-block-end: -1px;
height: 1px; height: 1px;
background: light-dark(#09090b, #ffffff); background: var(--high-contrast-text-color);
transition: 250ms cubic-bezier(0.35, 0, 0.25, 1); transition: 250ms cubic-bezier(0.35, 0, 0.25, 1);
} }
@ -123,23 +150,35 @@
color: inherit; color: inherit;
padding: 0.875rem 0 1.125rem 0; padding: 0.875rem 0 1.125rem 0;
} }
.p-tabpanel {
&:focus-visible {
outline: 1px solid var(--designer-focus-outline-color);
outline-offset: 0;
}
}
} }
.p-accordion { .p-accordion {
.p-accordionpanel { .p-accordionpanel {
border-width: 0 0 1px 0; border-width: 0 0 1px 0;
border-color: light-dark(var(--p-surface-200), var(--p-surface-700)); border-color: var(--border-color);
} }
.p-accordionheader { .p-accordionheader {
padding: 1.125rem; padding: 1.125rem;
color: light-dark(var(--p-surface-500), var(--p-surface-400)); color: var(--text-secondary-color);
background: transparent; background: transparent;
border-width: 0; border-width: 0;
border-color: unset; border-color: unset;
font-weight: 600; font-weight: 600;
border-radius: 4px; border-radius: 4px;
transition: none; transition: none;
&:focus-visible {
outline: 1px solid var(--designer-focus-outline-color);
outline-offset: -1px;
}
} }
.p-accordionpanel:first-child>.p-accordionheader { .p-accordionpanel:first-child>.p-accordionheader {
@ -159,13 +198,13 @@
} }
.p-accordionheader-toggle-icon { .p-accordionheader-toggle-icon {
color: light-dark(var(--p-surface-500), var(--p-surface-400)); color: var(--text-secondary-color);
} }
.p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled)>.p-accordionheader:hover, .p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled)>.p-accordionheader:hover,
.p-accordionpanel:not(.p-disabled).p-accordionpanel-active>.p-accordionheader { .p-accordionpanel:not(.p-disabled).p-accordionpanel-active>.p-accordionheader {
background: transparent; background: transparent;
color: light-dark(var(--p-surface-700), var(--p-surface-0)); color: var(--text-color);
} }
.p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled) .p-accordionheader:hover .p-accordionheader-toggle-icon, .p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled) .p-accordionheader:hover .p-accordionheader-toggle-icon,
@ -175,7 +214,7 @@
.p-accordioncontent-content { .p-accordioncontent-content {
border-width: 0; border-width: 0;
border-color: light-dark(var(--p-surface-200), var(--p-surface-700)); border-color: var(--border-color);
background-color: transparent; background-color: transparent;
color: inherit; color: inherit;
padding: 0 1.125rem 1.125rem 1.125rem; padding: 0 1.125rem 1.125rem 1.125rem;
@ -184,21 +223,23 @@
.p-fileupload-choose-button { .p-fileupload-choose-button {
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
background: light-dark(#09090b, #ffffff); background: var(--designer-primary-color);
border-color: light-dark(#09090b, #ffffff); border-color: var(--designer-primary-color);
color: light-dark(#ffffff, #000000); color: var(--designer-primary-contrast-color);
cursor: pointer; cursor: pointer;
font-weight: medium; font-weight: medium;
border-radius: 4px; border-radius: 4px;
transition: background 0.2s; transition: background-color 0.2s;
&:hover { &:enabled:hover,
background: light-dark(#27272a, #f3f4f6); &:enabled:active {
border-color: light-dark(#27272a, #f3f4f6); background: var(--designer-primary-emphasis-color);
border-color: var(--designer-primary-emphasis-color);
} }
&:focus-visible { &:enabled:active,
outline: 1px solid light-dark(#09090b, #ffffff); &:enabled:focus-visible {
outline: 1px solid var(--designer-primary-color);
outline-offset: 2px; outline-offset: 2px;
box-shadow: none; box-shadow: none;
} }

View File

@ -1,14 +1,14 @@
:root[class="p-dark"] { :root[class="p-dark"] {
--primary-text-color:var(--p-primary-400); --primary-text-color: var(--p-primary-400);
--primary-color: var(--p-primary-color); --primary-color: var(--p-primary-color);
--primary-contrast-color:var(--p-primary-contrast-color); --primary-contrast-color: var(--p-primary-contrast-color);
--primary-hover-color: var(--p-primary-hover-color); --primary-hover-color: var(--p-primary-hover-color);
--text-color: var(--p-surface-0); --text-color: var(--p-surface-0);
--text-secondary-color: var(--p-surface-400); --text-secondary-color: var(--p-surface-400);
--glow-image: url(https://www.primefaces.org/cdn/primevue/images/layout/pattern.png), radial-gradient(50% 50% at center -25px, var(--p-primary-color) 0%, #000000 100%); --glow-image: url(https://www.primefaces.org/cdn/primevue/images/layout/pattern.png), radial-gradient(50% 50% at center -25px, var(--p-primary-color) 0%, #000000 100%);
--glow-blend: hard-light, color-dodge; --glow-blend: hard-light, color-dodge;
--topbar-sticky-background:rgba(0,0,0,.3); --topbar-sticky-background: rgba(0, 0, 0, .3);
--mobile-menu-background: rgba(0,0,0,.3); --mobile-menu-background: rgba(0, 0, 0, .3);
--card-border: 1px solid transparent; --card-border: 1px solid transparent;
--card-background: var(--p-surface-900); --card-background: var(--p-surface-900);
--border-color: var(--p-surface-700); --border-color: var(--p-surface-700);
@ -25,4 +25,8 @@
--code-button-text-color: var(--p-surface-300); --code-button-text-color: var(--p-surface-300);
--docsearch-mask-background: var(--p-mask-background); --docsearch-mask-background: var(--p-mask-background);
--logo-color: var(--text-secondary-color); --logo-color: var(--text-secondary-color);
--designer-primary-color: #ffffff;
--designer-primary-emphasis-color: #f3f4f6;
--designer-primary-contrast-color: #000000;
--designer-focus-outline-color: #ffffff;
} }

View File

@ -25,4 +25,8 @@
--code-button-text-color: var(--p-surface-300); --code-button-text-color: var(--p-surface-300);
--docsearch-mask-background: var(--p-mask-background); --docsearch-mask-background: var(--p-mask-background);
--logo-color: var(--text-secondary-color); --logo-color: var(--text-secondary-color);
--designer-primary-color: #09090b;
--designer-primary-emphasis-color: #27272a;
--designer-primary-contrast-color: #ffffff;
--designer-focus-outline-color: #09090b;
} }

View File

@ -306,13 +306,6 @@ export default {
const preset = presets[value]; const preset = presets[value];
const surfacePalette = this.surfaces.find((s) => s.name === this.selectedSurfaceColor)?.palette; const surfacePalette = this.surfaces.find((s) => s.name === this.selectedSurfaceColor)?.palette;
if (value === 'Material') {
document.body.classList.add('material');
this.$primevue.config.ripple = true;
} else {
document.body.classList.remove('material');
}
$t().preset(preset).preset(this.getPresetExt()).surfacePalette(surfacePalette).use({ useDefaultOptions: true }); $t().preset(preset).preset(this.getPresetExt()).surfacePalette(surfacePalette).use({ useDefaultOptions: true });
}, },
onRTLChange(value) { onRTLChange(value) {

View File

@ -1,5 +1,5 @@
<template> <template>
<Drawer v-model:visible="$appState.designer.active" position="right" class="designer !w-screen md:!w-[48rem]" :modal="false" :dismissable="false" @after-show="onShow" @after-hide="onHide"> <Drawer v-model:visible="$appState.designer.active" position="right" class="designer !w-screen md:!w-[48rem]" :modal="false" :dismissable="false" blockScroll @after-show="onShow" @after-hide="onHide">
<template #container="{ closeCallback }"> <template #container="{ closeCallback }">
<div class="flex items-center justify-between p-5"> <div class="flex items-center justify-between p-5">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@ -34,7 +34,7 @@
<script> <script>
import EventBus from '@/app/AppEventBus'; import EventBus from '@/app/AppEventBus';
import { $dt, updatePreset, usePreset } from '@primeuix/themes'; import { $dt, usePreset } from '@primeuix/themes';
export default { export default {
setup() { setup() {
@ -53,7 +53,7 @@ export default {
activateTheme: this.activateTheme, activateTheme: this.activateTheme,
applyTheme: this.applyTheme, applyTheme: this.applyTheme,
applyFont: this.applyFont, applyFont: this.applyFont,
replaceColorPalette: this.replaceColorPalette resolveColor: this.resolveColor
} }
}; };
}, },
@ -140,9 +140,10 @@ export default {
applyTheme(theme) { applyTheme(theme) {
if (this.$appState.designer.verified) { if (this.$appState.designer.verified) {
this.saveTheme(theme); this.saveTheme(theme);
this.refreshACTokens();
} }
updatePreset(theme.preset); usePreset(theme.preset);
EventBus.emit('theme-palette-change'); EventBus.emit('theme-palette-change');
}, },
camelCaseToDotCase(name) { camelCaseToDotCase(name) {
@ -163,7 +164,7 @@ export default {
const regex = /\.\d+$/; const regex = /\.\d+$/;
const tokenName = this.camelCaseToDotCase(parentPath ? parentPath + '.' + key : key); const tokenName = this.camelCaseToDotCase(parentPath ? parentPath + '.' + key : key);
const tokenValue = $dt(tokenName).value; const tokenValue = obj[key];
const isColor = tokenName.includes('color') || tokenName.includes('background') || regex.test(tokenName); const isColor = tokenName.includes('color') || tokenName.includes('background') || regex.test(tokenName);
this.$appState.designer.acTokens.push({ token: tokenName, label: '{' + tokenName + '}', variable: $dt(tokenName).variable, value: tokenValue, isColor: isColor }); this.$appState.designer.acTokens.push({ token: tokenName, label: '{' + tokenName + '}', variable: $dt(tokenName).variable, value: tokenValue, isColor: isColor });
@ -207,11 +208,6 @@ export default {
// silent fail as some fonts may have not all the font weights // silent fail as some fonts may have not all the font weights
} }
}, },
replaceColorPalette() {
this.$appState.designer.theme.preset.semantic.primary = this.$appState.designer.theme.preset.primitive.emerald;
this.$appState.designer.theme.preset.semantic.colorScheme.light.surface = { ...{ 0: '#ffffff' }, ...this.$appState.designer.theme.preset.primitive.slate };
this.$appState.designer.theme.preset.semantic.colorScheme.dark.surface = { ...{ 0: '#ffffff' }, ...this.$appState.designer.theme.preset.primitive.zinc };
},
toggleDarkMode() { toggleDarkMode() {
EventBus.emit('dark-mode-toggle', { dark: !this.$appState.darkTheme }); EventBus.emit('dark-mode-toggle', { dark: !this.$appState.darkTheme });
}, },
@ -226,7 +222,6 @@ export default {
usePreset(this.$appState.designer.theme.preset); usePreset(this.$appState.designer.theme.preset);
this.applyFont(this.$appState.designer.theme.config.font_family); this.applyFont(this.$appState.designer.theme.config.font_family);
document.documentElement.style.fontSize = this.$appState.designer.theme.config.font_size; document.documentElement.style.fontSize = this.$appState.designer.theme.config.font_size;
this.replaceColorPalette();
this.refreshACTokens(); this.refreshACTokens();
}, },
getCookie(name) { getCookie(name) {
@ -241,6 +236,14 @@ export default {
} }
return null; return null;
},
resolveColor(token) {
if (token.startsWith('{') && token.endsWith('}')) {
let cssVariable = $dt(token).variable.slice(4, -1);
return getComputedStyle(document.documentElement).getPropertyValue(cssVariable);
} else {
return token;
}
} }
}, },
computed: { computed: {

View File

@ -98,46 +98,13 @@ export default {
}, },
methods: { methods: {
async createThemeFromPreset() { async createThemeFromPreset() {
const newPreset = presets[this.basePreset]; if (this.themeName == null || !this.themeName.trim().length) {
this.$toast.add({ severity: 'error', summary: 'Error', detail: 'Name is required', life: 3000 });
if (this.basePreset === 'Material') {
document.body.classList.add('material');
this.$primevue.config.ripple = true;
} else { } else {
document.body.classList.remove('material'); const newPreset = presets[this.basePreset];
}
if (this.$appState.designer.verified) {
const { data, error } = await $fetch(this.designerApiUrl + '/theme/create', {
method: 'POST',
credentials: 'include',
headers: {
'X-CSRF-Token': this.$appState.designer.csrfToken
},
body: {
name: this.themeName,
preset: newPreset,
project: 'primevue',
config: {
font_size: '14px',
font_family: 'Inter var'
}
}
});
if (error) {
this.$toast.add({ severity: 'error', summary: 'An error occured', detail: error.message, life: 3000 });
} else {
this.loadThemeEditor(data.t_key, newPreset);
}
} else {
this.loadThemeEditor('trial', newPreset);
}
},
async createThemeFromFigma() {
if (this.figmaData) {
if (this.$appState.designer.verified) { if (this.$appState.designer.verified) {
const { data, error } = await $fetch(this.designerApiUrl + '/theme/figma', { const { data, error } = await $fetch(this.designerApiUrl + '/theme/create', {
method: 'POST', method: 'POST',
credentials: 'include', credentials: 'include',
headers: { headers: {
@ -145,8 +112,9 @@ export default {
}, },
body: { body: {
name: this.themeName, name: this.themeName,
figma_tokens: this.figmaData, preset: newPreset,
project: 'primevue', project: 'primevue',
base: this.basePreset,
config: { config: {
font_size: '14px', font_size: '14px',
font_family: 'Inter var' font_family: 'Inter var'
@ -157,17 +125,52 @@ export default {
if (error) { if (error) {
this.$toast.add({ severity: 'error', summary: 'An error occured', detail: error.message, life: 3000 }); this.$toast.add({ severity: 'error', summary: 'An error occured', detail: error.message, life: 3000 });
} else { } else {
this.loadThemeEditor(data.t_key, data.t_preset); this.loadThemeEditor(data.t_key, newPreset);
if (data.lostAndFound?.length) {
this.$toast.add({ severity: 'warn', summary: 'Warning', detail: 'There are missing tokens. An update is recommended using the "Migration Assistant" in the settings section.' });
}
} }
} else { } else {
this.$toast.add({ severity: 'error', summary: 'An error occured', detail: 'A valid license required', life: 3000 }); this.loadThemeEditor('trial', newPreset);
} }
}
},
async createThemeFromFigma() {
if (this.themeName == null || !this.themeName.trim().length) {
this.$toast.add({ severity: 'error', summary: 'Error', detail: 'Name is required', life: 3000 });
} else { } else {
this.$toast.add({ severity: 'error', summary: 'An error occured', detail: 'File is required', life: 3000 }); if (this.figmaData) {
if (this.$appState.designer.verified) {
const { data, error } = await $fetch(this.designerApiUrl + '/theme/figma', {
method: 'POST',
credentials: 'include',
headers: {
'X-CSRF-Token': this.$appState.designer.csrfToken
},
body: {
name: this.themeName,
figma_tokens: this.figmaData,
project: 'primevue',
base: 'Figma',
config: {
font_size: '14px',
font_family: 'Inter var'
}
}
});
if (error) {
this.$toast.add({ severity: 'error', summary: 'An error occured', detail: error.message, life: 3000 });
} else {
this.loadThemeEditor(data.t_key, data.t_preset);
if (data.lostAndFound?.length) {
this.$toast.add({ severity: 'warn', summary: 'Warning', detail: 'There are missing tokens. An update is recommended using the "Migration Assistant" in the settings section.' });
}
}
} else {
this.$toast.add({ severity: 'error', summary: 'An error occured', detail: 'A valid license required', life: 3000 });
}
} else {
this.$toast.add({ severity: 'error', summary: 'An error occured', detail: 'File is required', life: 3000 });
}
} }
}, },
onFileSelect(event) { onFileSelect(event) {
@ -199,10 +202,13 @@ export default {
font_family: 'Inter var' font_family: 'Inter var'
} }
}; };
this.designerService.replaceColorPalette(); this.designerService.applyFont('Inter var');
document.documentElement.style.fontSize = '14px';
usePreset(preset); usePreset(preset);
this.designerService.refreshACTokens(); this.designerService.refreshACTokens();
this.$appState.designer.activeTab = '0';
this.$appState.designer.activeView = 'editor'; this.$appState.designer.activeView = 'editor';
} }
} }

View File

@ -6,11 +6,17 @@
</div> </div>
<div class="text-lg font-semibold mb-2">Authenticate</div> <div class="text-lg font-semibold mb-2">Authenticate</div>
<span class="block text-muted-color leading-6 mb-4" <div v-if="!$appState.designer.verified">
>A license can be purchased from PrimeStore, if you do not have a license key, you are still able to experience the Designer in trial mode. In trial mode, downloads, figma to code, migration assistant and cloud storage are not available. <span class="block leading-6 mb-4"
<NuxtLink to="/designer" class="doc-link">Learn more</NuxtLink> about the Theme Designer.</span >Theme Designer is the ultimate tool to customize and design your own themes featuring a visual editor, figma to code, cloud storage, and migration assistant. <NuxtLink to="/designer" class="doc-link">Discover</NuxtLink> more about the
> Theme Designer by visiting the detailed <NuxtLink to="/designer/guide" class="doc-link">documentation</NuxtLink></span
<span class="block text-muted-color leading-6 mb-4">License key and pass key are available at <a href="https://primefaces.org/store/designer.xhtml" class="doc-link" rel="noopener noreferrer">PrimeStore</a>.</span> >
<span class="block leading-6 mb-4"
>A license can be purchased from <a href="https://primefaces.org/store/designer.xhtml" class="doc-link" rel="noopener noreferrer">PrimeStore</a>, if you do not have a license key, you are still able to experience the Designer in trial
mode. Note that in trial mode, downloads, figma to code, migration assistant and cloud storage are not available.</span
>
<span class="block leading-6 mb-4">Sign-in at <a href="https://primefaces.org/store/designer.xhtml" class="doc-link" rel="noopener noreferrer">PrimeStore</a> to retrieve your license key along with the pass key.</span>
</div>
<form v-if="!$appState.designer.verified" @submit.prevent class="flex gap-4"> <form v-if="!$appState.designer.verified" @submit.prevent class="flex gap-4">
<input v-model="licenseKey" type="password" autocomplete="off" class="px-3 py-2 rounded-md border border-surface-300 dark:border-surface-700 flex-1" placeholder="License Key" /> <input v-model="licenseKey" type="password" autocomplete="off" class="px-3 py-2 rounded-md border border-surface-300 dark:border-surface-700 flex-1" placeholder="License Key" />
<input v-model="otp" autocomplete="off" class="px-3 py-2 rounded-md border border-surface-300 dark:border-surface-700" placeholder="Pass Key" /> <input v-model="otp" autocomplete="off" class="px-3 py-2 rounded-md border border-surface-300 dark:border-surface-700" placeholder="Pass Key" />
@ -40,7 +46,7 @@
]" ]"
@click="openNewTheme" @click="openNewTheme"
> >
<i class="pi pi-plus !text-2xl"></i> <i class="pi pi-plus"></i>
</button> </button>
<template v-if="loading"> <template v-if="loading">
<Skeleton class="!rounded-xl !h-32 !w-32">-</Skeleton> <Skeleton class="!rounded-xl !h-32 !w-32">-</Skeleton>
@ -57,8 +63,8 @@
</button> </button>
<div class="flex flex-col items-center gap-1"> <div class="flex flex-col items-center gap-1">
<div class="group flex items-center gap-2 relative"> <div class="group flex items-center gap-2 relative">
<input v-model="theme.t_name" type="text" class="w-24 text-sm px-2 text-center" maxlength="100" @blur="renameTheme(theme)" /> <input v-model="theme.t_name" type="text" class="w-24 text-sm px-2 text-center pr-4" maxlength="100" @blur="renameTheme(theme)" />
<i class="hidden group-hover:block pi pi-pencil !text-sm absolute top-50 right-0 text-muted-color"></i> <i class="hidden group-hover:block pi pi-pencil !text-xs absolute top-50 text-muted-color" style="right: 2px"></i>
</div> </div>
<span class="text-muted-color text-xs">{{ formatTimestamp(theme.t_last_updated) }}</span> <span class="text-muted-color text-xs">{{ formatTimestamp(theme.t_last_updated) }}</span>
</div> </div>
@ -189,8 +195,6 @@ export default {
this.currentTheme = null; this.currentTheme = null;
usePreset(Aura); usePreset(Aura);
document.body.classList.remove('material');
this.$primevue.config.ripple = false;
} }
}, },
openNewTheme() { openNewTheme() {
@ -227,6 +231,7 @@ export default {
this.$toast.add({ severity: 'error', summary: 'An Error Occurred', detail: error.message, life: 3000 }); this.$toast.add({ severity: 'error', summary: 'An Error Occurred', detail: error.message, life: 3000 });
} else { } else {
this.designerService.activateTheme(data); this.designerService.activateTheme(data);
this.$appState.designer.activeTab = '0';
this.$appState.designer.activeView = 'editor'; this.$appState.designer.activeView = 'editor';
} }
}, },

View File

@ -1,11 +1,12 @@
<template> <template>
<div class="flex flex-1 border border-surface rounded-l-lg rounded-r-lg overflow-hidden"> <div class="flex flex-1 border border-surface rounded-l-lg rounded-r-lg overflow-hidden">
<div v-for="color of value" :key="color" class="flex-1 h-8" :style="{ backgroundColor: color }" :title="color"></div> <div v-for="color of value" :key="color" class="flex-1 h-8" :style="{ backgroundColor: designerService.resolveColor(color) }" :title="color"></div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
inject: ['designerService'],
props: { props: {
value: { value: {
type: Object, type: Object,

View File

@ -2,7 +2,7 @@
<div class="group"> <div class="group">
<div class="flex justify-between justify-items-center"> <div class="flex justify-between justify-items-center">
<label :for="inputId" class="text-xs text-zinc-700 dark:text-white/70 block capitalize text-ellipsis overflow-hidden w-full whitespace-nowrap mb-px" :title="label">{{ label }}</label> <label :for="inputId" class="text-xs text-zinc-700 dark:text-white/70 block capitalize text-ellipsis overflow-hidden w-full whitespace-nowrap mb-px" :title="label">{{ label }}</label>
<button v-if="switchable" type="button" @click="transfer"> <button v-if="switchable" type="button" @click="transfer" tabindex="-1">
<i class="pi pi-sort-alt !text-xs text-zinc-500 dark:text-white/50 hidden group-hover:block animate-fadein" title="Transfer between color scheme and common"></i> <i class="pi pi-sort-alt !text-xs text-zinc-500 dark:text-white/50 hidden group-hover:block animate-fadein" title="Transfer between color scheme and common"></i>
</button> </button>
</div> </div>
@ -10,6 +10,7 @@
<AutoComplete <AutoComplete
:modelValue="modelValue" :modelValue="modelValue"
@input="onInput" @input="onInput"
@blur="onBlur"
:inputId="inputId" :inputId="inputId"
:suggestions="items" :suggestions="items"
@complete="search" @complete="search"
@ -34,7 +35,7 @@
<template #option="slotProps"> <template #option="slotProps">
<div v-tooltip.left="slotProps.option.value" class="flex items-center justify-between gap-4 px-2"> <div v-tooltip.left="slotProps.option.value" class="flex items-center justify-between gap-4 px-2">
<span>{{ slotProps.option.token }}</span> <span>{{ slotProps.option.token }}</span>
<div v-if="slotProps.option.isColor" class="border border-surface-200 dark:border-surface-700 w-4 h-4 rounded-full" :style="{ backgroundColor: slotProps.option.variable }"></div> <div v-if="slotProps.option.isColor" class="border border-surface-200 dark:border-surface-700 w-4 h-4 rounded-full" :style="{ backgroundColor: designerService.resolveColor(slotProps.option.value) }"></div>
<div v-else class="text-xs max-w-16 text-ellipsis whitespace-nowrap overflow-hidden"> <div v-else class="text-xs max-w-16 text-ellipsis whitespace-nowrap overflow-hidden">
{{ slotProps.option.value }} {{ slotProps.option.value }}
</div> </div>
@ -47,11 +48,12 @@
</template> </template>
<script> <script>
import { uuid } from '@primeuix/utils';
import { $dt } from '@primeuix/themes'; import { $dt } from '@primeuix/themes';
import { uuid } from '@primeuix/utils';
export default { export default {
emits: ['update:modelValue'], emits: ['update:modelValue'],
inject: ['designerService'],
props: { props: {
label: { label: {
type: String, type: String,
@ -212,6 +214,9 @@ export default {
delete current[lastKey]; delete current[lastKey];
return true; return true;
},
onBlur() {
this.designerService.refreshACTokens();
} }
}, },
computed: { computed: {

View File

@ -28,6 +28,8 @@
</template> </template>
<script> <script>
import { usePreset } from '@primeuix/themes';
export default { export default {
inject: ['designerService'], inject: ['designerService'],
data() { data() {
@ -61,6 +63,7 @@ export default {
}); });
this.designerService.saveTheme(this.$appState.designer.theme); this.designerService.saveTheme(this.$appState.designer.theme);
usePreset(this.$appState.designer.theme.preset);
this.designerService.refreshACTokens(); this.designerService.refreshACTokens();
this.$toast.add({ severity: 'success', summary: 'Success', detail: 'Tokens saved', life: 3000 }); this.$toast.add({ severity: 'success', summary: 'Success', detail: 'Tokens saved', life: 3000 });
}, },

View File

@ -4,7 +4,7 @@
<section v-if="key !== 'borderRadius'" class="flex justify-between items-center mb-4 gap-8"> <section v-if="key !== 'borderRadius'" class="flex justify-between items-center mb-4 gap-8">
<div class="flex gap-2 items-center"> <div class="flex gap-2 items-center">
<span class="text-sm capitalize block w-20">{{ key }}</span> <span class="text-sm capitalize block w-20">{{ key }}</span>
<input :value="$appState.designer.theme.preset.primitive[key]['500']" @input="onColorChange($event, key)" type="color" /> <input :value="designerService.resolveColor($appState.designer.theme.preset.primitive[key]['500'])" @input="onColorChange($event, key)" type="color" @blur="onBlur" />
</div> </div>
<DesignColorPalette :value="$appState.designer.theme.preset.primitive[key]" /> <DesignColorPalette :value="$appState.designer.theme.preset.primitive[key]" />
</section> </section>
@ -16,9 +16,13 @@
import { palette } from '@primeuix/themes'; import { palette } from '@primeuix/themes';
export default { export default {
inject: ['designerService'],
methods: { methods: {
onColorChange(event, color) { onColorChange(event, color) {
this.$appState.designer.theme.preset.primitive[color] = palette(event.target.value); this.$appState.designer.theme.preset.primitive[color] = palette(event.target.value);
},
onBlur() {
this.designerService.refreshACTokens();
} }
} }
}; };

View File

@ -3,7 +3,7 @@
<section class="flex justify-between items-center mb-5 gap-8"> <section class="flex justify-between items-center mb-5 gap-8">
<div class="flex gap-2 items-center"> <div class="flex gap-2 items-center">
<span class="text-sm">Primary</span> <span class="text-sm">Primary</span>
<input :value="$appState.designer.theme.preset.semantic.primary['500']" @input="onPrimaryColorChange($event)" type="color" /> <input :value="designerService.resolveColor($appState.designer.theme.preset.semantic.primary['500'])" @input="onPrimaryColorChange($event)" type="color" class="w-0 h-0" @onBlur="onColorPickerBlur" />
</div> </div>
<DesignColorPalette :value="$appState.designer.theme.preset.semantic.primary" /> <DesignColorPalette :value="$appState.designer.theme.preset.semantic.primary" />
</section> </section>
@ -52,9 +52,13 @@
import { palette } from '@primeuix/themes'; import { palette } from '@primeuix/themes';
export default { export default {
inject: ['designerService'],
methods: { methods: {
onPrimaryColorChange(event) { onPrimaryColorChange(event) {
this.$appState.designer.theme.preset.semantic.primary = palette(event.target.value); this.$appState.designer.theme.preset.semantic.primary = palette(event.target.value);
},
onColorPickerBlur() {
this.designerService.refreshACTokens();
} }
} }
}; };

View File

@ -3,7 +3,7 @@
<section class="flex justify-between items-center mb-5 gap-8"> <section class="flex justify-between items-center mb-5 gap-8">
<div class="flex gap-2 items-center"> <div class="flex gap-2 items-center">
<span class="text-sm">Surface</span> <span class="text-sm">Surface</span>
<input :value="$colorScheme.surface['500']" @input="onSurfaceColorChange($event)" type="color" /> <input :value="designerService.resolveColor($colorScheme.surface['500'])" @input="onSurfaceColorChange($event)" type="color" @blur="onColorPickerBlur" />
</div> </div>
<DesignColorPalette :value="$colorScheme.surface" /> <DesignColorPalette :value="$colorScheme.surface" />
</section> </section>
@ -82,10 +82,13 @@
import { palette } from '@primeuix/themes'; import { palette } from '@primeuix/themes';
export default { export default {
inject: ['$colorScheme'], inject: ['$colorScheme', 'designerService'],
methods: { methods: {
onSurfaceColorChange(event) { onSurfaceColorChange(event) {
this.$colorScheme.surface = { ...{ 0: '#ffffff' }, ...palette(event.target.value) }; this.$colorScheme.surface = { ...{ 0: '#ffffff' }, ...palette(event.target.value) };
},
onColorPickerBlur() {
this.designerService.refreshACTokens();
} }
} }
}; };

View File

@ -73,8 +73,7 @@ export default defineNuxtConfig({
], ],
link: [ link: [
{ rel: 'icon', href: baseUrl + 'favicon.ico' }, { rel: 'icon', href: baseUrl + 'favicon.ico' },
{ rel: 'stylesheet', href: 'https://rsms.me/inter/inter.css' }, { rel: 'stylesheet', href: 'https://rsms.me/inter/inter.css' }
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto:400|Roboto:500|Roboto:600|Roboto:700', fetchpriority: 'low' }
], ],
script: [ script: [
{ {