fix(spa): compact buttons + click-to-copy id + logo backdrop + dollar icon + hex color picker
This commit is contained in:
@@ -29,11 +29,6 @@ const logoSrc = `${import.meta.env.BASE_URL}images/favicon.svg`;
|
||||
aria-label="Settings"
|
||||
@click="router.push('/settings')"
|
||||
/>
|
||||
<Button
|
||||
icon="pi pi-moon" text rounded severity="secondary"
|
||||
aria-label="Toggle theme"
|
||||
@click="ui.toggleTheme"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
@@ -12,3 +12,41 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
}
|
||||
|
||||
/* Compact button + form-control density for the SPA. PrimeVue Aura defaults
|
||||
* are sized for large touch targets; this app is keyboard-first so we use
|
||||
* a tighter rhythm (matches the old project). */
|
||||
.p-button {
|
||||
padding: 0.4rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.p-button-sm,
|
||||
.p-button[data-pc-section="root"][size="small"] {
|
||||
padding: 0.3rem 0.6rem;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.p-button-icon-only {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0;
|
||||
}
|
||||
.p-button-icon-only.p-button-sm {
|
||||
width: 1.75rem;
|
||||
height: 1.75rem;
|
||||
}
|
||||
/* Tighter inputs, dropdowns, selects to match button density. */
|
||||
.p-inputtext,
|
||||
.p-select,
|
||||
.p-inputnumber-input {
|
||||
padding: 0.4rem 0.6rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.p-textarea {
|
||||
padding: 0.5rem 0.6rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
/* DataTable rows */
|
||||
.p-datatable-tbody > tr > td,
|
||||
.p-datatable-thead > tr > th {
|
||||
padding: 0.55rem 0.75rem;
|
||||
}
|
||||
|
||||
@@ -53,9 +53,14 @@ async function remove(row: CategoryRow) {
|
||||
<label for="cat-name" class="block text-xs text-wp-text2 mb-1">Name</label>
|
||||
<InputText id="cat-name" v-model="newName" placeholder="Style" class="w-full" @keydown.enter="add" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="cat-color" class="block text-xs text-wp-text2 mb-1">Color</label>
|
||||
<ColorPicker id="cat-color" v-model="newColor" />
|
||||
<div class="color-input-group">
|
||||
<ColorPicker v-model="newColor" class="color-input-group__picker" />
|
||||
<InputText
|
||||
v-model="newColor" placeholder="hex" maxlength="6"
|
||||
aria-label="Hex color code"
|
||||
class="color-input-group__hex font-mono text-xs"
|
||||
@keydown.enter="add"
|
||||
/>
|
||||
</div>
|
||||
<Button label="Add" icon="pi pi-plus" severity="primary" data-test="add-category-btn" @click="add" />
|
||||
</div>
|
||||
@@ -72,7 +77,6 @@ async function remove(row: CategoryRow) {
|
||||
<span class="font-mono text-xs">{{ data.color || "—" }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="sort_order" header="Order" sortable header-style="width:6rem" />
|
||||
<Column header="Actions" header-style="width:6rem">
|
||||
<template #body="{ data }">
|
||||
<Button icon="pi pi-trash" text rounded size="small" severity="danger"
|
||||
@@ -85,3 +89,28 @@ async function remove(row: CategoryRow) {
|
||||
</DataTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.color-input-group {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
border: 1px solid var(--wp-border);
|
||||
border-radius: var(--wp-radius);
|
||||
overflow: hidden;
|
||||
height: 2rem;
|
||||
}
|
||||
.color-input-group__picker :deep(.p-colorpicker-preview) {
|
||||
width: 2rem;
|
||||
height: 100%;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
.color-input-group__hex {
|
||||
width: 6rem;
|
||||
border: none !important;
|
||||
border-radius: 0 !important;
|
||||
outline: none !important;
|
||||
background: transparent;
|
||||
}
|
||||
.color-input-group__hex:focus { box-shadow: none !important; }
|
||||
</style>
|
||||
|
||||
@@ -77,13 +77,21 @@ const recent = computed(() => [...moduleStore.items].slice(0, 5));
|
||||
|
||||
<style scoped>
|
||||
.hero-card {
|
||||
display: flex; gap: 16px; align-items: center;
|
||||
display: flex; gap: 20px; align-items: center;
|
||||
padding: 24px;
|
||||
background: var(--wp-brand-gradient);
|
||||
border-radius: var(--wp-radius);
|
||||
color: #fff;
|
||||
}
|
||||
.hero-card__logo { width: 64px; height: 64px; }
|
||||
.hero-card__logo {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
padding: 12px;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
border-radius: 50%;
|
||||
box-sizing: content-box;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.stat-card {
|
||||
background: var(--wp-bg2);
|
||||
border: 1px solid var(--wp-border);
|
||||
|
||||
@@ -3,6 +3,8 @@ import { computed, onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import Button from "primevue/button";
|
||||
import InputText from "primevue/inputtext";
|
||||
import InputGroup from "primevue/inputgroup";
|
||||
import InputGroupAddon from "primevue/inputgroupaddon";
|
||||
import Textarea from "primevue/textarea";
|
||||
import Select from "primevue/select";
|
||||
import { useToast } from "primevue/usetoast";
|
||||
@@ -113,7 +115,7 @@ async function save() {
|
||||
<section class="form-section">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h2 class="form-section__label m-0">Values</h2>
|
||||
<Button label="Add value" icon="pi pi-plus" size="small" severity="secondary" outlined @click="addValue" />
|
||||
<Button label="Add value" icon="pi pi-plus" size="small" severity="primary" @click="addValue" />
|
||||
</div>
|
||||
<table class="w-full text-sm border border-wp-border rounded">
|
||||
<thead>
|
||||
@@ -125,7 +127,12 @@ async function save() {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(v, idx) in values" :key="v.id" class="border-t border-wp-border">
|
||||
<td class="px-3 py-2 w-48"><InputText v-model="v.name" placeholder="$varname" class="w-full" /></td>
|
||||
<td class="px-3 py-2 w-48">
|
||||
<InputGroup>
|
||||
<InputGroupAddon><i class="pi pi-dollar" /></InputGroupAddon>
|
||||
<InputText v-model="v.name" placeholder="varname" />
|
||||
</InputGroup>
|
||||
</td>
|
||||
<td class="px-3 py-2"><InputText v-model="v.value" class="w-full" /></td>
|
||||
<td class="px-3 py-2 text-right">
|
||||
<Button icon="pi pi-trash" text rounded size="small" severity="danger"
|
||||
|
||||
@@ -33,6 +33,15 @@ function edit(row: ModuleRow) {
|
||||
router.push({ name: "fixed-values-edit", params: { id: row.id } });
|
||||
}
|
||||
|
||||
async function copyId(id: string) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(id);
|
||||
toast.add({ severity: "info", summary: "ID copied", detail: id, life: 1500 });
|
||||
} catch {
|
||||
toast.add({ severity: "error", summary: "Copy failed", life: 2000 });
|
||||
}
|
||||
}
|
||||
|
||||
async function dup(row: ModuleRow) {
|
||||
try {
|
||||
await store.duplicate(row.id);
|
||||
@@ -104,8 +113,12 @@ function valueCount(row: ModuleRow): number {
|
||||
<Column field="name" header="Name" sortable>
|
||||
<template #body="{ data }">
|
||||
<div class="flex flex-col">
|
||||
<span class="cursor-pointer font-medium" @click="edit(data)">{{ data.name }}</span>
|
||||
<span class="text-xs text-wp-text3 font-mono">{{ data.id }}</span>
|
||||
<span class="cursor-pointer font-medium hover:text-white" @click="edit(data)">{{ data.name }}</span>
|
||||
<span
|
||||
class="text-xs text-wp-text3 font-mono cursor-pointer hover:text-wp-text2 select-all"
|
||||
:title="`Click to copy ${data.id}`"
|
||||
@click.stop="copyId(data.id)"
|
||||
>{{ data.id }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
|
||||
@@ -114,7 +114,7 @@ async function save() {
|
||||
<section class="form-section">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h2 class="form-section__label m-0">Options</h2>
|
||||
<Button label="Add option" icon="pi pi-plus" size="small" severity="secondary" outlined @click="addOption" />
|
||||
<Button label="Add option" icon="pi pi-plus" size="small" severity="primary" @click="addOption" />
|
||||
</div>
|
||||
<table class="w-full text-sm border border-wp-border rounded">
|
||||
<thead>
|
||||
|
||||
@@ -33,6 +33,15 @@ function edit(row: ModuleRow) {
|
||||
router.push({ name: "wildcards-edit", params: { id: row.id } });
|
||||
}
|
||||
|
||||
async function copyId(id: string) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(id);
|
||||
toast.add({ severity: "info", summary: "ID copied", detail: id, life: 1500 });
|
||||
} catch {
|
||||
toast.add({ severity: "error", summary: "Copy failed", life: 2000 });
|
||||
}
|
||||
}
|
||||
|
||||
async function dup(row: ModuleRow) {
|
||||
try {
|
||||
await store.duplicate(row.id);
|
||||
@@ -110,8 +119,12 @@ function validIcon(row: ModuleRow): string {
|
||||
<Column field="name" header="Name" sortable>
|
||||
<template #body="{ data }">
|
||||
<div class="flex flex-col">
|
||||
<span class="cursor-pointer font-medium" @click="edit(data)">{{ data.name }}</span>
|
||||
<span class="text-xs text-wp-text3 font-mono">{{ data.id }}</span>
|
||||
<span class="cursor-pointer font-medium hover:text-white" @click="edit(data)">{{ data.name }}</span>
|
||||
<span
|
||||
class="text-xs text-wp-text3 font-mono cursor-pointer hover:text-wp-text2 select-all"
|
||||
:title="`Click to copy ${data.id}`"
|
||||
@click.stop="copyId(data.id)"
|
||||
>{{ data.id }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/wp/images/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="/wp/images/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/wp/images/site.webmanifest" />
|
||||
<script type="module" crossorigin src="/wp/assets/manager-GO_zoksX.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/wp/assets/manager-_-ZL74NZ.css">
|
||||
<script type="module" crossorigin src="/wp/assets/manager-8iXcgXlr.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/wp/assets/manager-jFd_cg3s.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
Reference in New Issue
Block a user