Expiry Ring Component
Relevant source files
The following files were used as context for generating this wiki page:
The Expiry Ring Component is a visual indicator used within the Augenblick application to represent the remaining lifespan of a note before it is automatically moved to the trash. It serves as a core part of the "ephemeral note-taking" philosophy, providing real-time feedback on note aging based on the user's last interaction.
This component is specifically rendered for active, unpinned notes in the sidebar. It uses a color-coded circular progress bar and a descriptive tooltip to communicate the urgency of the note's expiration status.
Sources: README.md:14, plans/migration.inventory.md:173-174, src/features/sidebar/ExpiryRing.tsx:1-55
Component Architecture and Logic
The Expiry Ring is implemented as a React functional component that calculates its state based on two primary inputs: the timestamp of the last interaction with a note and the global expiry setting (in minutes).
State and Lifecycle
The component maintains a local now state variable, which is updated every 60 seconds via setInterval to ensure the progress and tooltip remain accurate without requiring a full application re-render.
The diagram shows the internal lifecycle of the component, highlighting the periodic update mechanism.
Sources: src/features/sidebar/ExpiryRing.tsx:13-18
Progress Calculation
The progress is calculated as a value between 0 and 1 using the following formula:
clamp01(1 - (now - lastInteraction) / totalExpiryTime).
The totalExpiryTime is derived from the user's settings, which can range from 1 to 30 days (stored as minutes).
Sources: src/lib/utils/expiry.ts:3-11, plans/migration.inventory.md:164-165
Visual Representation and Thresholds
The component uses an SVG containing two concentric circles: a background track and a foreground progress ring. The foreground ring's stroke-dashoffset is adjusted based on the calculated progress to create the visual "filling" effect.
Color Coding
The component maps the progress percentage to specific status levels and CSS variables for colors:
| Status | Threshold | Color Variable | Description |
|---|---|---|---|
| Fresh | ≥ 50% | var(--ring-green) | Note was recently active. |
| Aging | 25% - 49% | var(--ring-yellow) | Note is middle-aged. |
| Warning | 10% - 24% | var(--ring-orange) | Note is approaching expiration. |
| Danger | < 10% | var(--ring-red) | Note will be trashed very soon. |
Sources: src/lib/utils/expiry.ts:17-24, src/features/sidebar/ExpiryRing.tsx:23-31, src/test/features/ExpiryRing.test.tsx:43-70
Tooltip and Accessibility
The component is wrapped in a TooltipProvider with a delay of 550ms. The tooltip displays a relative time string (e.g., "Trashed in 3d") indicating exactly when the note will be moved to the trash. An aria-label is also applied to the SVG container for screen reader compatibility.
Sources: src/features/sidebar/ExpiryRing.tsx:38-51, src/test/features/ExpiryRing.test.tsx:32-34
Data Flow Integration
The Expiry Ring does not fetch data itself; it receives its configuration from the parent NoteItem component.
This sequence illustrates how data flows from the central store through components to the utility functions for visual computation.
Sources: src/features/sidebar/ExpiryRing.tsx:10-40, src/test/features/NoteItem.test.tsx:28-35
Constraints and Visibility
The Expiry Ring is subject to specific visibility rules within the sidebar:
- Active Notes: Visible only if the note is in the active list.
- Pinned Notes: Hidden for pinned notes, as they do not expire.
- Trashed Notes: Hidden; trashed notes use a different countdown string (e.g., "Deletes in 30d") instead of a ring.
Sources: plans/migration.inventory.md:173-174, src/test/features/NoteItem.test.tsx:44-53
The Expiry Ring Component effectively bridges the gap between raw backend timestamps and user-facing status, ensuring the "disappearing" nature of the application is transparent and predictable.