worklog-design
UI design and development guide for the Worklog project.
Install
mkdir -p .claude/skills/worklog-design && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/10058" && unzip -o skill.zip -d .claude/skills/worklog-design && rm skill.zipInstalls to .claude/skills/worklog-design
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Design and UI skill for the Worklog desktop project manager. Stack: SvelteKit 5 (Svelte Runes), Tauri v2, carbon-components-svelte, TypeScript, Bun. Use whenever building, refactoring, or extending Worklog's UI — new views, components, layouts, theming, or visual polish aligned with the Carbon Design System and the local-first desktop product philosophy.Key capabilities
- →Build UI components
- →Refactor layouts
- →Implement local-first data flows
- →Apply Carbon Design System
- →Manage keyboard-first interactions
How it works
It uses Svelte Runes and Tauri SQL to build fast, local-first desktop interfaces.
Inputs & outputs
When to use worklog-design
- →Building new UI components
- →Refactoring existing layouts
- →Implementing local-first data flows
About this skill
Worklog Design Skill
Project Identity
Worklog is a local-first, keyboard-driven desktop project manager for small dev teams.
Core qualities that should always be felt in the UI:
| Quality | What it means in practice |
|---|---|
| Fast | Instant feedback. No loading skeletons for local SQLite data. Transitions ≤ 150 ms. |
| Keyboard-first | Every action reachable without a mouse. Shortcuts visible in tooltips. |
| Dense, not cluttered | Information-rich layout typical of desktop apps. Prefer compact Carbon sizing. |
| Local-first transparency | No cloud metaphors. Workspace = folder on disk. |
| Small team focus | No enterprise complexity. One workspace, one team, clear hierarchy. |
Stack Constraints
SvelteKit 5 + Svelte Runes
- Components use
$state,$derived,$effect— nowritable()stores for new code. - Layouts own scope: workspace scope in
+layout.svelte, board scope in nested layouts. - Use
$pagefrom$app/storesfor route params; prefer typed params viaRouteParams. - Async data goes in
+page.ts/+layout.tsload()functions, not inlineonMount. - Avoid
onMountfor data fetching; it causes flash-of-empty-content in Tauri webview.
Tauri v2
- All persistence calls go through Tauri SQL plugin (
@tauri-apps/plugin-sql) via the repository layer insrc/lib/db/. - Never call the repository directly from a component — always go through a hook in
src/lib/hooks/. - Tauri
invokefor custom Rust commands (e.g., Git sync, file system operations). - Window is frameless; the app shell owns the drag region and custom title bar area.
- No
localStorage,sessionStorage, or IndexedDB — SQLite is the source of truth. - File paths use Tauri path API (
appDataDir,join) — never hardcode OS paths.
carbon-components-svelte
- Theme: use Gray 90 (
g90) dark theme as the default — it matches the existing dark shell.- Import in
app.htmlor root+layout.svelte:import 'carbon-components-svelte/css/g90.css' - For light mode support, dynamically swap to
g10.
- Import in
- Use
optimizeImportsfromcarbon-preprocess-svelteinsvelte.config.jsto avoid slow dev builds. - Prefer Carbon's compact density tokens:
size="sm"on buttons/inputs inside panels. - Do not fight Carbon's CSS custom properties — override with
--cds-*tokens, never with!importanthacks. - Common components to reach for first:
| Use case | Carbon component |
|---|---|
| Sidebar nav | SideNav, SideNavItems, SideNavLink, SideNavMenu |
| Command palette / search | Search + custom modal overlay |
| Ticket cards | Tile, ClickableTile |
| Modals / dialogs | Modal |
| Forms | TextInput, TextArea, Select, Toggle, Checkbox |
| Tags / labels | Tag |
| Data tables | DataTable, Toolbar, ToolbarSearch |
| Notifications | InlineNotification, ToastNotification |
| Buttons | Button, IconButton |
| Context menus | OverflowMenu, OverflowMenuItem |
| Tooltips | Tooltip, TooltipDefinition |
| Progress / loading | InlineLoading, SkeletonText |
Layout Architecture
AppShell (root +layout.svelte)
├── TitleBar ← custom drag region, app name, window controls
├── SideNav ← workspaces list + board tree
│ ├── WorkspaceHeader
│ ├── BoardTree ← per-board SideNavLink with right-click OverflowMenu
│ └── NavFooter ← settings link, sync status badge
└── MainContent ← <slot /> — swapped by nested routes
├── KanbanView ← /boards/[id]
├── TableView ← /boards/[id]/table
├── TimelineView ← /boards/[id]/timeline
└── SettingsView ← /settings/[tab]
Key layout rules:
- The sidebar is fixed-width (
240pxdefault, resizable via CSS variable--worklog-sidebar-width). - The title bar drag region must use
-webkit-app-region: dragwith interactive elements set to-webkit-app-region: no-drag. - Never use full-page loading states — local SQLite is fast; show stale data instantly, then update.
Design Tokens & Custom Properties
Override or extend Carbon tokens at :root in src/app.css:
:root {
/* Sidebar */
--worklog-sidebar-width: 240px;
--worklog-sidebar-bg: var(--cds-ui-background); /* matches g90 */
/* Kanban columns */
--worklog-column-width: 280px;
--worklog-column-gap: 12px;
/* Ticket card */
--worklog-card-radius: 2px; /* Carbon is square-ish */
--worklog-card-padding: 12px;
/* Status colors — extend Carbon's semantic palette */
--worklog-status-backlog: var(--cds-text-02);
--worklog-status-todo: var(--cds-interactive-01);
--worklog-status-in-progress: #f1c21b; /* Carbon yellow-30 */
--worklog-status-done: #42be65; /* Carbon green-40 */
/* Priority */
--worklog-priority-low: var(--cds-text-02);
--worklog-priority-medium: var(--cds-interactive-01);
--worklog-priority-high: #ff832b; /* Carbon orange-40 */
--worklog-priority-critical: var(--cds-support-error);
/* Typography — Carbon uses IBM Plex by default; Worklog inherits this */
--worklog-font-mono: 'IBM Plex Mono', monospace;
/* Zoom — controlled by app settings (50%–200%) */
--worklog-zoom: 1;
}
Apply zoom at the app shell level:
#app-shell {
zoom: var(--worklog-zoom); /* Tauri webview supports this */
}
Component Patterns
Kanban Board
<!-- KanbanBoard.svelte -->
<script lang="ts">
import { Tag, OverflowMenu, OverflowMenuItem } from 'carbon-components-svelte';
import type { Ticket } from '$lib/db/types';
let { columns }: { columns: KanbanColumn[] } = $props();
</script>
<div class="kanban-board">
{#each columns as col}
<div class="kanban-column">
<header class="col-header">
<span class="col-title">{col.label}</span>
<Tag size="sm">{col.tickets.length}</Tag>
</header>
<div class="col-body">
{#each col.tickets as ticket (ticket.id)}
<TicketCard {ticket} />
{/each}
</div>
</div>
{/each}
</div>
<style>
.kanban-board {
display: flex;
gap: var(--worklog-column-gap);
height: 100%;
overflow-x: auto;
padding: 16px;
}
.kanban-column {
flex: 0 0 var(--worklog-column-width);
display: flex;
flex-direction: column;
background: var(--cds-ui-01);
border: 1px solid var(--cds-ui-03);
}
.col-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
border-bottom: 1px solid var(--cds-ui-03);
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--cds-text-02);
}
.col-body {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 4px;
padding: 8px;
}
</style>
Ticket Card
<!-- TicketCard.svelte -->
<script lang="ts">
import { Tag, OverflowMenu, OverflowMenuItem } from 'carbon-components-svelte';
import type { Ticket } from '$lib/db/types';
let { ticket, onSelect, onMove }: {
ticket: Ticket;
onSelect: (id: string) => void;
onMove: (id: string, direction: 'next' | 'prev') => void;
} = $props();
function handleKeydown(e: KeyboardEvent) {
if (e.key === 'm') onMove(ticket.id, 'next');
if (e.key === 'Escape') { /* close panel */ }
}
</script>
<div
class="ticket-card"
tabindex="0"
role="button"
aria-label="Ticket: {ticket.title}"
onclick={() => onSelect(ticket.id)}
onkeydown={handleKeydown}
>
<div class="ticket-header">
<span class="ticket-id">{ticket.id.slice(0, 8)}</span>
<OverflowMenu size="sm" flipped>
<OverflowMenuItem text="Move forward" on:click={() => onMove(ticket.id, 'next')} />
<OverflowMenuItem text="Move back" on:click={() => onMove(ticket.id, 'prev')} />
<OverflowMenuItem text="Delete" danger />
</OverflowMenu>
</div>
<p class="ticket-title">{ticket.title}</p>
<div class="ticket-meta">
{#if ticket.priority}
<Tag size="sm" type="outline"
style="--tag-color: var(--worklog-priority-{ticket.priority})">
{ticket.priority}
</Tag>
{/if}
{#if ticket.due_date}
<span class="ticket-date">{formatDate(ticket.due_date)}</span>
{/if}
</div>
</div>
<style>
.ticket-card {
background: var(--cds-ui-02);
border: 1px solid var(--cds-ui-03);
border-radius: var(--worklog-card-radius);
padding: var(--worklog-card-padding);
cursor: pointer;
transition: border-color 120ms ease, background 120ms ease;
}
.ticket-card:hover,
.ticket-card:focus-visible {
border-color: var(--cds-interactive-01);
outline: none;
background: var(--cds-hover-ui);
}
.ticket-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 6px;
}
.ticket-id {
font-family: var(--worklog-font-mono);
font-size: 0.6875rem;
color: var(--cds-text-03);
}
.ticket-title {
font-size: 0.875rem;
line-height: 1.4;
color: var(--cds-text-01);
margin: 0 0 8px;
}
.ticket-meta {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
}
.ticket-date {
font-size: 0.6875rem;
color: var(--cds-text-03);
font-family: var(--worklog-font-mono);
}
</style>
Command Palette
Worklog's command palette (Ctrl/Cmd+K) should use Carbon's Search inside a Modal:
<!-- CommandPalette.svelte -->
<script lang="ts">
import { Modal, Search } from 'carbon-components-svelte';
let open = $state(false);
let query = $state('');
</script>
<svelte:window onkeydown={(e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
open = true;
}
}} />
<Modal bind:open size="sm" passiveModal modalHeading="" hasScrollingContent>
<Search bind:value={query} placeholder="Type a command…" autofocus size="lg"
---
*Content truncated.*
When not to use it
- →Using skeleton loaders
- →Hardcoding paths
Prerequisites
Limitations
- →No skeleton loaders
- →No hardcoded OS paths
How it compares
It prioritizes local-first data management and keyboard-first interactions over cloud-based patterns.
Compared to similar skills
worklog-design side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| worklog-design (this skill) | 0 | 2mo | No flags | Advanced |
| svelte-ui-design | 23 | 9mo | No flags | Intermediate |
| page-builder | 1 | 7mo | No flags | Intermediate |
| scroll-experience | 101 | 6mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
svelte-ui-design
XIYO
ALWAYS use this skill for ANY Svelte component styling, design, or UI work. Svelte 5 UI design system using Tailwind CSS 4, Skeleton Labs design tokens/presets/Tailwind Components, and Bits UI headless components. Covers class composition, color systems, interactive components, forms, overlays, and all visual design.
page-builder
svelte-society
Patterns for building list and detail pages with forms, filters, and data fetching
scroll-experience
davila7
Expert in building immersive scroll-driven experiences - parallax storytelling, scroll animations, interactive narratives, and cinematic web experiences. Like NY Times interactives, Apple product pages, and award-winning web experiences. Makes websites feel like experiences, not just pages. Use when: scroll animation, parallax, scroll storytelling, interactive story, cinematic website.
tanstack-form
exceptionless
TanStack Form with Zod validation in Svelte 5. Form state management, field validation, error handling, and ProblemDetails integration. Keywords: TanStack Form, createForm, Field, form validation, zod schema, form errors, onSubmit, onSubmitAsync, problemDetailsToFormErrors
anthropic-frontend-design
chaibuilder
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
tanstack-query
exceptionless
Data fetching and caching with TanStack Query in Svelte. Query patterns, mutations, cache invalidation, WebSocket-driven updates, and optimistic updates. Keywords: createQuery, createMutation, TanStack Query, query keys, cache invalidation, optimistic updates, refetch, stale time, @exceptionless/fetchclient, WebSocket