Sigta UI · Kit

Save state

The compass stands in for "Saving…". It draws while a save is in flight, lands with a handwritten "Saved" as the mark completes, and shakes red when a save fails, validation errors included. Typing into a watched field greys it and takes away the arc: unsaved.

It never moves. Every label shares one cell, so it keeps the width of its longest whatever it is saying. At the right end of a bar, align="end" puts the compass flush right and lets the words grow leftward.

States

Unsaved changes Saving… Saved Not saved Unsaved changes Saving… Saved Not saved Unsaved changes Saving… Saved Not saved Unsaved changes Saving… Saved Not saved Unsaved changes Saving… Saved Not saved All changes saved
Source
<div class="flex flex-wrap items-center gap-x-10 gap-y-4">
        <sigta:save-state state="dirty" />
        <sigta:save-state state="saving" />
        <sigta:save-state state="saved" />
        <sigta:save-state state="failed" />
        <sigta:save-state idle="All changes saved" />
    </div>

Livewire — follows the component by itself (target names actions and/or properties)

Autosaving note

Unsaved changes Saving… Saved Not saved All changes saved
Unsaved changes Saving… Saved Not saved
<sigta:save-state target="title, body" idle="All changes saved" align="end" />
<sigta:input wire:model.live.debounce.500ms="title" />

<sigta:button wire:click="save">Save now</sigta:button>
<sigta:save-state target="save" />

Alpine / JS — drive it by name with $sigta.save(promise, name)

Profile

Unsaved changes Saving… Saved Not saved Up to date
Source
<div class="flex max-w-lg flex-col gap-3" x-data="{ fail: false, draft() { return new Promise((resolve, reject) => setTimeout(() => this.fail ? reject(new Error('Demo failure')) : resolve(), 1200)) } }">
        <div class="flex items-center justify-between gap-4">
            <sigta:eyebrow>Profile</sigta:eyebrow>
            <sigta:save-state name="profile" idle="Up to date" align="end" />
        </div>
        <sigta:textarea rows="3" x-on:input="$sigta.saveState('dirty', 'profile')" x-on:input.debounce.700ms="$sigta.save(draft(), 'profile').catch(() => {})">A studio for paper-quiet software.</sigta:textarea>
        <sigta:checkbox label="Make the next save fail" x-model="fail" />
    </div>