Merge pull request #7280 from cagataycivici/master

Designer improvements
pull/7287/head
Cagatay Civici 2025-02-19 18:54:43 +03:00 committed by GitHub
commit f455896625
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 68 additions and 19 deletions

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" blockScroll @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" @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">

View File

@ -9,7 +9,7 @@
<div v-if="!$appState.designer.verified"> <div v-if="!$appState.designer.verified">
<span class="block leading-6 mb-4" <span class="block leading-6 mb-4"
>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 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 Theme Designer by visiting the detailed <NuxtLink to="/designer/guide" class="doc-link">documentation</NuxtLink>.</span
> >
<span class="block leading-6 mb-4" <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 >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
@ -63,7 +63,15 @@
</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 pr-4" maxlength="100" @blur="renameTheme(theme)" /> <input
v-model="theme.t_name"
type="text"
:class="['w-24 text-sm px-2 text-center pr-4', { 'bg-red-50 dark:bg-red-500/30': !theme.t_name }]"
maxlength="100"
@blur="renameTheme(theme)"
@keydown.enter="onThemeNameEnterKey($event)"
@keydown.escape="onThemeNameEscape($event)"
/>
<i class="hidden group-hover:block pi pi-pencil !text-xs absolute top-50 text-muted-color" style="right: 2px"></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>
@ -73,7 +81,7 @@
</button> </button>
</div> </div>
</template> </template>
<Menu ref="themeMenu" :model="themeOptions" :popup="true" /> <Menu ref="themeMenu" :model="themeOptions" :popup="true" @show="onMenuShow" @hide="onMenuHide" />
</div> </div>
</template> </template>
@ -82,6 +90,7 @@ import { usePreset } from '@primeuix/themes';
import Aura from '@primeuix/themes/aura'; import Aura from '@primeuix/themes/aura';
export default { export default {
scrollListener: null,
setup() { setup() {
const runtimeConfig = useRuntimeConfig(); const runtimeConfig = useRuntimeConfig();
@ -90,6 +99,9 @@ export default {
}; };
}, },
inject: ['designerService'], inject: ['designerService'],
beforeUnmount() {
this.unbindScrollListener();
},
data() { data() {
return { return {
licenseKey: null, licenseKey: null,
@ -236,21 +248,30 @@ export default {
} }
}, },
async renameTheme(theme) { async renameTheme(theme) {
const { error } = await $fetch(this.designerApiUrl + '/theme/rename/' + theme.t_key, { if (theme.t_name && theme.t_name.trim().length) {
method: 'PATCH', const { error } = await $fetch(this.designerApiUrl + '/theme/rename/' + theme.t_key, {
credentials: 'include', method: 'PATCH',
headers: { credentials: 'include',
'X-CSRF-Token': this.$appState.designer.csrfToken headers: {
}, 'X-CSRF-Token': this.$appState.designer.csrfToken
body: { },
name: theme.t_name body: {
} name: theme.t_name
}); }
});
if (error) { if (error) {
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 });
}
} }
}, },
onThemeNameEnterKey(event) {
event.target.blur();
},
onThemeNameEscape(event) {
event.target.blur();
event.stopPropagation();
},
async deleteTheme(theme) { async deleteTheme(theme) {
const { error } = await $fetch(this.designerApiUrl + '/theme/delete/' + theme.t_key, { const { error } = await $fetch(this.designerApiUrl + '/theme/delete/' + theme.t_key, {
method: 'DELETE', method: 'DELETE',
@ -299,6 +320,27 @@ export default {
this.currentTheme = theme; this.currentTheme = theme;
this.$refs.themeMenu.toggle(event); this.$refs.themeMenu.toggle(event);
}, },
onMenuShow() {
this.bindScrollListener();
},
onMenuHide() {
this.unbindScrollListener();
},
bindScrollListener() {
if (!this.scrollListener) {
this.scrollListener = () => {
this.$refs.themeMenu.hide();
};
window.addEventListener('scroll', this.scrollListener);
}
},
unbindScrollListener() {
if (this.scrollListener) {
window.removeEventListener('scroll', this.scrollListener);
this.scrollListener = null;
}
},
abbrThemeName(theme) { abbrThemeName(theme) {
return theme.t_name ? theme.t_name.substring(0, 2) : 'UT'; return theme.t_name ? theme.t_name.substring(0, 2) : 'UT';
} }

View File

@ -17,6 +17,7 @@
unstyled unstyled
optionLabel="label" optionLabel="label"
:showEmptyMessage="false" :showEmptyMessage="false"
appendTo="self"
:pt="{ :pt="{
pcInputText: { pcInputText: {
root: [ root: [

View File

@ -5,7 +5,7 @@
<div class="flex flex-col gap-3"> <div class="flex flex-col gap-3">
<template v-if="hasCommonTokens"> <template v-if="hasCommonTokens">
<template v-for="(value, name) in tokens" :key="name"> <template v-for="(value, name) in tokens" :key="name">
<DesignComponentSection v-if="name !== 'colorScheme'" :componentKey="componentKey" :path="name" /> <DesignComponentSection v-if="name !== 'colorScheme' && name !== 'css'" :componentKey="componentKey" :path="name" />
</template> </template>
</template> </template>
<span v-else class="block py-3">There are no design tokens</span> <span v-else class="block py-3">There are no design tokens</span>
@ -54,7 +54,11 @@ export default {
return this.tokens.colorScheme != undefined; return this.tokens.colorScheme != undefined;
}, },
hasCommonTokens() { hasCommonTokens() {
return Object.keys(this.tokens).filter((name) => name !== 'colorScheme').length > 0; return (
Object.keys(this.tokens).filter((name) => {
return name !== 'colorScheme' && name !== 'css';
}).length > 0
);
} }
} }
}; };

View File

@ -1,5 +1,7 @@
<template> <template>
<div class="leading-6 text-muted-color mb-4">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.</div> <div class="leading-6 text-muted-color mb-4">
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, and ensure that the name does not match any built-in tokens.
</div>
<ul v-if="tokens?.length" class="flex flex-col gap-4 list-none p-0 mx-0 mb-4"> <ul v-if="tokens?.length" class="flex flex-col gap-4 list-none p-0 mx-0 mb-4">
<li v-for="(token, index) of tokens" :key="index" class="first:border-t border-b border-surface-200 dark:border-surface-700 py-2"> <li v-for="(token, index) of tokens" :key="index" class="first:border-t border-b border-surface-200 dark:border-surface-700 py-2">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">