WO

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.zip

Installs 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.
356 charsno explicit “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

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

You give it
Design requirements
You get back
UI implementation

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:

QualityWhat it means in practice
FastInstant feedback. No loading skeletons for local SQLite data. Transitions ≤ 150 ms.
Keyboard-firstEvery action reachable without a mouse. Shortcuts visible in tooltips.
Dense, not clutteredInformation-rich layout typical of desktop apps. Prefer compact Carbon sizing.
Local-first transparencyNo cloud metaphors. Workspace = folder on disk.
Small team focusNo enterprise complexity. One workspace, one team, clear hierarchy.

Stack Constraints

SvelteKit 5 + Svelte Runes

  • Components use $state, $derived, $effect — no writable() stores for new code.
  • Layouts own scope: workspace scope in +layout.svelte, board scope in nested layouts.
  • Use $page from $app/stores for route params; prefer typed params via RouteParams.
  • Async data goes in +page.ts / +layout.ts load() functions, not inline onMount.
  • Avoid onMount for 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 in src/lib/db/.
  • Never call the repository directly from a component — always go through a hook in src/lib/hooks/.
  • Tauri invoke for 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.html or root +layout.svelte: import 'carbon-components-svelte/css/g90.css'
    • For light mode support, dynamically swap to g10.
  • Use optimizeImports from carbon-preprocess-svelte in svelte.config.js to 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 !important hacks.
  • Common components to reach for first:
Use caseCarbon component
Sidebar navSideNav, SideNavItems, SideNavLink, SideNavMenu
Command palette / searchSearch + custom modal overlay
Ticket cardsTile, ClickableTile
Modals / dialogsModal
FormsTextInput, TextArea, Select, Toggle, Checkbox
Tags / labelsTag
Data tablesDataTable, Toolbar, ToolbarSearch
NotificationsInlineNotification, ToastNotification
ButtonsButton, IconButton
Context menusOverflowMenu, OverflowMenuItem
TooltipsTooltip, TooltipDefinition
Progress / loadingInlineLoading, 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 (240px default, resizable via CSS variable --worklog-sidebar-width).
  • The title bar drag region must use -webkit-app-region: drag with 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

SvelteKit 5Tauri v2

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.

SkillInstallsUpdatedSafetyDifficulty
worklog-design (this skill)02moNo flagsAdvanced
svelte-ui-design239moNo flagsIntermediate
page-builder17moNo flagsIntermediate
scroll-experience1016moNo flagsIntermediate

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.

23136

page-builder

svelte-society

Patterns for building list and detail pages with forms, filters, and data fetching

13

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.

101142

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

1670

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.

1237

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

740

Search skills

Search the agent skills registry