mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 21:21:10 +02:00
refactor(mana/web): extract QuickActionsList molecule shared by both widget variants
Two QuickActionsWidget files lived in parallel under different widget systems — `dashboard/widgets/` (the user-customizable dashboard, i18n keys, 3 actions: credits/feedback/profile) and `core/widgets/` (the mana home screen, hardcoded German strings, 5 actions: todo/calendar/ contacts/context/times). The two rendered the same shape character- for-character: optional emoji-prefixed title + a list of rounded-card links each with icon + label + description. Only the data and a slightly different padding/icon sizing differed. Extract <QuickActionsList> in $lib/components that takes the actions array directly (consumers resolve i18n before passing in). Both widget files become thin wrappers — the dashboard one resolves $_(...) keys and passes the result, the core one passes its hardcoded data with `compact` set. LOC: 110 → 102 across the 3 files (-8 net, plus the shared 70-LOC molecule). Small numerically, but the bigger win is that future changes to the link layout (hover state, padding, icon style) happen once instead of twice — and the two widget files no longer accidentally drift in sizing/spacing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8772a9b9e1
commit
96023394b5
3 changed files with 97 additions and 42 deletions
|
|
@ -0,0 +1,75 @@
|
|||
<!--
|
||||
QuickActionsList — shared shell for "list of clickable shortcut links" widgets.
|
||||
|
||||
Both `dashboard/widgets/QuickActionsWidget` and `core/widgets/QuickActionsWidget`
|
||||
rendered the same shape: optional title (with emoji prefix) + a list of
|
||||
rounded-card links, each with an emoji/icon, a label and a description.
|
||||
They differed only in the data and a slightly different padding/icon size
|
||||
(the dashboard one is roomier; the core one is compact).
|
||||
|
||||
This molecule takes the actions array directly. Consumers that need i18n
|
||||
resolve the keys before passing the data in.
|
||||
|
||||
@example
|
||||
```svelte
|
||||
<QuickActionsList
|
||||
title="Schnellzugriff"
|
||||
actions={[
|
||||
{ href: '/todo', icon: '✅', label: 'Neue Aufgabe', description: 'Aufgabe erstellen' },
|
||||
...
|
||||
]}
|
||||
compact
|
||||
/>
|
||||
```
|
||||
-->
|
||||
<script lang="ts">
|
||||
export interface QuickAction {
|
||||
href: string;
|
||||
/** Emoji glyph or HTML entity (rendered with {@html}). Use a Phosphor icon snippet via the consumer's wrapper if you need a real component. */
|
||||
icon: string;
|
||||
label: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
actions: QuickAction[];
|
||||
/** Compact mode: smaller padding, smaller icon, smaller text. Used by core/widgets. */
|
||||
compact?: boolean;
|
||||
/** Optional heading rendered above the list. */
|
||||
title?: string;
|
||||
/** Optional emoji glyph rendered before the title. */
|
||||
titleIcon?: string;
|
||||
}
|
||||
|
||||
let { actions, compact = false, title, titleIcon }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if title}
|
||||
<div class="mb-3">
|
||||
<h3 class="flex items-center gap-2 text-lg font-semibold">
|
||||
{#if titleIcon}<span>{@html titleIcon}</span>{/if}
|
||||
{title}
|
||||
</h3>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class={compact ? 'space-y-1' : 'space-y-2'}>
|
||||
{#each actions as action}
|
||||
<a
|
||||
href={action.href}
|
||||
class="flex items-center gap-3 rounded-lg transition-colors hover:bg-surface-hover {compact
|
||||
? 'p-2.5'
|
||||
: 'p-3'}"
|
||||
>
|
||||
<span class={compact ? 'text-xl' : 'text-2xl'}>{@html action.icon}</span>
|
||||
<div class="min-w-0">
|
||||
<p class="font-medium {compact ? 'text-sm' : ''}">{action.label}</p>
|
||||
<p class="text-muted-foreground {compact ? 'text-xs' : 'text-sm'}">
|
||||
{action.description}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
<script lang="ts">
|
||||
/**
|
||||
* QuickActionsWidget - Quick action links
|
||||
* QuickActionsWidget - Quick action links (dashboard variant, i18n).
|
||||
*
|
||||
* Thin wrapper around <QuickActionsList>. Resolves i18n keys to literal
|
||||
* strings before passing the actions array down.
|
||||
*/
|
||||
|
||||
import { _ } from 'svelte-i18n';
|
||||
import QuickActionsList, { type QuickAction } from '$lib/components/QuickActionsList.svelte';
|
||||
|
||||
const actions = [
|
||||
{
|
||||
|
|
@ -25,25 +28,19 @@
|
|||
descKey: 'dashboard.widgets.quick_actions.profile_desc',
|
||||
},
|
||||
];
|
||||
|
||||
let resolved = $derived<QuickAction[]>(
|
||||
actions.map((a) => ({
|
||||
href: a.href,
|
||||
icon: a.icon,
|
||||
label: $_(a.labelKey),
|
||||
description: $_(a.descKey),
|
||||
}))
|
||||
);
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<h3 class="mb-3 flex items-center gap-2 text-lg font-semibold">
|
||||
<span>⚡</span>
|
||||
{$_('dashboard.widgets.quick_actions.title')}
|
||||
</h3>
|
||||
|
||||
<div class="space-y-2">
|
||||
{#each actions as action}
|
||||
<a href={action.href} class="block rounded-lg p-3 transition-colors hover:bg-surface-hover">
|
||||
<div class="flex items-center">
|
||||
<span class="text-2xl">{action.icon}</span>
|
||||
<div class="ml-3">
|
||||
<p class="font-medium">{$_(action.labelKey)}</p>
|
||||
<p class="text-sm text-muted-foreground">{$_(action.descKey)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<QuickActionsList
|
||||
title={$_('dashboard.widgets.quick_actions.title')}
|
||||
titleIcon="⚡"
|
||||
actions={resolved}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
* QuickActionsWidget — Schnellzugriff-Buttons für häufige Aktionen.
|
||||
*
|
||||
* Navigiert direkt zu den jeweiligen App-Routen innerhalb der Unified App.
|
||||
* Thin wrapper around <QuickActionsList> in compact mode.
|
||||
*/
|
||||
import QuickActionsList from '$lib/components/QuickActionsList.svelte';
|
||||
|
||||
const actions = [
|
||||
{
|
||||
|
|
@ -39,23 +41,4 @@
|
|||
];
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="mb-3">
|
||||
<h3 class="flex items-center gap-2 text-lg font-semibold">Schnellzugriff</h3>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
{#each actions as action}
|
||||
<a
|
||||
href={action.href}
|
||||
class="flex items-center gap-3 rounded-lg p-2.5 transition-colors hover:bg-surface-hover"
|
||||
>
|
||||
<span class="text-xl">{@html action.icon}</span>
|
||||
<div>
|
||||
<p class="text-sm font-medium">{action.label}</p>
|
||||
<p class="text-xs text-muted-foreground">{action.description}</p>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<QuickActionsList title="Schnellzugriff" {actions} compact />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue