fix(app): iOS HIG Phase 1 — input font sizes and text minimums

- Replace all text-[10px] (308 instances) with text-xs (12px)
- Replace all text-[9px] and text-[8px] (133 instances) with text-xs
- Replace all text-[11px] (76 instances) with text-xs
- Bump all input/textarea font sizes to text-base (16px) to prevent iOS auto-zoom
- No visual design changes — only sizing minimums enforced

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-04 12:53:25 +00:00
co-authored by Claude Opus 4.6
parent dde3859a2e
commit b2fcc23623
97 changed files with 5561 additions and 564 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ define(['./workbox-f97094b3'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812"
}, {
"url": "index.html",
"revision": "0.0t39d8ip1tk"
"revision": "0.b6ot7ui3o7c"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
<template>
<div class="px-3 md:px-4 pb-1">
<button
class="flex items-center gap-1.5 text-[11px] text-white/40 hover:text-white/60 transition-colors"
class="flex items-center gap-1.5 text-xs text-white/40 hover:text-white/60 transition-colors"
@click="isExpanded = !isExpanded"
>
<svg
@@ -19,8 +19,8 @@
<!-- Temperature -->
<div class="space-y-1">
<div class="flex items-center justify-between">
<label class="text-[11px] text-white/40">Temperature</label>
<span class="text-[11px] text-white/50 tabular-nums">{{ temperature.toFixed(2) }}</span>
<label class="text-xs text-white/40">Temperature</label>
<span class="text-xs text-white/50 tabular-nums">{{ temperature.toFixed(2) }}</span>
</div>
<input
v-model.number="temperature"
@@ -36,8 +36,8 @@
<!-- Max Tokens -->
<div class="space-y-1">
<div class="flex items-center justify-between">
<label class="text-[11px] text-white/40">Max Tokens</label>
<span class="text-[11px] text-white/50 tabular-nums">{{ maxTokens }}</span>
<label class="text-xs text-white/40">Max Tokens</label>
<span class="text-xs text-white/50 tabular-nums">{{ maxTokens }}</span>
</div>
<input
v-model.number="maxTokens"
@@ -53,8 +53,8 @@
<!-- Top P -->
<div class="space-y-1">
<div class="flex items-center justify-between">
<label class="text-[11px] text-white/40">Top P</label>
<span class="text-[11px] text-white/50 tabular-nums">{{ topP.toFixed(2) }}</span>
<label class="text-xs text-white/40">Top P</label>
<span class="text-xs text-white/50 tabular-nums">{{ topP.toFixed(2) }}</span>
</div>
<input
v-model.number="topP"
@@ -69,12 +69,12 @@
<!-- Stop Sequences (M9.10) -->
<div class="space-y-1">
<label class="text-[11px] text-white/40">Stop Sequences</label>
<label class="text-xs text-white/40">Stop Sequences</label>
<div v-if="stopSequences.length > 0" class="flex gap-1 flex-wrap mb-1">
<span
v-for="(seq, i) in stopSequences"
:key="i"
class="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-[10px] text-white/50"
class="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-xs text-white/50"
>
{{ seq }}
<button class="text-white/30 hover:text-white/60" @click="removeStopSequence(i)">×</button>
@@ -83,7 +83,7 @@
<input
v-model="newStopSeq"
type="text"
class="w-full bg-white/5 border border-white/10 rounded-lg px-2.5 py-1.5 text-xs text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
class="w-full bg-white/5 border border-white/10 rounded-lg px-2.5 py-1.5 text-base text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
placeholder="Add stop sequence (Enter to add)"
@keydown.enter="addStopSequence"
/>
@@ -91,7 +91,7 @@
<!-- Reset -->
<button
class="text-[11px] text-white/30 hover:text-white/50 transition-colors"
class="text-xs text-white/30 hover:text-white/50 transition-colors"
@click="resetDefaults"
>
Reset to defaults
@@ -3,7 +3,7 @@
v-if="branches.length > 1"
class="flex items-center justify-center px-4 py-1.5 animate-fade-up-fast"
>
<div class="glass-button-sm !h-7 !min-h-0 flex items-center gap-1.5 px-2 text-[11px]">
<div class="glass-button-sm !h-7 !min-h-0 flex items-center gap-1.5 px-2 text-xs">
<button
class="w-5 h-5 flex items-center justify-center rounded-md hover:bg-white/10 transition-colors text-white/60 hover:text-white/90 disabled:opacity-30 disabled:cursor-default"
:disabled="currentIndex <= 0"
@@ -27,7 +27,7 @@
<!-- Mint info -->
<div
class="text-[10px] font-mono"
class="text-xs font-mono"
:class="isDark ? 'text-white/30' : 'text-gray-400'"
>
Mint: {{ displayMint }}
@@ -45,7 +45,7 @@
<!-- Actions -->
<div class="flex gap-2">
<button
class="flex-1 px-3 py-1.5 rounded-lg text-[10px] font-medium transition-colors"
class="flex-1 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors"
:class="isDark
? 'bg-white/5 text-white/60 hover:bg-white/10'
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'"
@@ -54,7 +54,7 @@
{{ copied ? 'Copied!' : 'Copy Token' }}
</button>
<button
class="flex-1 px-3 py-1.5 rounded-lg text-[10px] font-medium transition-colors bg-[#F7931A]/10 text-[#F7931A] hover:bg-[#F7931A]/20"
class="flex-1 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors bg-[#F7931A]/10 text-[#F7931A] hover:bg-[#F7931A]/20"
@click="openInWallet"
>
Open in Wallet
@@ -122,9 +122,9 @@
<div class="w-full text-left pt-3 pb-1 min-w-0">
<h2 class="text-sm font-semibold truncate text-white/96">{{ title }}</h2>
<div class="flex items-center gap-1.5 mt-0.5">
<p class="text-[10px] truncate font-mono text-white/40">{{ conversationId }}</p>
<span class="text-[10px] text-white/20">·</span>
<span class="text-[10px] truncate text-white/50">{{ modelDisplayName }}</span>
<p class="text-xs truncate font-mono text-white/40">{{ conversationId }}</p>
<span class="text-xs text-white/20">·</span>
<span class="text-xs truncate text-white/50">{{ modelDisplayName }}</span>
</div>
</div>
@@ -138,7 +138,7 @@
@click.stop
>
<div v-for="provider in availableProviders" :key="provider.id">
<p class="text-[10px] font-semibold uppercase tracking-wider mb-1.5 px-1 text-white/40">
<p class="text-xs font-semibold uppercase tracking-wider mb-1.5 px-1 text-white/40">
{{ provider.name }}
</p>
<div class="space-y-0.5">
@@ -155,17 +155,17 @@
<span class="flex gap-0.5 shrink-0">
<span
v-if="getModelCaps(model.id).vision"
class="text-[10px] opacity-60"
class="text-xs opacity-60"
title="Supports vision input"
>👁</span>
<span
v-if="getModelCaps(model.id).tools"
class="text-[10px] opacity-60"
class="text-xs opacity-60"
title="Supports tool use"
>🔧</span>
<span
v-if="getModelCaps(model.id).longContext"
class="text-[10px] opacity-60"
class="text-xs opacity-60"
title="Long context window"
>📄</span>
</span>
@@ -198,7 +198,7 @@
:style="menuDropdownStyle"
@click.stop
>
<p class="text-[10px] font-semibold uppercase tracking-wider mb-1.5 px-2 text-white/40">Export</p>
<p class="text-xs font-semibold uppercase tracking-wider mb-1.5 px-2 text-white/40">Export</p>
<button
class="w-full text-left px-3 py-2 rounded-lg text-xs text-white/60 hover:text-white hover:bg-white/10 transition-all"
@click="handleExport('markdown')"
@@ -25,11 +25,11 @@
{{ conv.title || 'Untitled' }}
</p>
<div class="flex items-center gap-1.5 mt-1">
<span class="text-[10px] text-white/30">
<span class="text-xs text-white/30">
{{ formatTime(conv.updatedAt) }}
</span>
<span class="text-[10px] text-white/20">&middot;</span>
<span class="text-[10px] text-white/30">
<span class="text-xs text-white/20">&middot;</span>
<span class="text-xs text-white/30">
{{ conv.messages.length }} msg{{ conv.messages.length !== 1 ? 's' : '' }}
</span>
</div>
@@ -18,7 +18,7 @@
class="mb-2 flex items-start gap-2 rounded-xl bg-white/5 border border-white/10 px-3 py-2 animate-fade-up-fast"
>
<div class="flex-1 min-w-0">
<p class="text-[10px] text-accent/70 font-medium mb-0.5">Replying to</p>
<p class="text-xs text-accent/70 font-medium mb-0.5">Replying to</p>
<p class="text-xs text-white/50 truncate">{{ replyTo.excerpt }}</p>
</div>
<button
@@ -54,7 +54,7 @@
</svg>
</button>
</div>
<span v-if="images.length >= MAX_IMAGES" class="self-center text-[10px] text-white/30">
<span v-if="images.length >= MAX_IMAGES" class="self-center text-xs text-white/30">
Max {{ MAX_IMAGES }} images
</span>
</div>
@@ -102,7 +102,7 @@
v-model="text"
rows="1"
:placeholder="placeholder"
class="flex-1 resize-none bg-transparent text-sm outline-none min-h-[24px] max-h-[120px] text-white/90 placeholder:text-white/25"
class="flex-1 resize-none bg-transparent text-base outline-none min-h-[24px] max-h-[120px] text-white/90 placeholder:text-white/25"
@keydown="handleKeydown"
@input="autoResize"
@paste="onPaste"
@@ -276,90 +276,90 @@
</div>
<div v-if="!isEditing" class="flex items-center gap-2 mt-1.5">
<span class="text-[10px] select-none text-white/30">{{ formattedTime }}</span>
<span v-if="message.editedAt" class="text-[10px] text-white/25 select-none">(edited)</span>
<span v-if="showTokenCount" class="text-[10px] text-white/20 select-none" :title="`~${estimatedTokens} tokens`">{{ tokenLabel }}</span>
<span v-if="message.feedback" class="text-[10px] select-none">{{ message.feedback === 'up' ? '👍' : '👎' }}</span>
<span class="text-xs select-none text-white/30">{{ formattedTime }}</span>
<span v-if="message.editedAt" class="text-xs text-white/25 select-none">(edited)</span>
<span v-if="showTokenCount" class="text-xs text-white/20 select-none" :title="`~${estimatedTokens} tokens`">{{ tokenLabel }}</span>
<span v-if="message.feedback" class="text-xs select-none">{{ message.feedback === 'up' ? '👍' : '👎' }}</span>
<button
v-if="inlineFilms.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlineFilms.length }} films
</button>
<button
v-else-if="inlineBooks.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlineBooks.length }} books
</button>
<button
v-else-if="inlineTVSeries.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlineTVSeries.length }} series
</button>
<button
v-else-if="inlineImages.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlineImages.length }} images
</button>
<button
v-else-if="inlinePlaces.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlinePlaces.length }} places
</button>
<button
v-if="inlinePlaces.length > 0 && inlinePlaces.some(p => p.lat != null)"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openMapView(inlinePlaces)"
>
View on map
</button>
<button
v-else-if="inlineSongs.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlineSongs.length }} songs
</button>
<button
v-else-if="inlinePodcasts.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlinePodcasts.length }} podcasts
</button>
<button
v-else-if="inlineNewsLinks.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlineNewsLinks.length }} articles
</button>
<button
v-else-if="inlineWebsitesLinks.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View all {{ inlineWebsitesLinks.length }} websites
</button>
<button
v-else-if="inlineMagazineSections.length > 0"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openPanel"
>
View brief
</button>
<button
v-if="isLongForm"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
class="text-xs text-accent/70 hover:text-accent transition-colors"
@click.stop="openLongFormArticle(message.content)"
>
Read as article
@@ -11,14 +11,14 @@
v-model="query"
type="text"
placeholder="Search messages..."
class="flex-1 bg-transparent text-sm text-white/90 placeholder:text-white/25 outline-none min-w-0"
class="flex-1 bg-transparent text-base text-white/90 placeholder:text-white/25 outline-none min-w-0"
@keydown.enter.exact="nextMatch"
@keydown.shift.enter="prevMatch"
@keydown.escape="close"
@keydown.up.prevent="prevMatch"
@keydown.down.prevent="nextMatch"
/>
<span v-if="query" class="text-[10px] text-white/40 whitespace-nowrap select-none">
<span v-if="query" class="text-xs text-white/40 whitespace-nowrap select-none">
{{ matchCount > 0 ? `${currentMatchIndex + 1}/${matchCount}` : 'No results' }}
</span>
<button
@@ -108,7 +108,7 @@
v-if="codeContext.isCodeMode.value && codeContext.activeProject.value"
class="px-3 pb-1 flex items-center gap-1.5"
>
<span class="text-[10px] px-2 py-0.5 rounded-md bg-accent/15 text-accent font-medium truncate max-w-[200px]">
<span class="text-xs px-2 py-0.5 rounded-md bg-accent/15 text-accent font-medium truncate max-w-[200px]">
{{ codeContext.activeProject.value.name }}
</span>
<button
@@ -23,8 +23,8 @@
:class="{ 'hidden md:flex': activeTab !== 0 }"
>
<div class="px-3 py-2 flex items-center justify-between border-b border-white/5">
<span class="text-[10px] text-accent font-medium truncate">{{ model1Label }}</span>
<span v-if="isStreaming1" class="text-[10px] text-white/30 animate-pulse">streaming...</span>
<span class="text-xs text-accent font-medium truncate">{{ model1Label }}</span>
<span v-if="isStreaming1" class="text-xs text-white/30 animate-pulse">streaming...</span>
</div>
<div class="flex-1 overflow-y-auto p-3">
<div
@@ -43,8 +43,8 @@
:class="{ 'hidden md:flex': activeTab !== 1 }"
>
<div class="px-3 py-2 flex items-center justify-between border-b border-white/5">
<span class="text-[10px] text-accent font-medium truncate">{{ model2Label }}</span>
<span v-if="isStreaming2" class="text-[10px] text-white/30 animate-pulse">streaming...</span>
<span class="text-xs text-accent font-medium truncate">{{ model2Label }}</span>
<span v-if="isStreaming2" class="text-xs text-white/30 animate-pulse">streaming...</span>
</div>
<div class="flex-1 overflow-y-auto p-3">
<div
@@ -11,7 +11,7 @@
/>
<!-- Tooltip on hover -->
<div
class="absolute -top-8 left-1/2 -translate-x-1/2 hidden group-hover:flex items-center px-2 py-1 rounded-md bg-black/80 text-[10px] text-white/80 whitespace-nowrap pointer-events-none z-10"
class="absolute -top-8 left-1/2 -translate-x-1/2 hidden group-hover:flex items-center px-2 py-1 rounded-md bg-black/80 text-xs text-white/80 whitespace-nowrap pointer-events-none z-10"
>
{{ tooltipText }}
</div>
@@ -2,7 +2,7 @@
<div class="px-3 md:px-4 pb-1">
<!-- Collapsed toggle -->
<button
class="flex items-center gap-1.5 text-[11px] text-white/40 hover:text-white/60 transition-colors"
class="flex items-center gap-1.5 text-xs text-white/40 hover:text-white/60 transition-colors"
@click="isExpanded = !isExpanded"
>
<svg
@@ -27,12 +27,12 @@
<input
v-model="editText"
type="text"
class="flex-1 bg-transparent text-xs text-white/80 outline-none"
class="flex-1 bg-transparent text-base text-white/80 outline-none"
@keydown.enter="saveEdit(item.id)"
@keydown.escape="cancelEdit"
/>
<button
class="text-[10px] text-accent/70 hover:text-accent"
class="text-xs text-accent/70 hover:text-accent"
@click="saveEdit(item.id)"
>
Save
@@ -66,19 +66,19 @@
<input
v-model="newText"
type="text"
class="flex-1 bg-white/5 border border-white/10 rounded-lg px-2.5 py-1.5 text-xs text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
class="flex-1 bg-white/5 border border-white/10 rounded-lg px-2.5 py-1.5 text-base text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
placeholder="Add a memory..."
@keydown.enter="addMemory"
/>
<button
class="px-2.5 py-1.5 rounded-lg text-[11px] bg-accent/15 text-accent/80 hover:bg-accent/25 transition-all"
class="px-2.5 py-1.5 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-all"
:disabled="!newText.trim()"
@click="addMemory"
>
Add
</button>
</div>
<p v-else class="text-[10px] text-white/25">
<p v-else class="text-xs text-white/25">
Maximum 20 memories reached
</p>
</div>
+10 -10
View File
@@ -25,11 +25,11 @@
<!-- Error -->
<div v-else-if="error" class="flex items-center gap-2">
<span class="text-[10px]" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ isProfile ? 'Profile' : 'Note' }} not found
</span>
<span
class="text-[9px] font-mono truncate"
class="text-xs font-mono truncate"
:class="isDark ? 'text-purple-400/40' : 'text-purple-400'"
>
{{ truncatedId }}
@@ -40,33 +40,33 @@
<div v-else-if="note">
<div class="flex items-center gap-2 mb-1.5">
<div
class="w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-[9px] font-bold"
class="w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-xs font-bold"
:class="isDark ? 'bg-purple-500/20 text-purple-400' : 'bg-purple-100 text-purple-600'"
>
{{ note.authorName?.charAt(0)?.toUpperCase() ?? '?' }}
</div>
<span
class="text-[11px] font-semibold truncate"
class="text-xs font-semibold truncate"
:class="isDark ? 'text-white/70' : 'text-gray-700'"
>
{{ note.authorName ?? 'anon' }}
</span>
<span
class="text-[9px] ml-auto shrink-0"
class="text-xs ml-auto shrink-0"
:class="isDark ? 'text-white/20' : 'text-gray-300'"
>
{{ formatTime(note.created_at) }}
</span>
</div>
<p
class="text-[11px] leading-relaxed line-clamp-4"
class="text-xs leading-relaxed line-clamp-4"
:class="isDark ? 'text-white/60' : 'text-gray-600'"
>
{{ note.content }}
</p>
<div class="flex items-center gap-2 mt-1.5">
<span
class="text-[9px] font-mono"
class="text-xs font-mono"
:class="isDark ? 'text-purple-400/40' : 'text-purple-400/60'"
>
nostr
@@ -78,20 +78,20 @@
<div v-else-if="isProfile">
<div class="flex items-center gap-2">
<div
class="w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-[10px] font-bold"
class="w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-xs font-bold"
:class="isDark ? 'bg-purple-500/20 text-purple-400' : 'bg-purple-100 text-purple-600'"
>
{{ truncatedId.charAt(0).toUpperCase() }}
</div>
<div>
<span
class="text-[11px] font-mono block"
class="text-xs font-mono block"
:class="isDark ? 'text-white/60' : 'text-gray-600'"
>
{{ truncatedId }}
</span>
<span
class="text-[9px]"
class="text-xs"
:class="isDark ? 'text-purple-400/40' : 'text-purple-400/60'"
>
nostr profile
@@ -4,7 +4,7 @@
<button
v-for="p in personaStore.sortedPersonas"
:key="p.id"
class="px-2.5 py-1 rounded-full text-[11px] font-medium transition-all duration-200 border"
class="px-2.5 py-1 rounded-full text-xs font-medium transition-all duration-200 border"
:class="isActive(p.id)
? 'bg-accent/20 text-accent border-accent/30'
: 'bg-white/5 text-white/50 border-white/10 hover:text-white/70 hover:bg-white/10'"
@@ -18,14 +18,14 @@
{{ p.name }}
</button>
<button
class="px-2 py-1 rounded-full text-[11px] text-white/30 hover:text-white/60 border border-transparent hover:border-white/10 transition-all duration-200"
class="px-2 py-1 rounded-full text-xs text-white/30 hover:text-white/60 border border-transparent hover:border-white/10 transition-all duration-200"
@click="showEditor = true"
>
+ New
</button>
<button
v-if="activePersonaId"
class="px-2 py-1 rounded-full text-[11px] text-white/30 hover:text-white/60 transition-all"
class="px-2 py-1 rounded-full text-xs text-white/30 hover:text-white/60 transition-all"
title="Clear persona"
@click="clearPersona"
>
@@ -58,20 +58,20 @@
<div class="space-y-3">
<div>
<label class="block text-[11px] text-white/40 mb-1">Name</label>
<label class="block text-xs text-white/40 mb-1">Name</label>
<input
v-model="formName"
type="text"
class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-sm text-white/90 focus:outline-none focus:border-accent/50"
class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-base text-white/90 focus:outline-none focus:border-accent/50"
placeholder="e.g. Film Critic"
/>
</div>
<div>
<label class="block text-[11px] text-white/40 mb-1">System Prompt</label>
<label class="block text-xs text-white/40 mb-1">System Prompt</label>
<textarea
v-model="formPrompt"
class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-sm text-white/90 resize-none focus:outline-none focus:border-accent/50"
class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-base text-white/90 resize-none focus:outline-none focus:border-accent/50"
rows="5"
placeholder="You are a film critic who..."
/>
@@ -79,10 +79,10 @@
<div class="flex gap-3">
<div class="flex-1">
<label class="block text-[11px] text-white/40 mb-1">Model Preference</label>
<label class="block text-xs text-white/40 mb-1">Model Preference</label>
<select
v-model="formModel"
class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-sm text-white/90 focus:outline-none focus:border-accent/50"
class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-base text-white/90 focus:outline-none focus:border-accent/50"
>
<option value="">Default</option>
<option value="claude-haiku-4.5">Claude 4.5 Haiku</option>
@@ -91,7 +91,7 @@
</select>
</div>
<div class="w-20">
<label class="block text-[11px] text-white/40 mb-1">Colour</label>
<label class="block text-xs text-white/40 mb-1">Colour</label>
<input
v-model="formColor"
type="color"
@@ -21,13 +21,13 @@
{{ pair.userMsg.content }}
</p>
<div class="flex items-center gap-1.5 mt-1 flex-wrap">
<span class="text-[10px] text-white/30">
<span class="text-xs text-white/30">
{{ formatTime(pair.userMsg.timestamp) }}
</span>
<span
v-for="badge in pair.badges"
:key="badge"
class="text-[9px] px-1.5 py-0.5 rounded-md bg-white/8 text-white/40"
class="text-xs px-1.5 py-0.5 rounded-md bg-white/8 text-white/40"
>
{{ badge }}
</span>
@@ -8,18 +8,18 @@
<div class="flex items-center justify-between">
<h4 class="text-xs font-semibold text-white/80">{{ selectedTemplate.title }}</h4>
<button
class="text-[10px] text-white/40 hover:text-white/60 transition-colors"
class="text-xs text-white/40 hover:text-white/60 transition-colors"
@click="cancelTemplate"
>
Cancel
</button>
</div>
<div v-for="v in variables" :key="v" class="space-y-1">
<label class="text-[11px] text-white/40">{{ v }}</label>
<label class="text-xs text-white/40">{{ v }}</label>
<input
v-model="variableValues[v]"
type="text"
class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-1.5 text-sm text-white/90 focus:outline-none focus:border-accent/50"
class="w-full bg-white/5 border border-white/10 rounded-lg px-3 py-1.5 text-base text-white/90 focus:outline-none focus:border-accent/50"
:placeholder="v"
@keydown.enter="applyTemplate"
/>
@@ -40,7 +40,7 @@
<!-- Commands section -->
<div v-if="filteredCommands.length > 0">
<div class="p-2 border-b border-white/5">
<p class="text-[10px] text-white/30 px-2">Commands</p>
<p class="text-xs text-white/30 px-2">Commands</p>
</div>
<div
v-for="(cmd, i) in filteredCommands"
@@ -51,17 +51,17 @@
@mouseenter="highlightIndex = i"
>
<div class="flex items-center gap-2">
<span class="text-[11px] font-mono text-accent/70">{{ cmd.slash }}</span>
<span class="text-xs font-mono text-accent/70">{{ cmd.slash }}</span>
<p class="text-sm text-white/80">{{ cmd.title }}</p>
</div>
<p v-if="cmd.preview" class="text-[11px] text-white/40 mt-0.5 truncate">{{ cmd.preview }}</p>
<p v-if="cmd.preview" class="text-xs text-white/40 mt-0.5 truncate">{{ cmd.preview }}</p>
</div>
</div>
<!-- Templates section -->
<div v-if="filteredUserTemplates.length > 0">
<div class="p-2 border-b border-white/5">
<p class="text-[10px] text-white/30 px-2">Templates</p>
<p class="text-xs text-white/30 px-2">Templates</p>
</div>
<div
v-for="(t, i) in filteredUserTemplates"
@@ -72,7 +72,7 @@
@mouseenter="highlightIndex = filteredCommands.length + i"
>
<p class="text-sm text-white/80">{{ t.title }}</p>
<p v-if="t.preview" class="text-[11px] text-white/40 mt-0.5 truncate">{{ t.preview }}</p>
<p v-if="t.preview" class="text-xs text-white/40 mt-0.5 truncate">{{ t.preview }}</p>
</div>
</div>
@@ -27,7 +27,7 @@
<!-- Memory Section -->
<div class="space-y-2">
<h3 class="text-[11px] font-semibold uppercase tracking-wider text-white/40">
<h3 class="text-xs font-semibold uppercase tracking-wider text-white/40">
Memory ({{ memoryStore.items.length }}/20)
</h3>
@@ -41,12 +41,12 @@
<input
v-model="editText"
type="text"
class="flex-1 bg-transparent text-xs text-white/80 outline-none"
class="flex-1 bg-transparent text-base text-white/80 outline-none"
@keydown.enter="saveEdit(item.id)"
@keydown.escape="cancelEdit"
/>
<button
class="text-[10px] text-accent/70 hover:text-accent"
class="text-xs text-accent/70 hover:text-accent"
@click="saveEdit(item.id)"
>
Save
@@ -79,19 +79,19 @@
<input
v-model="newMemoryText"
type="text"
class="flex-1 bg-white/5 border border-white/10 rounded-lg px-2.5 py-1.5 text-xs text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
class="flex-1 bg-white/5 border border-white/10 rounded-lg px-2.5 py-1.5 text-base text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
placeholder="Add a memory..."
@keydown.enter="addMemory"
/>
<button
class="px-2.5 py-1.5 rounded-lg text-[11px] bg-accent/15 text-accent/80 hover:bg-accent/25 transition-all"
class="px-2.5 py-1.5 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-all"
:disabled="!newMemoryText.trim()"
@click="addMemory"
>
Add
</button>
</div>
<p v-else class="text-[10px] text-white/25">
<p v-else class="text-xs text-white/25">
Maximum 20 memories reached
</p>
</div>
@@ -102,15 +102,15 @@
<!-- Advanced Section -->
<div class="space-y-3">
<h3 class="text-[11px] font-semibold uppercase tracking-wider text-white/40">
<h3 class="text-xs font-semibold uppercase tracking-wider text-white/40">
Advanced
</h3>
<template v-if="conv">
<div class="space-y-1">
<div class="flex items-center justify-between">
<label class="text-[11px] text-white/40">Temperature</label>
<span class="text-[11px] text-white/50 tabular-nums">{{ temperature.toFixed(2) }}</span>
<label class="text-xs text-white/40">Temperature</label>
<span class="text-xs text-white/50 tabular-nums">{{ temperature.toFixed(2) }}</span>
</div>
<input
v-model.number="temperature"
@@ -125,8 +125,8 @@
<div class="space-y-1">
<div class="flex items-center justify-between">
<label class="text-[11px] text-white/40">Max Tokens</label>
<span class="text-[11px] text-white/50 tabular-nums">{{ maxTokens }}</span>
<label class="text-xs text-white/40">Max Tokens</label>
<span class="text-xs text-white/50 tabular-nums">{{ maxTokens }}</span>
</div>
<input
v-model.number="maxTokens"
@@ -141,8 +141,8 @@
<div class="space-y-1">
<div class="flex items-center justify-between">
<label class="text-[11px] text-white/40">Top P</label>
<span class="text-[11px] text-white/50 tabular-nums">{{ topP.toFixed(2) }}</span>
<label class="text-xs text-white/40">Top P</label>
<span class="text-xs text-white/50 tabular-nums">{{ topP.toFixed(2) }}</span>
</div>
<input
v-model.number="topP"
@@ -156,12 +156,12 @@
</div>
<div class="space-y-1">
<label class="text-[11px] text-white/40">Stop Sequences</label>
<label class="text-xs text-white/40">Stop Sequences</label>
<div v-if="stopSequences.length > 0" class="flex gap-1 flex-wrap mb-1">
<span
v-for="(seq, i) in stopSequences"
:key="i"
class="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-[10px] text-white/50"
class="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-xs text-white/50"
>
{{ seq }}
<button class="text-white/30 hover:text-white/60" @click="removeStopSequence(i)">&times;</button>
@@ -170,14 +170,14 @@
<input
v-model="newStopSeq"
type="text"
class="w-full bg-white/5 border border-white/10 rounded-lg px-2.5 py-1.5 text-xs text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
class="w-full bg-white/5 border border-white/10 rounded-lg px-2.5 py-1.5 text-base text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
placeholder="Add stop sequence (Enter to add)"
@keydown.enter="addStopSequence"
/>
</div>
<button
class="text-[11px] text-white/30 hover:text-white/50 transition-colors"
class="text-xs text-white/30 hover:text-white/50 transition-colors"
@click="resetDefaults"
>
Reset to defaults
@@ -22,12 +22,12 @@
<h2 class="text-lg font-bold text-white">{{ app.name }}</h2>
<div class="flex flex-wrap items-center gap-x-2 gap-y-0.5 mt-1 text-xs text-white/60">
<span
class="px-1.5 py-0.5 rounded text-[10px] font-medium bg-white/15"
class="px-1.5 py-0.5 rounded text-xs font-medium bg-white/15"
>{{ categoryLabel }}</span>
<span
v-for="p in app.platforms"
:key="p"
class="text-[10px]"
class="text-xs"
>{{ platformLabel(p) }}</span>
</div>
</div>
@@ -49,7 +49,7 @@
class="flex gap-2.5 text-xs"
>
<span
class="w-5 h-5 rounded-full flex items-center justify-center text-[10px] font-bold shrink-0 mt-0.5"
class="w-5 h-5 rounded-full flex items-center justify-center text-xs font-bold shrink-0 mt-0.5"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'"
>{{ i + 1 }}</span>
<span :class="isDark ? 'text-white/70' : 'text-gray-600'">{{ step }}</span>
@@ -79,7 +79,7 @@
<div>
<p class="text-xs font-medium"
:class="isDark ? 'text-white/80' : 'text-gray-800'">{{ app.url.replace(/^https?:\/\//, '') }}</p>
<p class="text-[10px]"
<p class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">Official website</p>
</div>
</div>
@@ -112,7 +112,7 @@
<div class="min-w-0">
<p class="text-xs font-medium truncate"
:class="isDark ? 'text-white/80' : 'text-gray-800'">{{ related.name }}</p>
<p class="text-[10px] truncate"
<p class="text-xs truncate"
:class="isDark ? 'text-white/30' : 'text-gray-400'">{{ related.description }}</p>
</div>
</button>
@@ -8,7 +8,7 @@
<h3 class="text-sm font-bold" :class="isDark ? 'text-white/90' : 'text-gray-900'">
{{ title }}
</h3>
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredApps.length }} apps
</span>
</div>
@@ -17,7 +17,7 @@
v-model="search"
type="text"
placeholder="Search apps..."
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10'
: 'bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5'"
@@ -27,7 +27,7 @@
<button
v-for="cat in categories"
:key="cat.value"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeCategory === cat.value
? 'nav-tab-active'
: isDark
@@ -65,13 +65,13 @@
{{ app.name }}
</p>
<span
class="text-[9px] px-1.5 py-0.5 rounded font-medium shrink-0"
class="text-xs px-1.5 py-0.5 rounded font-medium shrink-0"
:class="isDark ? 'bg-white/10 text-white/50' : 'bg-black/5 text-gray-500'"
>
{{ categoryLabel(app.category) }}
</span>
</div>
<p class="text-[11px] mt-0.5 line-clamp-2"
<p class="text-xs mt-0.5 line-clamp-2"
:class="isDark ? 'text-white/50' : 'text-gray-500'">
{{ app.description }}
</p>
@@ -79,7 +79,7 @@
<span
v-for="p in app.platforms"
:key="p"
class="text-[8px] px-1 py-0.5 rounded"
class="text-xs px-1 py-0.5 rounded"
:class="isDark ? 'bg-white/5 text-white/30' : 'bg-black/3 text-gray-400'"
>
{{ platformLabel(p) }}
@@ -5,7 +5,7 @@
<h3 class="text-sm font-bold text-white/90">
Node Apps
</h3>
<span class="text-[10px] font-mono text-white/30">
<span class="text-xs font-mono text-white/30">
{{ filteredApps.length }} apps
</span>
</div>
@@ -14,15 +14,14 @@
v-model="search"
type="text"
placeholder="Search node apps..."
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10"
style="font-size: 16px"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10"
/>
<div class="flex flex-wrap gap-1.5">
<button
v-for="cat in categories"
:key="cat.value"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeCategory === cat.value
? 'nav-tab-active'
: 'text-white/40 hover:text-white/70 hover:bg-white/5'"
@@ -46,7 +45,7 @@
<span class="text-lg leading-none">{{ app.icon }}</span>
<span class="text-xs font-semibold text-white/90 truncate">{{ app.name }}</span>
</div>
<p class="text-[10px] text-white/50 line-clamp-2 leading-relaxed">
<p class="text-xs text-white/50 line-clamp-2 leading-relaxed">
{{ app.description }}
</p>
<div class="mt-2 flex items-center gap-1.5">
@@ -54,7 +53,7 @@
class="w-1.5 h-1.5 rounded-full"
:class="statusDotClass(app.liveStatus)"
/>
<span class="text-[10px]" :class="statusTextClass(app.liveStatus)">
<span class="text-xs" :class="statusTextClass(app.liveStatus)">
{{ statusLabel(app.liveStatus) }}
</span>
</div>
@@ -32,7 +32,7 @@
:class="isDark ? 'text-white/50' : 'text-gray-500'">
{{ book.author }}<span v-if="book.year"> · {{ book.year }}</span>
</p>
<p v-if="book.description" class="text-[11px] mt-1 line-clamp-2 leading-relaxed"
<p v-if="book.description" class="text-xs mt-1 line-clamp-2 leading-relaxed"
:class="isDark ? 'text-white/40' : 'text-gray-400'">
{{ book.description }}
</p>
@@ -47,7 +47,7 @@
<span
v-for="genre in book.genres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md font-medium"
class="text-xs px-2 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'"
>
{{ genre }}
@@ -95,7 +95,7 @@
<div>
<p class="text-xs font-medium"
:class="isDark ? 'text-white/80' : 'text-gray-800'">{{ link.name }}</p>
<p v-if="link.desc" class="text-[10px]"
<p v-if="link.desc" class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">{{ link.desc }}</p>
</div>
</div>
@@ -9,7 +9,7 @@
{{ title }}
</h3>
<div class="flex items-center gap-2 shrink-0">
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredBooks.length }} books
</span>
<slot name="header-actions" />
@@ -20,7 +20,7 @@
v-model="search"
type="text"
placeholder="Search books..."
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10'
: 'bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5'"
@@ -30,7 +30,7 @@
<button
v-for="genre in topGenres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeGenre === genre
? 'nav-tab-active'
: isDark
@@ -69,20 +69,20 @@
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none" />
<div class="absolute bottom-0 left-0 right-0 p-2">
<p class="text-[11px] font-semibold text-white/90 leading-tight truncate">
<p class="text-xs font-semibold text-white/90 leading-tight truncate">
{{ book.title }}
</p>
<p class="text-[9px] text-white/40 truncate mt-0.5">{{ book.author }}</p>
<p class="text-xs text-white/40 truncate mt-0.5">{{ book.author }}</p>
</div>
<div v-if="book.rating" class="absolute top-1.5 left-1.5">
<span class="text-[9px] px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-medium">
<span class="text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-medium">
{{ book.rating.toFixed(1) }}
</span>
</div>
<div v-if="book.year" class="absolute top-1.5 right-1.5">
<span class="text-[8px] px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm">
<span class="text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm">
{{ book.year }}
</span>
</div>
@@ -19,7 +19,7 @@
<div class="flex-1 min-w-0 pl-8">
<div class="flex items-center gap-2">
<!-- Language badge -->
<span class="shrink-0 text-[9px] px-1.5 py-0.5 rounded font-mono"
<span class="shrink-0 text-xs px-1.5 py-0.5 rounded font-mono"
:class="isDark ? 'bg-white/10 text-white/50' : 'bg-black/5 text-gray-500'">
{{ language }}
</span>
@@ -28,7 +28,7 @@
{{ fileName }}
</p>
</div>
<p v-if="projectName" class="text-[10px] font-mono mt-0.5 truncate"
<p v-if="projectName" class="text-xs font-mono mt-0.5 truncate"
:class="isDark ? 'text-white/25' : 'text-gray-400'">
{{ projectName }} / {{ filePath }}
</p>
@@ -39,7 +39,7 @@
<button
v-for="tab in displayTabs"
:key="tab"
class="text-[10px] px-2.5 py-1.5 rounded-lg font-medium whitespace-nowrap transition-all duration-150"
class="text-xs px-2.5 py-1.5 rounded-lg font-medium whitespace-nowrap transition-all duration-150"
:class="activeTab === tab
? 'nav-tab-active'
: isDark
@@ -15,7 +15,7 @@
{{ contextLabel }}
</p>
<div class="flex items-center gap-2 shrink-0">
<p class="text-[10px] font-mono uppercase tracking-[0.2em]"
<p class="text-xs font-mono uppercase tracking-[0.2em]"
:class="isDark ? 'text-white/25' : 'text-gray-400'">
Surfacing
</p>
@@ -20,13 +20,13 @@
:class="isDark ? 'text-white/90' : 'text-gray-900'">
{{ item.name }}
</h2>
<p class="text-[10px]"
<p class="text-xs"
:class="isDark ? 'text-white/40' : 'text-gray-400'">
{{ categoryLabel }}
</p>
</div>
<button
class="text-[10px] px-2 py-1 rounded-md transition-colors"
class="text-xs px-2 py-1 rounded-md transition-colors"
:class="copied
? 'bg-emerald-500/20 text-emerald-400'
: isDark
@@ -47,7 +47,7 @@
<!-- Live preview -->
<div>
<h4 class="text-[10px] uppercase tracking-[0.2em] font-semibold mb-2"
<h4 class="text-xs uppercase tracking-[0.2em] font-semibold mb-2"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
Preview
</h4>
@@ -58,7 +58,7 @@
<div class="h-12 rounded-lg border"
:class="isDark ? 'border-white/10' : 'border-black/10'"
:style="{ background: extractColorValue(item.code) }" />
<p class="text-[10px] font-mono text-center"
<p class="text-xs font-mono text-center"
:class="isDark ? 'text-white/40' : 'text-gray-400'">
{{ extractColorValue(item.code) }}
</p>
@@ -119,11 +119,11 @@
</button>
</div>
<div v-else-if="item.id === 'atom-badge'" class="flex flex-wrap gap-1.5">
<span class="text-[10px] px-2 py-1 rounded-md font-medium"
<span class="text-xs px-2 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'">Science Fiction</span>
<span class="text-[10px] px-2 py-1 rounded-md font-medium"
<span class="text-xs px-2 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'">Drama</span>
<span class="text-[10px] px-2 py-1 rounded-md font-medium"
<span class="text-xs px-2 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'">Thriller</span>
</div>
<div v-else-if="item.id === 'mol-glass-card'">
@@ -135,17 +135,17 @@
<!-- Nav tab preview -->
<div v-else-if="item.id === 'atom-nav-tab'" class="flex gap-1.5">
<button class="text-[10px] px-2.5 py-1 rounded-md font-medium bg-accent/20 text-accent">Films</button>
<button class="text-[10px] px-2.5 py-1 rounded-md font-medium"
<button class="text-xs px-2.5 py-1 rounded-md font-medium bg-accent/20 text-accent">Films</button>
<button class="text-xs px-2.5 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/5 text-white/50' : 'bg-black/5 text-gray-500'">Songs</button>
<button class="text-[10px] px-2.5 py-1 rounded-md font-medium"
<button class="text-xs px-2.5 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/5 text-white/50' : 'bg-black/5 text-gray-500'">Podcasts</button>
</div>
<!-- Text input preview -->
<div v-else-if="item.id === 'atom-input'">
<input
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10'
: 'bg-black/5 text-gray-800 placeholder:text-gray-400 focus:bg-black/10'"
@@ -159,12 +159,12 @@
<div class="h-16 overflow-y-auto rounded-lg px-3 py-2"
:class="isDark ? 'bg-white/5' : 'bg-black/5'"
style="scrollbar-width: thin;">
<p v-for="n in 8" :key="n" class="text-[10px] py-0.5"
<p v-for="n in 8" :key="n" class="text-xs py-0.5"
:class="isDark ? 'text-white/40' : 'text-gray-400'">
Scrollable content line {{ n }}
</p>
</div>
<p class="text-[10px] text-center" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<p class="text-xs text-center" :class="isDark ? 'text-white/30' : 'text-gray-400'">
4px wide, translucent thumb
</p>
</div>
@@ -185,7 +185,7 @@
<span class="text-sm">🎬</span>
<div>
<p class="text-xs font-medium" :class="isDark ? 'text-white/80' : 'text-gray-800'">Netflix</p>
<p class="text-[10px]" :class="isDark ? 'text-white/30' : 'text-gray-400'">Stream now</p>
<p class="text-xs" :class="isDark ? 'text-white/30' : 'text-gray-400'">Stream now</p>
</div>
</div>
<svg class="w-3.5 h-3.5" :class="isDark ? 'text-white/30' : 'text-gray-400'"
@@ -203,7 +203,7 @@
<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/30 to-transparent" />
<div class="absolute bottom-0 left-0 p-3">
<h3 class="text-sm font-bold text-white/90">Banner Title</h3>
<p class="text-[10px] text-white/50">Subtitle text</p>
<p class="text-xs text-white/50">Subtitle text</p>
</div>
</div>
</div>
@@ -216,7 +216,7 @@
:style="{ background: `linear-gradient(${120 * n}deg, ${['#2d1b69','#1b3a4b','#3b1b2b'][n-1]}, ${['#1a0a3e','#0a2030','#200a1a'][n-1]})` }">
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
<div class="absolute bottom-0 left-0 right-0 p-1.5">
<p class="text-[9px] text-white/80 font-medium truncate">{{ ['Film', 'Album', 'Series'][n-1] }}</p>
<p class="text-xs text-white/80 font-medium truncate">{{ ['Film', 'Album', 'Series'][n-1] }}</p>
</div>
</div>
</div>
@@ -225,13 +225,13 @@
<!-- Chat bubble preview -->
<div v-else-if="item.id === 'org-chat-bubble'" class="space-y-2">
<div class="flex justify-end">
<div class="max-w-[80%] px-3 py-2 rounded-2xl text-[11px]"
<div class="max-w-[80%] px-3 py-2 rounded-2xl text-xs"
:class="isDark ? 'bg-white/10 text-white/90' : 'bg-black/10 text-gray-800'">
What films should I watch?
</div>
</div>
<div class="flex justify-start">
<div class="max-w-[80%] px-3 py-2 text-[11px]"
<div class="max-w-[80%] px-3 py-2 text-xs"
:class="isDark ? 'text-white/70' : 'text-gray-600'">
Here are some great picks from your library...
</div>
@@ -242,10 +242,10 @@
<div v-else-if="item.id === 'org-content-panel'" class="space-y-2">
<div class="flex gap-1 pb-1.5"
:style="isDark ? 'border-bottom: 1px solid rgba(255,255,255,0.08)' : 'border-bottom: 1px solid rgba(0,0,0,0.06)'">
<span class="text-[9px] px-2 py-0.5 rounded font-medium bg-accent/20 text-accent">Films</span>
<span class="text-[9px] px-2 py-0.5 rounded font-medium"
<span class="text-xs px-2 py-0.5 rounded font-medium bg-accent/20 text-accent">Films</span>
<span class="text-xs px-2 py-0.5 rounded font-medium"
:class="isDark ? 'text-white/40' : 'text-gray-400'">Songs</span>
<span class="text-[9px] px-2 py-0.5 rounded font-medium"
<span class="text-xs px-2 py-0.5 rounded font-medium"
:class="isDark ? 'text-white/40' : 'text-gray-400'">Books</span>
</div>
<div class="grid grid-cols-3 gap-1">
@@ -267,8 +267,8 @@
</svg>
</div>
<div class="absolute bottom-1 left-2">
<p class="text-[10px] font-bold text-white/90">Title</p>
<p class="text-[8px] text-white/50">Meta</p>
<p class="text-xs font-bold text-white/90">Title</p>
<p class="text-xs text-white/50">Meta</p>
</div>
</div>
<div class="space-y-1 px-1">
@@ -285,15 +285,15 @@
:class="isDark ? 'bg-[#0a0a0a]' : 'bg-white'">
<p class="text-[7px] uppercase tracking-[0.3em] mb-0.5"
:class="isDark ? 'text-white/30' : 'text-gray-400'">Editorial</p>
<p class="text-[11px] font-serif font-bold"
<p class="text-xs font-serif font-bold"
:class="isDark ? 'text-white/90' : 'text-gray-900'">Hero Headline</p>
</div>
<div class="px-2 py-2" :class="isDark ? 'bg-[#0a0a0a]' : 'bg-white'">
<p class="text-[9px] font-serif font-bold"
<p class="text-xs font-serif font-bold"
:class="isDark ? 'text-white/80' : 'text-gray-800'">Half Tile</p>
</div>
<div class="px-2 py-2" :class="isDark ? 'bg-[#0a0a0a]' : 'bg-white'">
<p class="text-[9px] font-serif font-bold"
<p class="text-xs font-serif font-bold"
:class="isDark ? 'text-white/80' : 'text-gray-800'">Half Tile</p>
</div>
</div>
@@ -304,22 +304,22 @@
<div class="p-3 rounded-xl"
:class="isDark ? 'bg-white/[0.03] border border-white/5' : 'bg-black/[0.02] border border-black/5'">
<div class="flex items-start gap-2.5">
<div class="w-7 h-7 rounded-full flex items-center justify-center text-[10px] font-bold shrink-0"
<div class="w-7 h-7 rounded-full flex items-center justify-center text-xs font-bold shrink-0"
style="background: rgba(168, 85, 247, 0.2); color: rgba(168, 85, 247, 0.8);">
F
</div>
<div class="min-w-0 flex-1">
<div class="flex items-center gap-1.5">
<span class="text-[11px] font-semibold" :class="isDark ? 'text-white/80' : 'text-gray-800'">fiatjaf</span>
<span class="text-[9px]" :class="isDark ? 'text-white/25' : 'text-gray-300'">2h</span>
<span class="text-xs font-semibold" :class="isDark ? 'text-white/80' : 'text-gray-800'">fiatjaf</span>
<span class="text-xs" :class="isDark ? 'text-white/25' : 'text-gray-300'">2h</span>
</div>
<p class="text-[10px] mt-0.5 leading-relaxed"
<p class="text-xs mt-0.5 leading-relaxed"
:class="isDark ? 'text-white/50' : 'text-gray-500'">
Nostr is the simplest open protocol...
</p>
<div class="flex gap-3 mt-1.5">
<span class="text-[9px]" :class="isDark ? 'text-white/25' : 'text-gray-300'">3 replies</span>
<span class="text-[9px] text-amber-500/70">21000 sats</span>
<span class="text-xs" :class="isDark ? 'text-white/25' : 'text-gray-300'">3 replies</span>
<span class="text-xs text-amber-500/70">21000 sats</span>
</div>
</div>
</div>
@@ -332,7 +332,7 @@
:class="isDark ? 'bg-white/10 text-white/70' : 'bg-black/10 text-gray-600'">
Fade Up (900ms)
</div>
<button class="text-[10px] px-2 py-0.5 rounded transition-colors"
<button class="text-xs px-2 py-0.5 rounded transition-colors"
:class="isDark ? 'text-white/40 hover:text-white/60' : 'text-gray-400 hover:text-gray-600'"
@click="fadeUpKey++">
Replay
@@ -345,7 +345,7 @@
:class="isDark ? 'bg-white/10 text-white/70' : 'bg-black/10 text-gray-600'">
Scale In (250ms)
</div>
<button class="text-[10px] px-2 py-0.5 rounded transition-colors"
<button class="text-xs px-2 py-0.5 rounded transition-colors"
:class="isDark ? 'text-white/40 hover:text-white/60' : 'text-gray-400 hover:text-gray-600'"
@click="scaleInKey++">
Replay
@@ -364,7 +364,7 @@
<!-- Used In -->
<div v-if="item.usedIn">
<h4 class="text-[10px] uppercase tracking-[0.2em] font-semibold mb-2"
<h4 class="text-xs uppercase tracking-[0.2em] font-semibold mb-2"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
Used In
</h4>
@@ -379,7 +379,7 @@
<!-- Code block -->
<div>
<h4 class="text-[10px] uppercase tracking-[0.2em] font-semibold mb-2"
<h4 class="text-xs uppercase tracking-[0.2em] font-semibold mb-2"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
Code
</h4>
@@ -8,7 +8,7 @@
:class="isDark ? 'text-white/90' : 'text-gray-900'">
Design System
</span>
<p class="text-[10px]"
<p class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredItems.length }} items
</p>
@@ -19,7 +19,7 @@
<button
v-for="cat in categories"
:key="cat.id"
class="text-[10px] px-2.5 py-1 rounded-md font-medium whitespace-nowrap transition-colors"
class="text-xs px-2.5 py-1 rounded-md font-medium whitespace-nowrap transition-colors"
:class="activeCategory === cat.id
? 'bg-accent/20 text-accent'
: isDark
@@ -95,7 +95,7 @@
:class="isDark ? 'text-white/80' : 'text-gray-800'">
{{ item.name }}
</h3>
<p class="text-[10px] leading-snug line-clamp-2"
<p class="text-xs leading-snug line-clamp-2"
:class="isDark ? 'text-white/40' : 'text-gray-400'">
{{ item.description }}
</p>
@@ -139,7 +139,7 @@ const items: DesignSystemItem[] = [
{ id: 'type-body', name: 'Body Font', category: 'typography', description: 'Inter / system-ui for all body text', code: 'font-family: Inter, system-ui, -apple-system, sans-serif;\n/* Applied globally */', usedIn: 'Global default — ChatMessage, grids, detail views' },
{ id: 'type-mono', name: 'Monospace Font', category: 'typography', description: 'Menlo / Monaco for code and IDs', code: 'font-family: Menlo, Monaco, "Courier New", monospace;\n/* Tailwind: font-mono */', usedIn: 'CodeDetail, conversation IDs, relay URLs, metadata' },
{ id: 'type-serif', name: 'Serif Font', category: 'typography', description: 'Georgia for magazine/editorial layouts', code: 'font-family: Georgia, "Times New Roman", Times, serif;\n/* Used in MagazineGrid, AI Brief */', usedIn: 'MagazineGrid, MagazineSectionDetail, AI Brief' },
{ id: 'type-sizes', name: 'Text Sizes', category: 'typography', description: 'Compact scale: 10px labels to 2xl headings', code: '/* Key sizes used */\ntext-[10px] /* labels, metadata */\ntext-xs /* 12px - secondary text */\ntext-sm /* 14px - body text */\ntext-base /* 16px - primary text */\ntext-lg /* 18px - section headings */\ntext-xl /* 20px - page headings */\ntext-2xl /* 24px - hero text */', usedIn: 'Globally — see specific usage in each size bracket' },
{ id: 'type-sizes', name: 'Text Sizes', category: 'typography', description: 'Compact scale: 10px labels to 2xl headings', code: '/* Key sizes used */\ntext-xs /* labels, metadata */\ntext-xs /* 12px - secondary text */\ntext-sm /* 14px - body text */\ntext-base /* 16px - primary text */\ntext-lg /* 18px - section headings */\ntext-xl /* 20px - page headings */\ntext-2xl /* 24px - hero text */', usedIn: 'Globally — see specific usage in each size bracket' },
// Spacing
{ id: 'space-grid', name: '4px Grid', category: 'spacing', preview: 'inline', description: 'All spacing follows a 4px base grid', code: '/* 4px grid system */\n1 = 4px /* micro gap */\n2 = 8px /* tight gap */\n3 = 12px /* small padding */\n4 = 16px /* standard padding */\n5 = 20px /* section padding */\n6 = 24px /* large gap */\n8 = 32px /* section spacing */\n12 = 48px /* large sections */', usedIn: 'Every layout — padding, margins, gaps between elements' },
@@ -149,7 +149,7 @@ const items: DesignSystemItem[] = [
{ id: 'atom-glass-btn', name: 'Glass Button', category: 'atoms', description: '48px height, glass morphism background', code: '<button class="glass-button">\n Action\n</button>\n\n/* glass-button:\n height: 48px\n background: rgba(0,0,0,0.6)\n backdrop-filter: blur(18px)\n border-radius: 12px\n border: 1px solid rgba(255,255,255,0.12)\n*/', usedIn: 'ChatInput send, modal actions, primary controls' },
{ id: 'atom-glass-btn-sm', name: 'Glass Button Small', category: 'atoms', description: 'Compact glass button variant', code: '<button class="glass-button-sm">\n Small\n</button>\n\n/* Compact variant of glass-button */', usedIn: 'ChatInput send/stop buttons, inline actions' },
{ id: 'atom-icon-btn', name: 'Icon Button', category: 'atoms', description: 'Path glass icon, 32-36px square', code: '<button class="w-9 h-9 rounded-xl path-glass-icon\n flex items-center justify-center">\n <svg class="w-4 h-4" ...>\n</button>\n\n/* path-glass-icon:\n background: transparent\n transition: colors\n hover: bg-white/10\n*/', usedIn: 'ChatHeader toolbar, detail back buttons, close buttons' },
{ id: 'atom-badge', name: 'Genre Badge', category: 'atoms', description: 'Tiny pill badge for tags/genres', code: '<span class="text-[10px] px-2 py-1 rounded-md\n font-medium bg-white/10 text-white/60">\n Science Fiction\n</span>', usedIn: 'FilmGrid, SongGrid, BookGrid, TVSeriesGrid genre filters' },
{ id: 'atom-badge', name: 'Genre Badge', category: 'atoms', description: 'Tiny pill badge for tags/genres', code: '<span class="text-xs px-2 py-1 rounded-md\n font-medium bg-white/10 text-white/60">\n Science Fiction\n</span>', usedIn: 'FilmGrid, SongGrid, BookGrid, TVSeriesGrid genre filters' },
{ id: 'atom-nav-tab', name: 'Nav Tab', category: 'atoms', description: 'Content panel tab with active state', code: '<button class="nav-tab-active">\n Films\n</button>\n\n/* Active: accent underline\n Inactive: text-white/50 hover:text-white\n Transition: 200ms */', usedIn: 'ContentPanel tab bar, mobile content tab filters' },
{ id: 'atom-input', name: 'Text Input', category: 'atoms', description: 'Search/filter input field', code: '<input\n class="w-full px-3 py-2 rounded-lg text-xs\n outline-none transition-colors\n bg-white/5 text-white/80\n placeholder:text-white/25\n focus:bg-white/10"\n placeholder="Search..."\n/>', usedIn: 'All grid search bars, ProjectGrid new project' },
{ id: 'atom-scrollbar', name: 'Custom Scrollbar', category: 'atoms', description: 'Thin translucent scrollbar for scroll areas', code: '.custom-scrollbar::-webkit-scrollbar {\n width: 4px;\n}\n.custom-scrollbar::-webkit-scrollbar-thumb {\n background: rgba(255,255,255, 0.1);\n border-radius: 2px;\n}\n/* Also: .scrollbar-hide hides completely */', usedIn: 'Content grids, chat message list, file trees' },
@@ -157,16 +157,16 @@ const items: DesignSystemItem[] = [
// Molecules
{ id: 'mol-glass-card', name: 'Glass Card', category: 'molecules', description: 'Frosted glass card with border', code: '<div class="glass-card">\n <h3>Title</h3>\n <p>Content</p>\n</div>\n\n/* glass-card:\n background: rgba(0,0,0,0.65)\n backdrop-filter: blur(18px)\n border: 1px solid rgba(255,255,255,0.12)\n border-radius: 16px\n padding: 16px\n*/', usedIn: 'ChatWindow container, content panel wrapper' },
{ id: 'mol-gradient-card', name: 'Gradient Card', category: 'molecules', description: 'Card with gradient background', code: '<div class="gradient-card">\n <h3>Featured</h3>\n <p>Content</p>\n</div>\n\n/* gradient-card:\n background: linear-gradient(135deg, ...)\n border-radius: 16px\n*/', usedIn: 'Featured content highlights, promotional sections' },
{ id: 'mol-source-link', name: 'Source Link Row', category: 'molecules', description: 'Icon + label + external link arrow', code: '<a class="flex items-center justify-between\n p-3 rounded-xl bg-white/5\n hover:bg-white/10 transition-colors">\n <div class="flex items-center gap-2.5">\n <span class="text-sm">icon</span>\n <div>\n <p class="text-xs font-medium\n text-white/80">Name</p>\n <p class="text-[10px]\n text-white/30">Description</p>\n </div>\n </div>\n <svg><!-- external link icon --></svg>\n</a>', usedIn: 'FilmDetail, SongDetail, PodcastDetail sources' },
{ id: 'mol-source-link', name: 'Source Link Row', category: 'molecules', description: 'Icon + label + external link arrow', code: '<a class="flex items-center justify-between\n p-3 rounded-xl bg-white/5\n hover:bg-white/10 transition-colors">\n <div class="flex items-center gap-2.5">\n <span class="text-sm">icon</span>\n <div>\n <p class="text-xs font-medium\n text-white/80">Name</p>\n <p class="text-xs\n text-white/30">Description</p>\n </div>\n </div>\n <svg><!-- external link icon --></svg>\n</a>', usedIn: 'FilmDetail, SongDetail, PodcastDetail sources' },
{ id: 'mol-banner-hero', name: 'Banner Hero', category: 'molecules', description: 'Aspect 16/7 image with gradient overlay', code: '<div class="relative w-full aspect-[16/7]\n overflow-hidden">\n <img :src="url" class="absolute inset-0\n w-full h-full object-cover" />\n <div class="absolute inset-0\n bg-gradient-to-t from-black/80\n via-black/30 to-transparent" />\n <div class="absolute bottom-0 p-4">\n <h2 class="text-lg font-bold\n text-white">Title</h2>\n </div>\n</div>', usedIn: 'FilmDetail, TVSeriesDetail, BookDetail banners' },
{ id: 'mol-cover-card', name: 'Cover Card', category: 'molecules', description: 'Poster/cover image card with overlay text', code: '<button class="group rounded-2xl overflow-hidden">\n <div class="aspect-[2/3] relative">\n <img class="w-full h-full object-cover\n group-hover:scale-110\n transition-transform duration-300" />\n <div class="absolute inset-0\n bg-gradient-to-t from-black/60\n to-transparent" />\n <div class="absolute bottom-0 p-2">\n <p class="text-[11px] text-white/90">\n Title</p>\n </div>\n </div>\n</button>', usedIn: 'FilmGrid, TVSeriesGrid, SongGrid, BookGrid cards' },
{ id: 'mol-cover-card', name: 'Cover Card', category: 'molecules', description: 'Poster/cover image card with overlay text', code: '<button class="group rounded-2xl overflow-hidden">\n <div class="aspect-[2/3] relative">\n <img class="w-full h-full object-cover\n group-hover:scale-110\n transition-transform duration-300" />\n <div class="absolute inset-0\n bg-gradient-to-t from-black/60\n to-transparent" />\n <div class="absolute bottom-0 p-2">\n <p class="text-xs text-white/90">\n Title</p>\n </div>\n </div>\n</button>', usedIn: 'FilmGrid, TVSeriesGrid, SongGrid, BookGrid cards' },
// Organisms
{ id: 'org-chat-bubble', name: 'Chat Bubble', category: 'organisms', description: 'AI/User message bubble with streaming', code: '<!-- User bubble -->\n<div class="flex justify-end">\n <div class="glass-card max-w-[85%]\n px-4 py-3 text-sm text-white/90">\n Message text\n </div>\n</div>\n\n<!-- AI bubble -->\n<div class="flex justify-start">\n <div class="max-w-[85%] px-4 py-3\n text-sm text-white/80">\n Response with markdown\n </div>\n</div>', usedIn: 'ChatMessage.vue — the primary chat interface' },
{ id: 'org-content-panel', name: 'Content Panel', category: 'organisms', description: 'Tabs + grid + detail navigation', code: '<!-- Structure -->\n<div class="flex flex-col h-full">\n <!-- Tab bar -->\n <div class="flex gap-1 px-3 py-2">\n <button class="nav-tab">Tab</button>\n </div>\n <!-- Grid view -->\n <ContentGridView />\n <!-- or Detail view -->\n <DetailView />\n</div>', usedIn: 'ChatPage middle column, mobile Content tab' },
{ id: 'org-detail-view', name: 'Detail View', category: 'organisms', description: 'Full detail with banner, back button, metadata', code: '<!-- Pattern: Banner → Meta → Content -->\n<div class="h-full overflow-y-auto">\n <!-- Banner with back button -->\n <div class="relative aspect-[16/7]">\n <img class="object-cover" />\n <div class="gradient-overlay" />\n <button class="absolute top-3 left-3\n path-glass-icon">Back</button>\n <div class="absolute bottom-0 p-4">\n <h2>Title</h2>\n <div>Metadata</div>\n </div>\n </div>\n <!-- Body -->\n <div class="p-4 space-y-4">\n <p>Description</p>\n <div>Genre badges</div>\n <div>Source links</div>\n </div>\n</div>', usedIn: 'FilmDetail, BookDetail, TVSeriesDetail, SongDetail, PodcastDetail' },
{ id: 'org-magazine', name: 'Magazine Grid', category: 'organisms', description: 'Editorial tile layout with hero, wide, and half tiles', code: '<!-- Magazine structure -->\n<div class="grid grid-cols-2 gap-px\n bg-white/12">\n <!-- Wide tile (col-span-2) -->\n <button class="col-span-2 px-5 py-5\n bg-[#0a0a0a]">\n <p class="text-[9px] uppercase\n tracking-[0.3em]">Label</p>\n <h2 class="font-serif text-lg\n font-bold">Title</h2>\n <p class="font-serif text-sm">Text</p>\n </button>\n <!-- Half tiles -->\n <button class="px-4 py-4 bg-[#0a0a0a]">\n <h3 class="font-serif text-sm\n font-bold">Title</h3>\n <p class="font-serif text-xs">Text</p>\n </button>\n</div>', usedIn: 'MagazineGrid.vue — AI Brief editorial view' },
{ id: 'org-nostr-note', name: 'Nostr Note', category: 'organisms', description: 'Note card with avatar, author, content, zaps', code: '<div class="p-3 rounded-xl bg-white/[0.03]\n border border-white/5">\n <div class="flex items-start gap-2.5">\n <div class="w-8 h-8 rounded-full\n bg-purple-500/20 text-purple-400">\n F\n </div>\n <div class="flex-1">\n <span class="text-xs font-semibold">\n author</span>\n <p class="text-[11px] text-white/60">\n Note content...</p>\n <span class="text-[9px]\n text-amber-500/70">21000 sats</span>\n </div>\n </div>\n</div>', usedIn: 'NostrGrid.vue — Nostr feed tab' },
{ id: 'org-magazine', name: 'Magazine Grid', category: 'organisms', description: 'Editorial tile layout with hero, wide, and half tiles', code: '<!-- Magazine structure -->\n<div class="grid grid-cols-2 gap-px\n bg-white/12">\n <!-- Wide tile (col-span-2) -->\n <button class="col-span-2 px-5 py-5\n bg-[#0a0a0a]">\n <p class="text-xs uppercase\n tracking-[0.3em]">Label</p>\n <h2 class="font-serif text-lg\n font-bold">Title</h2>\n <p class="font-serif text-sm">Text</p>\n </button>\n <!-- Half tiles -->\n <button class="px-4 py-4 bg-[#0a0a0a]">\n <h3 class="font-serif text-sm\n font-bold">Title</h3>\n <p class="font-serif text-xs">Text</p>\n </button>\n</div>', usedIn: 'MagazineGrid.vue — AI Brief editorial view' },
{ id: 'org-nostr-note', name: 'Nostr Note', category: 'organisms', description: 'Note card with avatar, author, content, zaps', code: '<div class="p-3 rounded-xl bg-white/[0.03]\n border border-white/5">\n <div class="flex items-start gap-2.5">\n <div class="w-8 h-8 rounded-full\n bg-purple-500/20 text-purple-400">\n F\n </div>\n <div class="flex-1">\n <span class="text-xs font-semibold">\n author</span>\n <p class="text-xs text-white/60">\n Note content...</p>\n <span class="text-xs\n text-amber-500/70">21000 sats</span>\n </div>\n </div>\n</div>', usedIn: 'NostrGrid.vue — Nostr feed tab' },
// Animations
{ id: 'anim-fade-up', name: 'Fade Up', category: 'atoms', description: 'Entry animation: translate + opacity', code: '.animate-fade-up {\n animation: fadeUp 900ms ease-out;\n}\n@keyframes fadeUp {\n from {\n opacity: 0;\n transform: translateY(16px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n/* Also: animate-fade-up-fast (400ms) */', usedIn: 'Empty states, initial load elements, ChatWindow' },
@@ -8,7 +8,7 @@
<button
v-for="tab in subTabs"
:key="tab.id"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeSubTab === tab.id
? 'nav-tab-active'
: 'text-white/40 hover:text-white/70 hover:bg-white/5'"
@@ -34,24 +34,24 @@
:key="item.id"
class="flex items-center gap-3 p-3 rounded-xl bg-white/[0.03] hover:bg-white/[0.07] border border-white/5 transition-all duration-150 cursor-pointer"
>
<span class="text-[10px] w-6 h-6 rounded flex items-center justify-center shrink-0" :class="typeStyle(item.type)">
<span class="text-xs w-6 h-6 rounded flex items-center justify-center shrink-0" :class="typeStyle(item.type)">
{{ typeIcon(item.type) }}
</span>
<div class="flex-1 min-w-0">
<div class="text-xs font-semibold truncate text-white/80">{{ item.title }}</div>
<div v-if="item.subtitle" class="text-[10px] truncate text-white/40">{{ item.subtitle }}</div>
<div v-if="item.subtitle" class="text-xs truncate text-white/40">{{ item.subtitle }}</div>
</div>
<span class="text-[8px] text-white/20 shrink-0">{{ item.type }}</span>
<span class="text-xs text-white/20 shrink-0">{{ item.type }}</span>
</div>
</template>
<!-- Recent -->
<template v-else-if="activeSubTab === 'recent'">
<div class="flex items-center justify-between mb-2">
<span class="text-[10px] text-white/30">{{ viewHistory.length }} items</span>
<span class="text-xs text-white/30">{{ viewHistory.length }} items</span>
<button
v-if="viewHistory.length > 0"
class="text-[9px] text-red-400/50 hover:text-red-400/80 transition-colors"
class="text-xs text-red-400/50 hover:text-red-400/80 transition-colors"
@click="clearHistory"
>
Clear
@@ -70,14 +70,14 @@
:key="entry.id + entry.viewedAt"
class="flex items-center gap-3 p-3 rounded-xl bg-white/[0.03] hover:bg-white/[0.07] border border-white/5 transition-all duration-150 cursor-pointer"
>
<span class="text-[10px] w-6 h-6 rounded flex items-center justify-center shrink-0" :class="typeStyle(entry.type)">
<span class="text-xs w-6 h-6 rounded flex items-center justify-center shrink-0" :class="typeStyle(entry.type)">
{{ typeIcon(entry.type) }}
</span>
<div class="flex-1 min-w-0">
<div class="text-xs font-semibold truncate text-white/80">{{ entry.title }}</div>
<div v-if="entry.subtitle" class="text-[10px] truncate text-white/40">{{ entry.subtitle }}</div>
<div v-if="entry.subtitle" class="text-xs truncate text-white/40">{{ entry.subtitle }}</div>
</div>
<span class="text-[8px] text-white/20 shrink-0">{{ timeAgo(entry.viewedAt) }}</span>
<span class="text-xs text-white/20 shrink-0">{{ timeAgo(entry.viewedAt) }}</span>
</div>
</template>
@@ -95,13 +95,13 @@
:key="item.id"
class="flex items-center gap-3 p-3 rounded-xl bg-white/[0.03] hover:bg-white/[0.07] border border-white/5 transition-all duration-150"
>
<span class="text-[10px] w-6 h-6 rounded flex items-center justify-center shrink-0" :class="typeStyle(item.type)">
<span class="text-xs w-6 h-6 rounded flex items-center justify-center shrink-0" :class="typeStyle(item.type)">
{{ typeIcon(item.type) }}
</span>
<div class="flex-1 min-w-0">
<div class="text-xs font-semibold truncate text-white/80">{{ item.title }}</div>
</div>
<span class="text-[9px] px-1.5 py-0.5 rounded bg-accent/15 text-accent/80 shrink-0">
<span class="text-xs px-1.5 py-0.5 rounded bg-accent/15 text-accent/80 shrink-0">
{{ item.count }}x
</span>
</div>
@@ -115,11 +115,11 @@
v-model="newCollectionName"
type="text"
placeholder="New collection name..."
class="flex-1 px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
class="flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
@keydown.enter="createNewCollection"
/>
<button
class="px-2.5 py-2 rounded-lg text-[10px] bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
class="px-2.5 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
:disabled="!newCollectionName.trim()"
@click="createNewCollection"
>
@@ -142,12 +142,12 @@
<div class="flex items-center justify-between">
<div class="flex-1 min-w-0">
<p class="text-xs font-semibold text-white/80 truncate">{{ col.name }}</p>
<p v-if="col.description" class="text-[9px] text-white/30 truncate">{{ col.description }}</p>
<p v-if="col.description" class="text-xs text-white/30 truncate">{{ col.description }}</p>
</div>
<div class="flex items-center gap-1 shrink-0">
<span class="text-[9px] text-white/25">{{ col.items.length }} items</span>
<span class="text-xs text-white/25">{{ col.items.length }} items</span>
<button
class="text-[9px] px-1.5 py-0.5 rounded text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors"
class="text-xs px-1.5 py-0.5 rounded text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors"
@click="deleteCollection(col.id)"
>
Delete
@@ -162,16 +162,16 @@
:key="item.id"
class="aspect-square rounded bg-white/5 flex items-center justify-center"
>
<span class="text-[8px] font-bold" :class="typeStyle(item.type)">{{ typeIcon(item.type) }}</span>
<span class="text-xs font-bold" :class="typeStyle(item.type)">{{ typeIcon(item.type) }}</span>
</div>
</div>
<!-- Items list -->
<div v-for="item in col.items" :key="item.id" class="flex items-center gap-2 text-[10px]">
<div v-for="item in col.items" :key="item.id" class="flex items-center gap-2 text-xs">
<span :class="typeStyle(item.type)" class="w-4 h-4 rounded flex items-center justify-center text-[7px] shrink-0">{{ typeIcon(item.type) }}</span>
<span class="text-white/60 truncate flex-1">{{ item.title }}</span>
<button
class="text-red-400/40 hover:text-red-400/70 transition-colors text-[8px] shrink-0"
class="text-red-400/40 hover:text-red-400/70 transition-colors text-xs shrink-0"
@click="removeFromCollection(col.id, item.id)"
>
x
@@ -187,7 +187,7 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
</svg>
<p class="text-xs text-white/30">No tags yet</p>
<p class="text-[10px] text-white/20">Tag items from content cards to organize them</p>
<p class="text-xs text-white/20">Tag items from content cards to organize them</p>
</div>
<!-- Tag cloud -->
@@ -195,7 +195,7 @@
<button
v-for="tc in tagCloud"
:key="tc.tag"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeTagFilter === tc.tag
? 'nav-tab-active'
: 'text-white/40 hover:text-white/70 bg-white/5 hover:bg-white/10'"
@@ -207,15 +207,15 @@
<!-- Filtered items by tag -->
<div v-if="activeTagFilter" class="space-y-2">
<p class="text-[10px] text-white/30">Items tagged "{{ activeTagFilter }}"</p>
<p class="text-xs text-white/30">Items tagged "{{ activeTagFilter }}"</p>
<div
v-for="itemId in getItemsByTag(activeTagFilter)"
:key="itemId"
class="flex items-center gap-2 p-2.5 rounded-xl bg-white/[0.03] border border-white/5"
>
<span class="text-[10px] text-white/60 font-mono truncate">{{ itemId }}</span>
<span class="text-xs text-white/60 font-mono truncate">{{ itemId }}</span>
<button
class="text-[8px] text-red-400/50 hover:text-red-400/80 transition-colors shrink-0"
class="text-xs text-red-400/50 hover:text-red-400/80 transition-colors shrink-0"
@click="removeTag(itemId, activeTagFilter!)"
>
untag
@@ -236,45 +236,45 @@
<template v-else>
<!-- Recently played songs -->
<div v-if="recentSongs.length > 0" class="mb-4">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold mb-2">Recently Played</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold mb-2">Recently Played</p>
<div
v-for="entry in recentSongs.slice(0, 10)"
:key="entry.id"
class="flex items-center gap-2 p-2 rounded-lg bg-white/[0.03] hover:bg-white/[0.07] border border-white/5 mb-1 transition-colors"
>
<span class="text-[10px] w-5 h-5 rounded flex items-center justify-center shrink-0 bg-green-500/20 text-green-400">S</span>
<span class="text-xs w-5 h-5 rounded flex items-center justify-center shrink-0 bg-green-500/20 text-green-400">S</span>
<div class="flex-1 min-w-0">
<p class="text-[11px] text-white/70 truncate">{{ entry.title }}</p>
<p v-if="entry.subtitle" class="text-[9px] text-white/30 truncate">{{ entry.subtitle }}</p>
<p class="text-xs text-white/70 truncate">{{ entry.title }}</p>
<p v-if="entry.subtitle" class="text-xs text-white/30 truncate">{{ entry.subtitle }}</p>
</div>
<span class="text-[8px] text-white/20 shrink-0">{{ timeAgo(entry.viewedAt) }}</span>
<span class="text-xs text-white/20 shrink-0">{{ timeAgo(entry.viewedAt) }}</span>
</div>
</div>
<!-- Most played songs -->
<div v-if="mostPlayedSongs.length > 0" class="mb-4">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold mb-2">Most Played</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold mb-2">Most Played</p>
<div
v-for="item in mostPlayedSongs.slice(0, 10)"
:key="item.id"
class="flex items-center gap-2 p-2 rounded-lg bg-white/[0.03] hover:bg-white/[0.07] border border-white/5 mb-1 transition-colors"
>
<span class="text-[10px] w-5 h-5 rounded flex items-center justify-center shrink-0 bg-green-500/20 text-green-400">S</span>
<span class="text-xs w-5 h-5 rounded flex items-center justify-center shrink-0 bg-green-500/20 text-green-400">S</span>
<div class="flex-1 min-w-0">
<p class="text-[11px] text-white/70 truncate">{{ item.title }}</p>
<p class="text-xs text-white/70 truncate">{{ item.title }}</p>
</div>
<span class="text-[9px] px-1.5 py-0.5 rounded bg-green-400/15 text-green-400/80 shrink-0">{{ item.count }}x</span>
<span class="text-xs px-1.5 py-0.5 rounded bg-green-400/15 text-green-400/80 shrink-0">{{ item.count }}x</span>
</div>
</div>
<!-- By genre -->
<div v-if="songsByGenre.length > 0" class="mb-4">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold mb-2">By Genre</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold mb-2">By Genre</p>
<div class="flex flex-wrap gap-1.5">
<button
v-for="genre in songsByGenre"
:key="genre.genre"
class="text-[10px] px-2 py-1 rounded-md bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
class="text-xs px-2 py-1 rounded-md bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
>
{{ genre.genre }} <span class="text-white/20">{{ genre.count }}</span>
</button>
@@ -283,12 +283,12 @@
<!-- By decade -->
<div v-if="songsByDecade.length > 0">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold mb-2">By Decade</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold mb-2">By Decade</p>
<div class="flex flex-wrap gap-1.5">
<button
v-for="dec in songsByDecade"
:key="dec.decade"
class="text-[10px] px-2 py-1 rounded-md bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
class="text-xs px-2 py-1 rounded-md bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
>
{{ dec.decade }}s <span class="text-white/20">{{ dec.count }}</span>
</button>
@@ -8,7 +8,7 @@
<h3 class="text-sm font-bold" :class="isDark ? 'text-white/90' : 'text-gray-900'">
Favorites
</h3>
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredItems.length }} saved
</span>
</div>
@@ -17,7 +17,7 @@
<button
v-for="filter in typeFilters"
:key="filter.id"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeType === filter.id
? 'nav-tab-active'
: isDark
@@ -63,7 +63,7 @@
: 'bg-black/[0.02] hover:bg-black/[0.05] border border-black/5'"
>
<span
class="text-[10px] w-6 h-6 rounded flex items-center justify-center shrink-0"
class="text-xs w-6 h-6 rounded flex items-center justify-center shrink-0"
:class="typeStyle(item.type)"
>
{{ typeIcon(item.type) }}
@@ -77,7 +77,7 @@
</div>
<div
v-if="item.subtitle"
class="text-[10px] truncate"
class="text-xs truncate"
:class="isDark ? 'text-white/40' : 'text-gray-500'"
>
{{ item.subtitle }}
@@ -25,30 +25,30 @@
<div class="min-w-0 flex-1 py-0.5">
<p class="text-sm font-semibold truncate"
:class="isDark ? 'text-white/90' : 'text-gray-900'">{{ film.title }}</p>
<p class="text-[11px] mt-0.5"
<p class="text-xs mt-0.5"
:class="isDark ? 'text-white/40' : 'text-gray-500'">
{{ film.year }}<template v-if="film.director"> · {{ film.director }}</template>
</p>
<p v-if="isExternal && film.synopsis"
class="text-[10px] mt-0.5 line-clamp-2"
class="text-xs mt-0.5 line-clamp-2"
:class="isDark ? 'text-white/35' : 'text-gray-400'">
{{ film.synopsis }}
</p>
<div class="flex items-center gap-1.5 mt-1.5">
<span v-if="film.rating > 0"
class="text-[10px] font-semibold px-1.5 py-0.5 rounded"
class="text-xs font-semibold px-1.5 py-0.5 rounded"
:class="ratingClass">
{{ film.rating }}
</span>
<span v-if="isExternal"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-info/15 text-info/70' : 'bg-info/10 text-blue-600'">
not in library
</span>
<span
v-for="src in film.sources.slice(0, 3)"
:key="src.type"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-white/8 text-white/50' : 'bg-black/5 text-gray-500'"
>
{{ src.type }}
@@ -40,7 +40,7 @@
<span
v-for="genre in film.genres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md font-medium"
class="text-xs px-2 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'"
>
{{ genre }}
@@ -49,7 +49,7 @@
<div v-if="film.synopsis">
<h4 v-if="isExternal"
class="text-[10px] uppercase tracking-[0.2em] font-semibold mb-1.5"
class="text-xs uppercase tracking-[0.2em] font-semibold mb-1.5"
:class="isDark ? 'text-white/50' : 'text-gray-500'">
Why watch
</h4>
@@ -87,7 +87,7 @@
<div>
<p class="text-xs font-medium"
:class="isDark ? 'text-white/80' : 'text-gray-800'">{{ src.name }}</p>
<p class="text-[10px]"
<p class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">{{ src.quality }}</p>
</div>
</div>
@@ -9,7 +9,7 @@
{{ title }}
</h3>
<div class="flex items-center gap-2 shrink-0">
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredFilms.length }} films
</span>
<slot name="header-actions" />
@@ -20,7 +20,7 @@
v-model="search"
type="text"
placeholder="Search films..."
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10'
: 'bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5'"
@@ -30,7 +30,7 @@
<button
v-for="genre in topGenres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeGenre === genre
? 'nav-tab-active'
: isDark
@@ -69,12 +69,12 @@
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none" />
<div class="absolute bottom-0 left-0 right-0 p-2">
<p class="text-[11px] font-semibold text-white/90 leading-tight truncate">
<p class="text-xs font-semibold text-white/90 leading-tight truncate">
{{ film.title }}
</p>
<div class="flex items-center gap-1 mt-0.5">
<span class="text-[9px] text-accent font-bold"> {{ film.rating }}</span>
<span class="text-[9px] text-white/40">{{ film.year }}</span>
<span class="text-xs text-accent font-bold"> {{ film.rating }}</span>
<span class="text-xs text-white/40">{{ film.year }}</span>
</div>
</div>
@@ -82,7 +82,7 @@
<span
v-for="src in film.sources.slice(0, 2)"
:key="src.type"
class="text-[8px] px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"
class="text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"
>
{{ src.type }}
</span>
@@ -36,7 +36,7 @@
:class="isDark ? 'text-white/50' : 'text-gray-500'">
{{ image.source }}
</p>
<p v-if="image.description" class="text-[11px] mt-1 line-clamp-2 leading-relaxed"
<p v-if="image.description" class="text-xs mt-1 line-clamp-2 leading-relaxed"
:class="isDark ? 'text-white/40' : 'text-gray-400'">
{{ image.description }}
</p>
@@ -49,7 +49,7 @@
Source: {{ image.source }}
</div>
<div v-if="image.width && image.height" class="text-[10px]"
<div v-if="image.width && image.height" class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ image.width }} &times; {{ image.height }}
</div>
@@ -9,7 +9,7 @@
{{ title }}
</h3>
<div class="flex items-center gap-2 shrink-0">
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ images.length }} images
</span>
<slot name="header-actions" />
@@ -45,8 +45,8 @@
</div>
<div v-if="img.title || img.source"
class="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/70 via-black/30 to-transparent">
<p v-if="img.title" class="text-[10px] font-medium text-white/90 truncate">{{ img.title }}</p>
<p v-if="img.source" class="text-[8px] text-white/50 truncate">{{ img.source }}</p>
<p v-if="img.title" class="text-xs font-medium text-white/90 truncate">{{ img.title }}</p>
<p v-if="img.source" class="text-xs text-white/50 truncate">{{ img.source }}</p>
</div>
</button>
</div>
@@ -37,7 +37,7 @@
<!-- Content -->
<div class="relative z-10 flex flex-col justify-end h-full px-5 pb-5 pt-12"
style="min-height: 180px;">
<p class="text-[9px] uppercase tracking-[0.3em] font-medium mb-2"
<p class="text-xs uppercase tracking-[0.3em] font-medium mb-2"
:class="isDark ? 'text-white/40' : 'text-black/40'">
In response to
</p>
@@ -68,7 +68,7 @@
<path v-else stroke-linecap="round" stroke-linejoin="round"
d="M4 6h16M4 12h16M4 18h7" />
</svg>
<p class="text-[9px] uppercase tracking-[0.3em] font-semibold text-center"
<p class="text-xs uppercase tracking-[0.3em] font-semibold text-center"
:class="isDark ? 'text-white/30' : 'text-black/30'">
{{ tile.label }}
</p>
@@ -82,7 +82,7 @@
: 'bg-[#faf9f6] hover:bg-black/[0.02]'"
@click="tile.section && openTile(tile.section)">
<p v-if="tile.label"
class="text-[9px] uppercase tracking-[0.3em] font-semibold mb-2"
class="text-xs uppercase tracking-[0.3em] font-semibold mb-2"
:class="isDark ? 'text-white/30' : 'text-black/35'">
{{ tile.label }}
</p>
@@ -91,7 +91,7 @@
{{ tile.title }}
</h2>
<p v-if="tile.author"
class="text-[10px] mb-2"
class="text-xs mb-2"
:class="isDark ? 'text-white/40' : 'text-black/40'">
By {{ tile.author }}
</p>
@@ -114,7 +114,7 @@
]"
@click="tile.section && openTile(tile.section)">
<p v-if="tile.label"
class="text-[8px] uppercase tracking-[0.25em] font-semibold mb-1.5"
class="text-xs uppercase tracking-[0.25em] font-semibold mb-1.5"
:class="isDark ? 'text-white/25' : 'text-black/30'">
{{ tile.label }}
</p>
@@ -17,12 +17,12 @@
</svg>
</button>
<div class="flex-1 text-center pl-8">
<span class="text-[9px] uppercase tracking-[0.3em] font-semibold"
<span class="text-xs uppercase tracking-[0.3em] font-semibold"
:class="isDark ? 'text-white/30' : 'text-black/30'">
AI Brief
</span>
</div>
<span class="text-[10px] font-mono tabular-nums shrink-0"
<span class="text-xs font-mono tabular-nums shrink-0"
:class="isDark ? 'text-white/25' : 'text-black/25'">
{{ currentIndex + 1 }}/{{ totalSections }}
</span>
@@ -33,7 +33,7 @@
<div class="px-6 py-8 md:px-8 md:py-10 max-w-lg mx-auto my-auto">
<!-- Group label -->
<p v-if="section.group"
class="text-[9px] uppercase tracking-[0.3em] font-semibold mb-4"
class="text-xs uppercase tracking-[0.3em] font-semibold mb-4"
:class="isDark ? 'text-white/25' : 'text-black/30'">
{{ section.group }}
</p>
@@ -30,11 +30,11 @@
<p class="text-sm font-semibold truncate"
:class="isDark ? 'text-white/90' : 'text-gray-900'">{{ article.title }}</p>
<p v-if="article.content"
class="text-[11px] mt-0.5 line-clamp-2"
class="text-xs mt-0.5 line-clamp-2"
:class="isDark ? 'text-white/40' : 'text-gray-500'">
{{ article.content }}
</p>
<p class="text-[10px] mt-1 truncate"
<p class="text-xs mt-1 truncate"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ formatDomain(article.url) }}
</p>
@@ -9,7 +9,7 @@
{{ title }}
</h3>
<div class="flex items-center gap-2 shrink-0">
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredArticles.length }} {{ variant === 'websites' ? 'websites' : 'articles' }}
</span>
<slot name="header-actions" />
@@ -20,7 +20,7 @@
v-model="search"
type="text"
:placeholder="variant === 'websites' ? 'Search websites...' : 'Search articles...'"
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10'
: 'bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5'"
@@ -89,16 +89,16 @@
isDark ? 'bg-black shadow-[inset_0_1px_0_rgba(255,255,255,0.12)]' : 'bg-white shadow-[inset_0_1px_0_rgba(0,0,0,0.06)]'
]"
>
<p class="text-[11px] font-semibold leading-tight line-clamp-2"
<p class="text-xs font-semibold leading-tight line-clamp-2"
:class="isDark ? 'text-white/95' : 'text-gray-900'">
{{ article.title }}
</p>
<p v-if="article.content"
class="text-[9px] line-clamp-1 mt-0.5"
class="text-xs line-clamp-1 mt-0.5"
:class="isDark ? 'text-white/70' : 'text-gray-600'">
{{ article.content }}
</p>
<p class="text-[8px] truncate mt-0.5"
<p class="text-xs truncate mt-0.5"
:class="isDark ? 'text-white/50' : 'text-gray-500'">
{{ formatDomain(article.url) }}
</p>
@@ -25,7 +25,7 @@
<template v-else>
<div class="p-4 border-b border-white/[0.08]">
<h3 class="text-sm font-bold text-white/90 mb-2">Long-Form Articles</h3>
<p class="text-[10px] text-white/30">NIP-23 kind:30023 articles from your network</p>
<p class="text-xs text-white/30">NIP-23 kind:30023 articles from your network</p>
</div>
<div class="flex-1 overflow-y-auto custom-scrollbar px-4 pt-3 pb-16 space-y-2">
@@ -43,13 +43,13 @@
<h4 class="text-xs font-semibold text-white/80 line-clamp-2">
{{ getArticleTitle(article) }}
</h4>
<p class="text-[10px] text-white/40 line-clamp-2">
<p class="text-xs text-white/40 line-clamp-2">
{{ getArticleSummary(article) }}
</p>
<div class="flex items-center gap-2">
<span class="text-[9px] text-white/25 font-mono">{{ truncate(article.pubkey) }}</span>
<span class="text-[9px] text-white/20">{{ formatDate(article.created_at) }}</span>
<span v-if="getArticleImage(article)" class="text-[9px] text-accent/40 ml-auto">has image</span>
<span class="text-xs text-white/25 font-mono">{{ truncate(article.pubkey) }}</span>
<span class="text-xs text-white/20">{{ formatDate(article.created_at) }}</span>
<span v-if="getArticleImage(article)" class="text-xs text-accent/40 ml-auto">has image</span>
</div>
</div>
</button>
@@ -13,7 +13,7 @@
</button>
<div class="flex-1 min-w-0">
<p class="text-xs font-semibold text-white/80 truncate">{{ activeThread.contactName }}</p>
<p class="text-[9px] text-white/30 font-mono truncate">{{ activeThread.contactPubkey }}</p>
<p class="text-xs text-white/30 font-mono truncate">{{ activeThread.contactPubkey }}</p>
</div>
</div>
@@ -31,7 +31,7 @@
: 'bg-white/5 text-white/70'"
>
<p class="text-xs leading-relaxed break-words">{{ msg.content }}</p>
<p class="text-[9px] mt-1 text-white/25 tabular-nums">{{ formatTime(msg.created_at) }}</p>
<p class="text-xs mt-1 text-white/25 tabular-nums">{{ formatTime(msg.created_at) }}</p>
</div>
</div>
</div>
@@ -43,7 +43,7 @@
v-model="messageInput"
type="text"
placeholder="Type a message..."
class="flex-1 px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
class="flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
@keydown.enter="sendMessage"
/>
<button
@@ -63,7 +63,7 @@
<div class="flex items-center justify-between gap-2 mb-3">
<h3 class="text-sm font-bold text-white/90">Messages</h3>
<button
class="text-[10px] px-2.5 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="text-xs px-2.5 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
@click="showNewDM = !showNewDM"
>
{{ showNewDM ? 'Cancel' : 'New' }}
@@ -76,10 +76,10 @@
v-model="newContactPubkey"
type="text"
placeholder="Recipient hex pubkey or npub..."
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
/>
<button
class="text-[10px] px-2.5 py-1 rounded bg-white/5 text-white/60 hover:bg-white/10 transition-colors disabled:opacity-30"
class="text-xs px-2.5 py-1 rounded bg-white/5 text-white/60 hover:bg-white/10 transition-colors disabled:opacity-30"
:disabled="!newContactPubkey.trim()"
@click="startNewDM"
>
@@ -117,7 +117,7 @@
@click="selectContact(thread.contactPubkey)"
>
<div class="flex items-start gap-2.5">
<div class="w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-[10px] font-bold bg-accent/20 text-accent">
<div class="w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-accent/20 text-accent">
{{ thread.contactName.charAt(0).toUpperCase() }}
</div>
<div class="flex-1 min-w-0">
@@ -125,11 +125,11 @@
<span class="text-xs font-semibold truncate text-white/80">
{{ thread.contactName }}
</span>
<span v-if="thread.lastMessage" class="text-[9px] ml-auto shrink-0 text-white/20">
<span v-if="thread.lastMessage" class="text-xs ml-auto shrink-0 text-white/20">
{{ formatTime(thread.lastMessage.created_at) }}
</span>
</div>
<p v-if="thread.lastMessage" class="text-[11px] mt-1 text-white/40 truncate">
<p v-if="thread.lastMessage" class="text-xs mt-1 text-white/40 truncate">
{{ thread.lastMessage.content }}
</p>
</div>
@@ -5,7 +5,7 @@
<button
v-for="tab in subTabs"
:key="tab.id"
class="text-[10px] px-2.5 py-1 rounded-md transition-all duration-150"
class="text-xs px-2.5 py-1 rounded-md transition-all duration-150"
:class="activeSubTab === tab.id
? 'nav-tab-active'
: 'text-white/40 hover:text-white/70 hover:bg-white/5'"
@@ -45,7 +45,7 @@
Nostr Feed
</h3>
<div class="flex items-center gap-2 shrink-0">
<span class="text-[10px] font-mono text-white/30">
<span class="text-xs font-mono text-white/30">
{{ filteredNotes.length }} notes
</span>
<slot name="header-actions" />
@@ -66,20 +66,20 @@
<textarea
ref="composeRef"
v-model="composeText"
class="w-full bg-transparent text-xs text-white/80 placeholder:text-white/25 outline-none resize-none min-h-[80px]"
class="w-full bg-transparent text-base text-white/80 placeholder:text-white/25 outline-none resize-none min-h-[80px]"
placeholder="What's on your mind?"
@keydown.meta.enter="publishNote"
@keydown.ctrl.enter="publishNote"
/>
<div class="flex items-center justify-between gap-2">
<span
class="text-[10px] tabular-nums"
class="text-xs tabular-nums"
:class="composeText.length > 280 ? 'text-accent/80' : 'text-white/25'"
>
{{ composeText.length }}
</span>
<button
class="text-[10px] px-3 py-1.5 rounded-lg bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
class="text-xs px-3 py-1.5 rounded-lg bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
:disabled="!composeText.trim() || isPublishing"
@click="publishNote"
>
@@ -92,7 +92,7 @@
<div
v-for="result in publishResults"
:key="result.url"
class="flex items-center gap-2 text-[10px] px-2 py-1 rounded bg-white/[0.02]"
class="flex items-center gap-2 text-xs px-2 py-1 rounded bg-white/[0.02]"
>
<span
class="w-1.5 h-1.5 rounded-full shrink-0"
@@ -111,12 +111,12 @@
v-model="search"
type="text"
placeholder="Search notes, npubs..."
class="flex-1 px-3 py-2 rounded-lg text-xs outline-none transition-colors bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10"
class="flex-1 px-3 py-2 rounded-lg text-base outline-none transition-colors bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10"
@keydown.enter="triggerNostrSearch"
/>
<button
v-if="search.trim()"
class="px-2.5 py-2 rounded-lg text-[10px] bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30 shrink-0"
class="px-2.5 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30 shrink-0"
:disabled="isSearching"
@click="triggerNostrSearch"
>
@@ -128,7 +128,7 @@
<button
v-for="kind in noteKinds"
:key="kind.id"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeKind === kind.id
? 'nav-tab-active'
: 'text-white/40 hover:text-white/70 hover:bg-white/5'"
@@ -159,7 +159,7 @@
@click="selectedNoteId = note.id"
>
<div class="flex items-start gap-2.5">
<div class="w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-[10px] font-bold bg-purple-500/20 text-purple-400">
<div class="w-8 h-8 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-purple-500/20 text-purple-400">
{{ note.authorName?.charAt(0)?.toUpperCase() ?? '?' }}
</div>
<div class="flex-1 min-w-0">
@@ -167,7 +167,7 @@
<span class="text-xs font-semibold truncate text-white/80">
{{ note.authorName ?? 'anon' }}
</span>
<span v-if="note.nip05" class="text-[9px] truncate text-purple-400/60 flex items-center gap-0.5">
<span v-if="note.nip05" class="text-xs truncate text-purple-400/60 flex items-center gap-0.5">
<svg
v-if="nip05Status[note.id] === true"
class="w-2.5 h-2.5 text-emerald-400 shrink-0"
@@ -179,23 +179,23 @@
</svg>
{{ note.nip05 }}
</span>
<span class="text-[9px] ml-auto shrink-0 text-white/20">
<span class="text-xs ml-auto shrink-0 text-white/20">
{{ formatTime(note.created_at) }}
</span>
</div>
<p class="text-[11px] mt-1 leading-relaxed line-clamp-3 text-white/60">
<p class="text-xs mt-1 leading-relaxed line-clamp-3 text-white/60">
{{ note.content }}
</p>
<div class="flex items-center gap-3 mt-2">
<button
class="text-[9px] px-1.5 py-0.5 rounded bg-white/5 text-accent/60 hover:text-accent hover:bg-accent/10 transition-colors"
class="text-xs px-1.5 py-0.5 rounded bg-white/5 text-accent/60 hover:text-accent hover:bg-accent/10 transition-colors"
@click.stop="openZap(note)"
>
Zap
</button>
<span
v-if="note.kind !== 1"
class="text-[9px] px-1.5 py-0.5 rounded bg-white/5 text-white/30"
class="text-xs px-1.5 py-0.5 rounded bg-white/5 text-white/30"
>
kind:{{ note.kind }}
</span>
@@ -206,12 +206,12 @@
<!-- Relay status -->
<div class="mt-4 pt-4 border-t border-white/5">
<p class="text-[10px] font-medium mb-2 text-white/30">Relays</p>
<p class="text-xs font-medium mb-2 text-white/30">Relays</p>
<div class="space-y-1">
<div
v-for="relay in relayStates"
:key="relay.url"
class="flex items-center gap-2 text-[10px] px-2 py-1 rounded-lg bg-white/[0.02]"
class="flex items-center gap-2 text-xs px-2 py-1 rounded-lg bg-white/[0.02]"
>
<span
class="w-1.5 h-1.5 rounded-full shrink-0"
@@ -8,7 +8,7 @@
<button
v-for="lt in listTypes"
:key="lt.kind"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeListKind === lt.kind
? 'nav-tab-active'
: 'text-white/40 hover:text-white/70 hover:bg-white/5'"
@@ -35,11 +35,11 @@
v-model="newItemValue"
type="text"
:placeholder="activeListKind === 3 ? 'Add npub or hex pubkey...' : 'Add item (hex id or npub)...'"
class="flex-1 px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
@keydown.enter="addItem"
/>
<button
class="px-2.5 py-2 rounded-lg text-[10px] bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
class="px-2.5 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
:disabled="!newItemValue.trim()"
@click="addItem"
>
@@ -53,15 +53,15 @@
:key="item.value"
class="flex items-center gap-2 p-2.5 rounded-xl bg-white/[0.03] border border-white/5"
>
<div class="w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-[8px] font-bold bg-purple-500/20 text-purple-400">
<div class="w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-purple-500/20 text-purple-400">
{{ item.tag === 'p' ? 'P' : item.tag === 'e' ? 'E' : item.tag === 't' ? '#' : '?' }}
</div>
<div class="flex-1 min-w-0">
<p class="text-[10px] text-white/60 font-mono truncate">{{ item.displayValue }}</p>
<p v-if="item.petname" class="text-[9px] text-white/30">{{ item.petname }}</p>
<p class="text-xs text-white/60 font-mono truncate">{{ item.displayValue }}</p>
<p v-if="item.petname" class="text-xs text-white/30">{{ item.petname }}</p>
</div>
<button
class="text-[9px] px-2 py-1 rounded bg-white/5 text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors shrink-0"
class="text-xs px-2 py-1 rounded bg-white/5 text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors shrink-0"
@click="removeItem(item)"
>
Remove
@@ -82,7 +82,7 @@
{{ isPublishingList ? 'Publishing...' : 'Publish updated list' }}
</button>
<p v-if="publishStatus" class="text-[10px] text-center" :class="publishOk ? 'text-emerald-400/60' : 'text-red-400/60'">
<p v-if="publishStatus" class="text-xs text-center" :class="publishOk ? 'text-emerald-400/60' : 'text-red-400/60'">
{{ publishStatus }}
</p>
</div>
@@ -27,7 +27,7 @@
</span>
</div>
<p class="text-sm font-bold text-white/90 mt-2">{{ profile.display_name || profile.name || 'Anonymous' }}</p>
<p v-if="profile.nip05" class="text-[10px] text-purple-400/60">{{ profile.nip05 }}</p>
<p v-if="profile.nip05" class="text-xs text-purple-400/60">{{ profile.nip05 }}</p>
<p v-if="profile.about" class="text-xs text-white/50 mt-1 line-clamp-2">{{ profile.about }}</p>
</div>
</div>
@@ -35,80 +35,80 @@
<!-- Edit form -->
<div class="space-y-3">
<div>
<label class="text-[10px] text-white/30 block mb-1">Display Name</label>
<label class="text-xs text-white/30 block mb-1">Display Name</label>
<input
v-model="profile.display_name"
type="text"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
placeholder="Your display name"
/>
</div>
<div>
<label class="text-[10px] text-white/30 block mb-1">Username</label>
<label class="text-xs text-white/30 block mb-1">Username</label>
<input
v-model="profile.name"
type="text"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
placeholder="username"
/>
</div>
<div>
<label class="text-[10px] text-white/30 block mb-1">Bio</label>
<label class="text-xs text-white/30 block mb-1">Bio</label>
<textarea
v-model="profile.about"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors resize-none min-h-[60px]"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors resize-none min-h-[60px]"
placeholder="Tell the world about yourself"
/>
</div>
<div>
<label class="text-[10px] text-white/30 block mb-1">Avatar URL</label>
<label class="text-xs text-white/30 block mb-1">Avatar URL</label>
<input
v-model="profile.picture"
type="url"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
placeholder="https://example.com/avatar.jpg"
/>
</div>
<div>
<label class="text-[10px] text-white/30 block mb-1">Banner URL</label>
<label class="text-xs text-white/30 block mb-1">Banner URL</label>
<input
v-model="profile.banner"
type="url"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
placeholder="https://example.com/banner.jpg"
/>
</div>
<div>
<label class="text-[10px] text-white/30 block mb-1">Website</label>
<label class="text-xs text-white/30 block mb-1">Website</label>
<input
v-model="profile.website"
type="url"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
placeholder="https://example.com"
/>
</div>
<div>
<label class="text-[10px] text-white/30 block mb-1">NIP-05 Address</label>
<label class="text-xs text-white/30 block mb-1">NIP-05 Address</label>
<input
v-model="profile.nip05"
type="text"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
placeholder="you@example.com"
/>
</div>
<div>
<label class="text-[10px] text-white/30 block mb-1">Lightning Address</label>
<label class="text-xs text-white/30 block mb-1">Lightning Address</label>
<input
v-model="profile.lud16"
type="text"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
placeholder="you@getalby.com"
/>
</div>
@@ -123,7 +123,7 @@
</button>
<!-- Status -->
<div v-if="publishStatus" class="text-[10px] text-center" :class="publishSuccess ? 'text-emerald-400/60' : 'text-red-400/60'">
<div v-if="publishStatus" class="text-xs text-center" :class="publishSuccess ? 'text-emerald-400/60' : 'text-red-400/60'">
{{ publishStatus }}
</div>
</div>
@@ -9,11 +9,11 @@
v-model="newRelayUrl"
type="text"
placeholder="wss://relay.example.com"
class="flex-1 px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
@keydown.enter="addNewRelay"
/>
<button
class="px-3 py-2 rounded-lg text-[10px] bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
class="px-3 py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
:disabled="!newRelayUrl.trim()"
@click="addNewRelay"
>
@@ -37,13 +37,13 @@
<span class="text-xs font-mono text-white/70 truncate flex-1">{{ relay.url }}</span>
<span
v-if="relay.latencyMs !== null"
class="text-[9px] tabular-nums shrink-0"
class="text-xs tabular-nums shrink-0"
:class="relay.latencyMs < 200 ? 'text-emerald-400/60' : relay.latencyMs < 500 ? 'text-yellow-400/60' : 'text-red-400/60'"
>
{{ relay.latencyMs }}ms
</span>
<span
class="text-[9px] shrink-0"
class="text-xs shrink-0"
:class="relay.connected ? 'text-emerald-400/60' : 'text-red-400/60'"
>
{{ relay.connected ? 'Connected' : 'Disconnected' }}
@@ -53,7 +53,7 @@
<!-- Controls -->
<div class="flex items-center gap-2">
<button
class="text-[9px] px-2 py-1 rounded transition-colors"
class="text-xs px-2 py-1 rounded transition-colors"
:class="relay.read
? 'bg-accent/15 text-accent/80'
: 'bg-white/5 text-white/30 hover:text-white/50'"
@@ -62,7 +62,7 @@
Read
</button>
<button
class="text-[9px] px-2 py-1 rounded transition-colors"
class="text-xs px-2 py-1 rounded transition-colors"
:class="relay.write
? 'bg-accent/15 text-accent/80'
: 'bg-white/5 text-white/30 hover:text-white/50'"
@@ -72,14 +72,14 @@
</button>
<div class="flex-1" />
<button
class="text-[9px] px-2 py-1 rounded bg-white/5 text-white/30 hover:text-white/50 transition-colors"
class="text-xs px-2 py-1 rounded bg-white/5 text-white/30 hover:text-white/50 transition-colors"
:disabled="testingRelay === relay.url"
@click="testConnection(relay.url)"
>
{{ testingRelay === relay.url ? 'Testing...' : 'Test' }}
</button>
<button
class="text-[9px] px-2 py-1 rounded bg-white/5 text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors"
class="text-xs px-2 py-1 rounded bg-white/5 text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors"
@click="removeRelay(relay.url)"
>
Remove
@@ -89,7 +89,7 @@
<!-- Test result -->
<p
v-if="testResults[relay.url] !== undefined"
class="text-[9px]"
class="text-xs"
:class="testResults[relay.url] !== null ? 'text-emerald-400/60' : 'text-red-400/60'"
>
{{ testResults[relay.url] !== null ? `Reachable (${testResults[relay.url]}ms)` : 'Unreachable' }}
@@ -99,13 +99,13 @@
<!-- Import NIP-65 -->
<div v-if="isLoggedIn" class="mt-4 pt-4 border-t border-white/5">
<button
class="w-full text-left px-3 py-2 rounded-lg text-[10px] bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10 transition-colors"
class="w-full text-left px-3 py-2 rounded-lg text-xs bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10 transition-colors"
:disabled="isImporting"
@click="importFromNIP65"
>
{{ isImporting ? 'Importing...' : 'Import relays from NIP-65 (kind:10002)' }}
</button>
<p v-if="importMessage" class="text-[9px] mt-1 text-white/30">{{ importMessage }}</p>
<p v-if="importMessage" class="text-xs mt-1 text-white/30">{{ importMessage }}</p>
</div>
</div>
</div>
@@ -21,18 +21,18 @@
<!-- Root note -->
<div v-if="rootNote" class="rounded-xl bg-white/[0.05] border border-white/10 p-3">
<div class="flex items-center gap-1.5 mb-1">
<div class="w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-[9px] font-bold bg-purple-500/20 text-purple-400">
<div class="w-6 h-6 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-purple-500/20 text-purple-400">
{{ rootNote.authorName?.charAt(0)?.toUpperCase() ?? '?' }}
</div>
<span class="text-xs font-semibold text-white/80">{{ rootNote.authorName ?? 'anon' }}</span>
<span class="text-[9px] ml-auto text-white/20">{{ formatTime(rootNote.created_at) }}</span>
<span class="text-xs ml-auto text-white/20">{{ formatTime(rootNote.created_at) }}</span>
</div>
<p class="text-xs text-white/70 leading-relaxed whitespace-pre-wrap">{{ rootNote.content }}</p>
</div>
<!-- Replies -->
<div v-if="threadTree.length > 0" class="space-y-1">
<p class="text-[10px] text-white/30 font-medium mt-3 mb-1">{{ threadTree.length }} replies</p>
<p class="text-xs text-white/30 font-medium mt-3 mb-1">{{ threadTree.length }} replies</p>
<ThreadNode
v-for="node in threadTree"
:key="node.note.id"
@@ -49,7 +49,7 @@
<!-- Reply input -->
<div v-if="rootNote && isLoggedIn" class="px-4 py-3 border-t border-white/[0.08]">
<p v-if="replyTo" class="text-[9px] text-white/30 mb-1">
<p v-if="replyTo" class="text-xs text-white/30 mb-1">
Replying to {{ replyTo.authorName ?? 'anon' }}
<button class="text-accent/60 ml-1" @click="replyTo = null">cancel</button>
</p>
@@ -58,7 +58,7 @@
v-model="replyText"
type="text"
placeholder="Reply..."
class="flex-1 px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
class="flex-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
@keydown.enter="sendReply"
/>
<button
@@ -24,18 +24,18 @@
<div class="min-w-0 flex-1 py-0.5">
<p class="text-sm font-semibold truncate"
:class="isDark ? 'text-white/90' : 'text-gray-900'">{{ place.name }}</p>
<p class="text-[11px] mt-0.5 truncate"
<p class="text-xs mt-0.5 truncate"
:class="isDark ? 'text-white/40' : 'text-gray-500'">
{{ place.cuisine || place.category }}<template v-if="place.city"> · {{ place.city }}</template>
</p>
<div class="flex items-center gap-1.5 mt-1.5">
<span v-if="place.rating && place.rating > 0"
class="text-[10px] font-semibold px-1.5 py-0.5 rounded"
class="text-xs font-semibold px-1.5 py-0.5 rounded"
:class="ratingClass">
{{ place.rating.toFixed(1) }}
</span>
<span v-if="place.priceLevel"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-white/8 text-white/50' : 'bg-black/5 text-gray-500'">
{{ '$'.repeat(place.priceLevel) }}
</span>
@@ -122,7 +122,7 @@
<div>
<p class="text-xs font-medium"
:class="isDark ? 'text-white/80' : 'text-gray-800'">{{ link.name }}</p>
<p v-if="link.desc" class="text-[10px]"
<p v-if="link.desc" class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">{{ link.desc }}</p>
</div>
</div>
@@ -6,7 +6,7 @@
{{ title || 'Places' }}
</h3>
<div class="shrink-0 flex items-center gap-2">
<span class="text-[10px]" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredPlaces.length }} places
</span>
<slot name="header-actions" />
@@ -16,7 +16,7 @@
v-model="search"
type="text"
:placeholder="`Search places...`"
class="w-full text-xs px-3 py-2 rounded-lg outline-none transition-colors"
class="w-full text-base px-3 py-2 rounded-lg outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder-white/25 focus:bg-white/8'
: 'bg-black/5 text-gray-800 placeholder-gray-400 focus:bg-black/8'"
@@ -25,7 +25,7 @@
<button
v-for="cat in topCategories"
:key="cat"
class="text-[9px] px-2 py-1 rounded-md font-medium transition-all duration-150"
class="text-xs px-2 py-1 rounded-md font-medium transition-all duration-150"
:class="activeCategory === cat
? 'nav-tab-active'
: isDark
@@ -60,16 +60,16 @@
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none" />
<div class="absolute bottom-0 left-0 right-0 p-2">
<p class="text-[11px] font-semibold text-white/90 truncate">{{ place.name }}</p>
<p class="text-[9px] text-white/40 truncate mt-0.5">{{ place.cuisine || place.category }}</p>
<p class="text-xs font-semibold text-white/90 truncate">{{ place.name }}</p>
<p class="text-xs text-white/40 truncate mt-0.5">{{ place.cuisine || place.category }}</p>
</div>
<div v-if="place.rating" class="absolute top-1.5 right-1.5">
<span class="text-[8px] px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-semibold">
<span class="text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-semibold">
{{ place.rating.toFixed(1) }}
</span>
</div>
<div v-if="place.priceLevel" class="absolute top-1.5 left-1.5">
<span class="text-[8px] px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm">
<span class="text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm">
{{ '$'.repeat(place.priceLevel) }}
</span>
</div>
@@ -25,20 +25,20 @@
<div class="min-w-0 flex-1 py-0.5">
<p class="text-sm font-semibold truncate"
:class="isDark ? 'text-white/90' : 'text-gray-900'">{{ podcast.title }}</p>
<p class="text-[11px] mt-0.5"
<p class="text-xs mt-0.5"
:class="isDark ? 'text-white/40' : 'text-gray-500'">
{{ podcast.host || 'Podcast' }}<template v-if="podcast.year"> · {{ podcast.year }}</template>
</p>
<div class="flex items-center gap-1.5 mt-1.5">
<span v-if="isExternal"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-info/15 text-info/70' : 'bg-info/10 text-blue-600'">
not in library
</span>
<span
v-for="src in podcast.sources.slice(0, 3)"
:key="src.type"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-white/8 text-white/50' : 'bg-black/5 text-gray-500'"
>
{{ src.type }}
@@ -46,7 +46,7 @@
<span
v-for="genre in podcast.genres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md font-medium"
class="text-xs px-2 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'"
>
{{ genre }}
@@ -95,7 +95,7 @@
<div>
<p class="text-xs font-medium"
:class="isDark ? 'text-white/80' : 'text-gray-800'">{{ link.name }}</p>
<p v-if="link.desc" class="text-[10px]"
<p v-if="link.desc" class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">{{ link.desc }}</p>
</div>
</div>
@@ -9,7 +9,7 @@
{{ title }}
</h3>
<div class="flex items-center gap-2 shrink-0">
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredPodcasts.length }} podcasts
</span>
<slot name="header-actions" />
@@ -20,7 +20,7 @@
v-model="search"
type="text"
placeholder="Search podcasts..."
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10'
: 'bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5'"
@@ -30,7 +30,7 @@
<button
v-for="genre in topGenres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeGenre === genre
? 'nav-tab-active'
: isDark
@@ -69,17 +69,17 @@
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none" />
<div class="absolute bottom-0 left-0 right-0 p-2">
<p class="text-[11px] font-semibold text-white/90 leading-tight truncate">
<p class="text-xs font-semibold text-white/90 leading-tight truncate">
{{ podcast.title }}
</p>
<p class="text-[9px] text-white/40 truncate mt-0.5">{{ podcast.host || 'Podcast' }}</p>
<p class="text-xs text-white/40 truncate mt-0.5">{{ podcast.host || 'Podcast' }}</p>
</div>
<div class="absolute top-1.5 right-1.5 flex gap-0.5 flex-wrap justify-end max-w-[60%]">
<span
v-for="src in podcast.sources.slice(0, 2)"
:key="src.type"
class="text-[8px] px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"
class="text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"
>
{{ src.type }}
</span>
@@ -9,7 +9,7 @@
<!-- Breadcrumb: "Projects" root (clickable when deeper) -->
<button
v-if="viewState !== 'projects'"
class="text-[10px] shrink-0 transition-colors"
class="text-xs shrink-0 transition-colors"
:class="isDark
? 'text-white/40 hover:text-white/70 hover:underline'
: 'text-gray-400 hover:text-gray-700 hover:underline'"
@@ -17,7 +17,7 @@
>
Projects
</button>
<span v-if="viewState !== 'projects'" class="text-[10px] shrink-0"
<span v-if="viewState !== 'projects'" class="text-xs shrink-0"
:class="isDark ? 'text-white/20' : 'text-gray-300'">/</span>
<!-- Current location (not clickable) -->
@@ -29,11 +29,11 @@
<div class="flex items-center gap-2 shrink-0">
<!-- Subtitle info -->
<p v-if="viewState === 'projects'" class="text-[10px]"
<p v-if="viewState === 'projects'" class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ projectList.length }} repos
</p>
<p v-else-if="viewState === 'filetree'" class="text-[10px]"
<p v-else-if="viewState === 'filetree'" class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ activeProject?.language }}
</p>
@@ -49,7 +49,7 @@
v-model="search"
type="text"
placeholder="Search projects..."
class="flex-1 min-w-0 px-3 py-2 rounded-lg text-xs bg-transparent outline-none"
class="flex-1 min-w-0 px-3 py-2 rounded-lg text-base bg-transparent outline-none"
:class="isDark
? 'text-white/80 placeholder:text-white/20 border border-white/10 focus:border-white/25'
: 'text-gray-800 placeholder:text-gray-400 border border-black/10 focus:border-black/20'"
@@ -80,7 +80,7 @@
v-model="newProjectName"
type="text"
placeholder="Project name..."
class="w-full px-3 py-2 rounded-lg text-xs bg-transparent outline-none mb-2"
class="w-full px-3 py-2 rounded-lg text-base bg-transparent outline-none mb-2"
:class="isDark
? 'text-white/80 placeholder:text-white/20 border border-white/10 focus:border-white/25'
: 'text-gray-800 placeholder:text-gray-400 border border-black/10 focus:border-black/20'"
@@ -89,14 +89,14 @@
/>
<div class="flex justify-end gap-2">
<button
class="text-[10px] px-2.5 py-1 rounded-lg transition-colors"
class="text-xs px-2.5 py-1 rounded-lg transition-colors"
:class="isDark ? 'text-white/40 hover:text-white/70' : 'text-gray-500 hover:text-gray-800'"
@click="cancelCreateProject"
>
Cancel
</button>
<button
class="text-[10px] px-2.5 py-1 rounded-lg font-medium transition-colors"
class="text-xs px-2.5 py-1 rounded-lg font-medium transition-colors"
:class="isDark ? 'bg-accent/20 text-accent hover:bg-accent/30' : 'bg-accent/10 text-accent hover:bg-accent/20'"
:disabled="!newProjectName.trim()"
@click="confirmCreateProject"
@@ -127,7 +127,7 @@
:class="isDark ? 'text-white/80' : 'text-gray-800'">
{{ project.name }}
</p>
<p class="text-[10px] mt-0.5 truncate"
<p class="text-xs mt-0.5 truncate"
:class="isDark ? 'text-white/25' : 'text-gray-400'">
{{ project.language }}
</p>
@@ -15,13 +15,13 @@
<textarea
v-model="noteContent"
class="w-full h-32 px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors resize-none"
class="w-full h-32 px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors resize-none"
placeholder="Add a note about this content..."
/>
<div class="rounded-lg bg-white/[0.03] border border-white/5 p-3">
<p class="text-[10px] text-white/25 mb-1">Preview</p>
<p class="text-[11px] text-white/60 whitespace-pre-wrap">{{ previewText }}</p>
<p class="text-xs text-white/25 mb-1">Preview</p>
<p class="text-xs text-white/60 whitespace-pre-wrap">{{ previewText }}</p>
</div>
<div class="flex gap-2">
@@ -40,11 +40,11 @@
</button>
</div>
<p v-if="!isLoggedIn" class="text-[10px] text-yellow-400/60 text-center">
<p v-if="!isLoggedIn" class="text-xs text-yellow-400/60 text-center">
Sign in with Nostr to share
</p>
<p v-if="publishResult" class="text-[10px] text-center" :class="publishOk ? 'text-emerald-400/60' : 'text-red-400/60'">
<p v-if="publishResult" class="text-xs text-center" :class="publishOk ? 'text-emerald-400/60' : 'text-red-400/60'">
{{ publishResult }}
</p>
</div>
@@ -1,9 +1,9 @@
<template>
<div v-if="isLoading || suggestions.length > 0" class="mt-4 pt-4 border-t border-white/[0.08]">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold mb-2">More Like This</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold mb-2">More Like This</p>
<div v-if="isLoading" class="py-3">
<p class="text-[10px] text-white/30">Finding similar content...</p>
<p class="text-xs text-white/30">Finding similar content...</p>
</div>
<div v-else class="space-y-1.5">
@@ -12,8 +12,8 @@
:key="i"
class="p-2.5 rounded-lg bg-white/[0.03] border border-white/5"
>
<p class="text-[11px] font-semibold text-white/80">{{ item.title }}</p>
<p class="text-[9px] text-white/40 mt-0.5">{{ item.reason }}</p>
<p class="text-xs font-semibold text-white/80">{{ item.title }}</p>
<p class="text-xs text-white/40 mt-0.5">{{ item.reason }}</p>
</div>
</div>
</div>
@@ -25,20 +25,20 @@
<div class="min-w-0 flex-1 py-0.5">
<p class="text-sm font-semibold truncate"
:class="isDark ? 'text-white/90' : 'text-gray-900'">{{ song.title }}</p>
<p class="text-[11px] mt-0.5"
<p class="text-xs mt-0.5"
:class="isDark ? 'text-white/40' : 'text-gray-500'">
{{ song.artist }}<template v-if="song.year"> · {{ song.year }}</template>
</p>
<div class="flex items-center gap-1.5 mt-1.5">
<span v-if="isExternal"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-info/15 text-info/70' : 'bg-info/10 text-blue-600'">
not in library
</span>
<span
v-for="src in (song.sources ?? []).slice(0, 3)"
:key="src.type"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-white/8 text-white/50' : 'bg-black/5 text-gray-500'"
>
{{ src.type }}
@@ -52,7 +52,7 @@
<span
v-for="genre in song.genres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md font-medium"
class="text-xs px-2 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'"
>
{{ genre }}
@@ -91,7 +91,7 @@
<div>
<p class="text-xs font-medium"
:class="isDark ? 'text-white/80' : 'text-gray-800'">{{ link.name }}</p>
<p v-if="link.desc" class="text-[10px]"
<p v-if="link.desc" class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">{{ link.desc }}</p>
</div>
</div>
@@ -9,7 +9,7 @@
{{ title }}
</h3>
<div class="flex items-center gap-2 shrink-0">
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredSongs.length }} songs
</span>
<slot name="header-actions" />
@@ -20,7 +20,7 @@
v-model="search"
type="text"
placeholder="Search songs..."
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10'
: 'bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5'"
@@ -30,7 +30,7 @@
<button
v-for="genre in topGenres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeGenre === genre
? 'nav-tab-active'
: isDark
@@ -80,17 +80,17 @@
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none" />
<div class="absolute bottom-0 left-0 right-0 p-2">
<p class="text-[11px] font-semibold text-white/90 leading-tight truncate">
<p class="text-xs font-semibold text-white/90 leading-tight truncate">
{{ song.title }}
</p>
<p class="text-[9px] text-white/40 truncate mt-0.5">{{ song.artist }}</p>
<p class="text-xs text-white/40 truncate mt-0.5">{{ song.artist }}</p>
</div>
<div class="absolute top-1.5 right-1.5 flex gap-0.5 flex-wrap justify-end max-w-[60%]">
<span
v-for="src in (song.sources ?? []).slice(0, 2)"
:key="src.type"
class="text-[8px] px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"
class="text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"
>
{{ src.type }}
</span>
@@ -25,33 +25,33 @@
<div class="min-w-0 flex-1 py-0.5">
<p class="text-sm font-semibold truncate"
:class="isDark ? 'text-white/90' : 'text-gray-900'">{{ series.title }}</p>
<p class="text-[11px] mt-0.5"
<p class="text-xs mt-0.5"
:class="isDark ? 'text-white/40' : 'text-gray-500'">
{{ yearDisplay }}<template v-if="series.network"> · {{ series.network }}</template>
</p>
<p v-if="series.synopsis"
class="text-[10px] mt-0.5 line-clamp-2"
class="text-xs mt-0.5 line-clamp-2"
:class="isDark ? 'text-white/35' : 'text-gray-400'">
{{ series.synopsis }}
</p>
<div class="flex items-center gap-1.5 mt-1.5">
<span v-if="series.rating && series.rating > 0"
class="text-[10px] font-semibold px-1.5 py-0.5 rounded"
class="text-xs font-semibold px-1.5 py-0.5 rounded"
:class="ratingClass">
{{ series.rating.toFixed(1) }}
</span>
<span v-if="series.seasons"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-white/8 text-white/50' : 'bg-black/5 text-gray-500'">
{{ series.seasons }}S
</span>
<span v-if="series.status === 'ongoing'"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-success/15 text-success/70' : 'bg-green-50 text-green-600'">
ongoing
</span>
<span v-else-if="series.status === 'ended'"
class="text-[9px] px-1.5 py-0.5 rounded font-medium"
class="text-xs px-1.5 py-0.5 rounded font-medium"
:class="isDark ? 'bg-white/8 text-white/40' : 'bg-black/5 text-gray-400'">
ended
</span>
@@ -60,7 +60,7 @@
<span
v-for="genre in series.genres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md font-medium"
class="text-xs px-2 py-1 rounded-md font-medium"
:class="isDark ? 'bg-white/10 text-white/60' : 'bg-black/5 text-gray-600'"
>
{{ genre }}
@@ -108,7 +108,7 @@
<div>
<p class="text-xs font-medium"
:class="isDark ? 'text-white/80' : 'text-gray-800'">{{ link.name }}</p>
<p v-if="link.desc" class="text-[10px]"
<p v-if="link.desc" class="text-xs"
:class="isDark ? 'text-white/30' : 'text-gray-400'">{{ link.desc }}</p>
</div>
</div>
@@ -9,7 +9,7 @@
{{ title }}
</h3>
<div class="flex items-center gap-2 shrink-0">
<span class="text-[10px] font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
<span class="text-xs font-mono" :class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ filteredSeries.length }} series
</span>
<slot name="header-actions" />
@@ -20,7 +20,7 @@
v-model="search"
type="text"
placeholder="Search TV series..."
class="w-full px-3 py-2 rounded-lg text-xs outline-none transition-colors"
class="w-full px-3 py-2 rounded-lg text-base outline-none transition-colors"
:class="isDark
? 'bg-white/5 text-white/80 placeholder:text-white/25 focus:bg-white/10'
: 'bg-black/3 text-gray-800 placeholder:text-gray-400 focus:bg-black/5'"
@@ -30,7 +30,7 @@
<button
v-for="genre in topGenres"
:key="genre"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeGenre === genre
? 'nav-tab-active'
: isDark
@@ -69,22 +69,22 @@
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none" />
<div class="absolute bottom-0 left-0 right-0 p-2">
<p class="text-[11px] font-semibold text-white/90 leading-tight truncate">
<p class="text-xs font-semibold text-white/90 leading-tight truncate">
{{ s.title }}
</p>
<p class="text-[9px] text-white/40 truncate mt-0.5">
<p class="text-xs text-white/40 truncate mt-0.5">
{{ yearDisplay(s) }}<template v-if="s.seasons"> · {{ s.seasons }}S</template>
</p>
</div>
<div v-if="s.rating" class="absolute top-1.5 left-1.5">
<span class="text-[9px] px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-medium">
<span class="text-xs px-1.5 py-0.5 rounded bg-black/60 text-amber-400 backdrop-blur-sm font-medium">
{{ s.rating.toFixed(1) }}
</span>
</div>
<div v-if="s.status === 'ongoing'" class="absolute top-1.5 right-1.5">
<span class="text-[8px] px-1 py-0.5 rounded bg-emerald-500/80 text-white backdrop-blur-sm">
<span class="text-xs px-1 py-0.5 rounded bg-emerald-500/80 text-white backdrop-blur-sm">
ongoing
</span>
</div>
@@ -93,7 +93,7 @@
<span
v-for="src in (s.sources ?? []).slice(0, 2)"
:key="src.type"
class="text-[8px] px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"
class="text-xs px-1 py-0.5 rounded bg-black/60 text-white/70 backdrop-blur-sm"
>
{{ src.type }}
</span>
@@ -2,15 +2,15 @@
<div :style="{ paddingLeft: `${Math.min(depth, 4) * 16}px` }">
<div class="rounded-lg bg-white/[0.03] border border-white/5 p-2.5 mb-1">
<div class="flex items-center gap-1.5 mb-1">
<div class="w-5 h-5 rounded-full shrink-0 flex items-center justify-center text-[8px] font-bold bg-purple-500/20 text-purple-400">
<div class="w-5 h-5 rounded-full shrink-0 flex items-center justify-center text-xs font-bold bg-purple-500/20 text-purple-400">
{{ node.note.authorName?.charAt(0)?.toUpperCase() ?? '?' }}
</div>
<span class="text-[10px] font-semibold text-white/70">{{ node.note.authorName ?? 'anon' }}</span>
<span class="text-[8px] ml-auto text-white/20">{{ formatTime(node.note.created_at) }}</span>
<span class="text-xs font-semibold text-white/70">{{ node.note.authorName ?? 'anon' }}</span>
<span class="text-xs ml-auto text-white/20">{{ formatTime(node.note.created_at) }}</span>
</div>
<p class="text-[11px] text-white/60 leading-relaxed whitespace-pre-wrap">{{ node.note.content }}</p>
<p class="text-xs text-white/60 leading-relaxed whitespace-pre-wrap">{{ node.note.content }}</p>
<button
class="text-[8px] text-white/25 hover:text-accent/60 mt-1 transition-colors"
class="text-xs text-white/25 hover:text-accent/60 mt-1 transition-colors"
@click="$emit('reply', node.note)"
>
Reply
@@ -17,7 +17,7 @@
:class="isDark ? 'text-white/90' : 'text-gray-900'">
{{ website.title || 'Website' }}
</p>
<p v-if="domain" class="text-[10px] truncate"
<p v-if="domain" class="text-xs truncate"
:class="isDark ? 'text-white/30' : 'text-gray-400'">
{{ domain }}
</p>
@@ -19,14 +19,14 @@
</div>
<!-- Target info -->
<p class="text-[10px] text-white/40 truncate font-mono">{{ targetName }}</p>
<p class="text-xs text-white/40 truncate font-mono">{{ targetName }}</p>
<!-- Amount presets -->
<div class="flex gap-1.5 flex-wrap">
<button
v-for="preset in amountPresets"
:key="preset"
class="text-[10px] px-2.5 py-1.5 rounded-lg transition-colors"
class="text-xs px-2.5 py-1.5 rounded-lg transition-colors"
:class="amount === preset
? 'bg-accent/20 text-accent border border-accent/30'
: 'bg-white/5 text-white/50 hover:bg-white/10'"
@@ -38,23 +38,23 @@
<!-- Custom amount -->
<div>
<label class="text-[10px] text-white/30 block mb-1">Amount (sats)</label>
<label class="text-xs text-white/30 block mb-1">Amount (sats)</label>
<input
v-model.number="amount"
type="number"
min="1"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors tabular-nums"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors tabular-nums"
placeholder="21"
/>
</div>
<!-- Optional message -->
<div>
<label class="text-[10px] text-white/30 block mb-1">Message (optional)</label>
<label class="text-xs text-white/30 block mb-1">Message (optional)</label>
<input
v-model="message"
type="text"
class="w-full px-3 py-2 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
class="w-full px-3 py-2 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors"
placeholder="Great post!"
/>
</div>
@@ -70,7 +70,7 @@
<!-- Invoice / QR -->
<div v-if="invoice" class="space-y-2">
<p class="text-[9px] text-white/30 text-center">Scan or tap to pay</p>
<p class="text-xs text-white/30 text-center">Scan or tap to pay</p>
<!-- QR placeholder (canvas) -->
<div class="flex justify-center">
@@ -82,10 +82,10 @@
<input
:value="invoice"
readonly
class="flex-1 px-2 py-1.5 rounded text-[9px] bg-white/5 text-white/40 font-mono truncate outline-none"
class="flex-1 px-2 py-1.5 rounded text-base bg-white/5 text-white/40 font-mono truncate outline-none"
/>
<button
class="px-2 py-1.5 rounded text-[9px] bg-white/5 text-white/40 hover:text-white/60 transition-colors"
class="px-2 py-1.5 rounded text-xs bg-white/5 text-white/40 hover:text-white/60 transition-colors"
@click="copyInvoice"
>
{{ copied ? 'Copied' : 'Copy' }}
@@ -102,7 +102,7 @@
</div>
<!-- Error -->
<p v-if="error" class="text-[10px] text-red-400/60 text-center">{{ error }}</p>
<p v-if="error" class="text-xs text-red-400/60 text-center">{{ error }}</p>
</div>
</div>
</template>
@@ -77,7 +77,7 @@
<path d="M6 18l8.5-6L6 6v12zm10-12v12h2V6h-2z" />
</svg>
</button>
<span class="text-[10px] font-mono tabular-nums"
<span class="text-xs font-mono tabular-nums"
:class="isDark ? 'text-white/40' : 'text-gray-400'">
{{ formatTime(currentTime) }}
</span>
@@ -91,17 +91,17 @@
:style="{ width: `${progress}%` }"
/>
</div>
<span class="text-[10px] font-mono tabular-nums"
<span class="text-xs font-mono tabular-nums"
:class="isDark ? 'text-white/40' : 'text-gray-400'">
{{ formatTime(duration) }}
</span>
</div>
<p v-if="error" class="text-[10px] text-red-400">{{ error }}</p>
<p v-if="error" class="text-xs text-red-400">{{ error }}</p>
</div>
<span
v-if="queue.length > 1"
class="text-[10px] font-mono tabular-nums shrink-0"
class="text-xs font-mono tabular-nums shrink-0"
:class="isDark ? 'text-white/30' : 'text-gray-400'"
>{{ queue.length }} songs</span>
<button
@@ -5,7 +5,7 @@
v-if="headings.length > 1"
class="hidden lg:flex flex-col w-56 shrink-0 border-r border-white/5 overflow-y-auto scrollbar-hide py-4 px-3"
>
<p class="text-[10px] uppercase tracking-wider text-white/30 mb-2 px-2">Contents</p>
<p class="text-xs uppercase tracking-wider text-white/30 mb-2 px-2">Contents</p>
<button
v-for="(h, i) in headings"
:key="i"
@@ -55,7 +55,7 @@
:disabled="fontSizeIdx <= 0"
@click="fontSizeIdx = Math.max(0, fontSizeIdx - 1)"
>
<span class="text-[10px] font-bold">A-</span>
<span class="text-xs font-bold">A-</span>
</button>
<button
class="w-8 h-8 flex items-center justify-center rounded-lg text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors"
@@ -19,8 +19,8 @@
<div class="flex-1 min-w-0">
<div ref="waveformRef" class="waveform-container" />
<div class="flex justify-between mt-1">
<span class="text-[10px] text-white/30 tabular-nums">{{ formatTime(currentTime) }}</span>
<span class="text-[10px] text-white/30 tabular-nums">{{ formatTime(duration) }}</span>
<span class="text-xs text-white/30 tabular-nums">{{ formatTime(currentTime) }}</span>
<span class="text-xs text-white/30 tabular-nums">{{ formatTime(duration) }}</span>
</div>
</div>
</div>
@@ -30,7 +30,7 @@
</div>
<div v-if="loading" class="px-4 pb-3">
<p class="text-[10px] text-white/30">Loading audio...</p>
<p class="text-xs text-white/30">Loading audio...</p>
</div>
</div>
</template>
@@ -1,8 +1,8 @@
<template>
<div class="rounded-xl bg-white/5 border border-white/10 p-3 space-y-2">
<div class="flex items-center gap-2">
<span class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Bitcoin Address</span>
<span class="text-[9px] px-1.5 py-0.5 rounded bg-white/5 text-white/30">{{ addressType }}</span>
<span class="text-xs text-accent/60 uppercase tracking-wider font-bold">Bitcoin Address</span>
<span class="text-xs px-1.5 py-0.5 rounded bg-white/5 text-white/30">{{ addressType }}</span>
</div>
<!-- Address display -->
@@ -16,7 +16,7 @@
<!-- Actions -->
<div class="flex gap-2">
<button
class="flex-1 py-2 rounded-lg text-[10px] bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
class="flex-1 py-2 rounded-lg text-xs bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
@click="copyAddress"
>
{{ copied ? 'Copied!' : 'Copy Address' }}
@@ -25,7 +25,7 @@
:href="mempoolLink"
target="_blank"
rel="noopener noreferrer"
class="flex-1 py-2 rounded-lg text-[10px] text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="flex-1 py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
>
View on Mempool
</a>
@@ -1,10 +1,10 @@
<template>
<div class="rounded-xl bg-white/5 border border-white/10 p-3 space-y-2">
<div class="flex items-center gap-2">
<span class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Lightning Invoice</span>
<span class="text-xs text-accent/60 uppercase tracking-wider font-bold">Lightning Invoice</span>
<span
v-if="isExpired"
class="text-[9px] px-1.5 py-0.5 rounded bg-red-400/15 text-red-400/80"
class="text-xs px-1.5 py-0.5 rounded bg-red-400/15 text-red-400/80"
>
Expired
</span>
@@ -13,7 +13,7 @@
<!-- Amount -->
<div v-if="decodedAmount" class="flex items-center gap-2">
<span class="text-lg font-bold text-accent tabular-nums">{{ formatSats(decodedAmount) }}</span>
<span class="text-[10px] text-white/30">sats</span>
<span class="text-xs text-white/30">sats</span>
</div>
<!-- Description -->
@@ -22,7 +22,7 @@
<!-- Expiry countdown -->
<div v-if="expiryText" class="flex items-center gap-1.5">
<span
class="text-[9px] tabular-nums"
class="text-xs tabular-nums"
:class="isExpired ? 'text-red-400/60' : isExpiringSoon ? 'text-red-400/60' : 'text-white/30'"
>
{{ expiryText }}
@@ -30,18 +30,18 @@
</div>
<!-- Invoice string -->
<p class="text-[9px] font-mono text-white/30 break-all line-clamp-2 select-all">{{ invoice }}</p>
<p class="text-xs font-mono text-white/30 break-all line-clamp-2 select-all">{{ invoice }}</p>
<div class="flex gap-2">
<button
class="flex-1 py-2 rounded-lg text-[10px] bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
class="flex-1 py-2 rounded-lg text-xs bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
@click="copyInvoice"
>
{{ copied ? 'Copied!' : 'Copy' }}
</button>
<a
:href="'lightning:' + invoice"
class="flex-1 py-2 rounded-lg text-[10px] text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="flex-1 py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
>
Pay with wallet
</a>
@@ -1,7 +1,7 @@
<template>
<div class="rounded-xl bg-white/5 border border-white/10 p-3 space-y-2">
<div class="flex items-center gap-2">
<span class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">BOLT12 Offer</span>
<span class="text-xs text-accent/60 uppercase tracking-wider font-bold">BOLT12 Offer</span>
</div>
<p class="text-xs font-mono text-white/50 break-all line-clamp-2 select-all">{{ offer }}</p>
@@ -13,14 +13,14 @@
<div class="flex gap-2">
<button
class="flex-1 py-2 rounded-lg text-[10px] bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
class="flex-1 py-2 rounded-lg text-xs bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
@click="copyOffer"
>
{{ copied ? 'Copied!' : 'Copy Offer' }}
</button>
<a
:href="'lightning:' + offer"
class="flex-1 py-2 rounded-lg text-[10px] text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="flex-1 py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
>
Pay with wallet
</a>
@@ -2,17 +2,17 @@
<div class="code-runner rounded-xl bg-white/5 border border-white/10 overflow-hidden">
<!-- Toolbar -->
<div class="flex items-center gap-2 px-3 py-2 border-b border-white/5">
<span class="text-[10px] text-white/30 uppercase tracking-wider">{{ language }}</span>
<span class="text-xs text-white/30 uppercase tracking-wider">{{ language }}</span>
<div class="flex-1" />
<button
class="text-[10px] px-2.5 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="text-xs px-2.5 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
@click="runCode"
>
Run
</button>
<button
v-if="consoleOutput.length > 0"
class="text-[10px] px-2 py-1 rounded bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10 transition-colors"
class="text-xs px-2 py-1 rounded bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10 transition-colors"
@click="clearOutput"
>
Clear
@@ -38,11 +38,11 @@
v-if="consoleOutput.length > 0"
class="border-t border-white/5 bg-black/30 px-3 py-2 max-h-32 overflow-y-auto"
>
<p class="text-[9px] text-white/20 uppercase tracking-wider mb-1">Console</p>
<p class="text-xs text-white/20 uppercase tracking-wider mb-1">Console</p>
<div
v-for="(entry, i) in consoleOutput"
:key="i"
class="text-[11px] font-mono leading-relaxed"
class="text-xs font-mono leading-relaxed"
:class="entry.type === 'error' ? 'text-red-400/80' : 'text-white/60'"
>
{{ entry.text }}
@@ -3,7 +3,7 @@
<div class="flex items-start gap-3">
<!-- Date chip -->
<div class="shrink-0 w-14 text-center rounded-lg bg-accent/10 border border-accent/20 py-1.5">
<p class="text-[10px] text-accent/70 uppercase">{{ monthLabel }}</p>
<p class="text-xs text-accent/70 uppercase">{{ monthLabel }}</p>
<p class="text-lg font-bold text-accent leading-tight">{{ dayLabel }}</p>
</div>
@@ -13,14 +13,14 @@
<p v-if="event.description" class="text-xs text-white/40 mt-1 line-clamp-2">{{ event.description }}</p>
<!-- Countdown -->
<p v-if="countdownText" class="text-[10px] mt-1.5" :class="isPast ? 'text-white/30' : 'text-accent/70'">
<p v-if="countdownText" class="text-xs mt-1.5" :class="isPast ? 'text-white/30' : 'text-accent/70'">
{{ countdownText }}
</p>
<!-- Actions -->
<div class="flex gap-2 mt-2">
<button
class="text-[10px] px-2 py-1 rounded bg-white/5 border border-white/10 text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors"
class="text-xs px-2 py-1 rounded bg-white/5 border border-white/10 text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors"
title="Download ICS file"
@click.stop="downloadIcs"
>
@@ -30,7 +30,7 @@
:href="googleCalendarUrl"
target="_blank"
rel="noopener noreferrer"
class="text-[10px] px-2 py-1 rounded bg-white/5 border border-white/10 text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors"
class="text-xs px-2 py-1 rounded bg-white/5 border border-white/10 text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors"
@click.stop
>
Google Calendar
@@ -1,7 +1,7 @@
<template>
<div class="rounded-xl bg-white/5 border border-white/10 p-3 space-y-2">
<div class="flex items-center gap-2">
<span class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Fedimint Ecash</span>
<span class="text-xs text-accent/60 uppercase tracking-wider font-bold">Fedimint Ecash</span>
</div>
<p class="text-xs font-mono text-white/50 break-all line-clamp-2 select-all">{{ token }}</p>
@@ -12,14 +12,14 @@
<div class="flex gap-2">
<button
class="flex-1 py-2 rounded-lg text-[10px] bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
class="flex-1 py-2 rounded-lg text-xs bg-white/5 text-white/50 hover:text-white/70 hover:bg-white/10 transition-colors"
@click="copyToken"
>
{{ copied ? 'Copied!' : 'Copy Token' }}
</button>
<a
:href="fediLink"
class="flex-1 py-2 rounded-lg text-[10px] text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="flex-1 py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
>
Receive in Fedi
</a>
@@ -5,11 +5,11 @@
<input
v-model="filterQuery"
type="text"
class="flex-1 bg-white/5 border border-white/10 rounded px-2 py-1 text-xs text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
class="flex-1 bg-white/5 border border-white/10 rounded px-2 py-1 text-base text-white/80 outline-none focus:border-accent/40 placeholder:text-white/25"
placeholder="Filter rows..."
/>
<button
class="text-[10px] px-2 py-1 rounded bg-white/5 border border-white/10 text-white/50 hover:text-white/80 hover:bg-white/10 transition-colors"
class="text-xs px-2 py-1 rounded bg-white/5 border border-white/10 text-white/50 hover:text-white/80 hover:bg-white/10 transition-colors"
title="Export CSV"
@click="exportCsv"
>
@@ -59,7 +59,7 @@
No matching rows
</div>
<div v-if="filteredRows.length > 0" class="px-3 py-1.5 text-[10px] text-white/25 border-t border-white/5">
<div v-if="filteredRows.length > 0" class="px-3 py-1.5 text-xs text-white/25 border-t border-white/5">
{{ filteredRows.length }} row{{ filteredRows.length === 1 ? '' : 's' }}
<span v-if="filterQuery"> (filtered from {{ rows.length }})</span>
</div>
@@ -32,7 +32,7 @@
@click="selectPlace(i)"
>
<p class="text-xs text-white/80 truncate">{{ place.name }}</p>
<p v-if="place.address || place.city" class="text-[10px] text-white/40 truncate">
<p v-if="place.address || place.city" class="text-xs text-white/40 truncate">
{{ place.address || place.city }}
</p>
</button>
@@ -1,10 +1,10 @@
<template>
<div class="rounded-xl bg-white/5 border border-white/10 p-3 space-y-2">
<div class="flex items-center gap-2">
<span class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Transaction</span>
<span class="text-xs text-accent/60 uppercase tracking-wider font-bold">Transaction</span>
<span
v-if="txData"
class="text-[9px] px-1.5 py-0.5 rounded"
class="text-xs px-1.5 py-0.5 rounded"
:class="txData.confirmed ? 'bg-emerald-400/15 text-emerald-400/80' : 'bg-yellow-400/15 text-yellow-400/80'"
>
{{ txData.confirmed ? `${txData.confirmations} confirmations` : 'Unconfirmed' }}
@@ -12,10 +12,10 @@
</div>
<!-- TXID -->
<p class="text-[9px] font-mono text-white/40 break-all select-all">{{ txid }}</p>
<p class="text-xs font-mono text-white/40 break-all select-all">{{ txid }}</p>
<!-- TX details -->
<div v-if="txData" class="grid grid-cols-2 gap-2 text-[10px]">
<div v-if="txData" class="grid grid-cols-2 gap-2 text-xs">
<div>
<p class="text-white/25">Fee</p>
<p class="text-white/60 tabular-nums">{{ txData.fee.toLocaleString() }} sats</p>
@@ -35,18 +35,18 @@
</div>
<div v-else-if="isLoading" class="py-2">
<p class="text-[10px] text-white/30">Loading transaction...</p>
<p class="text-xs text-white/30">Loading transaction...</p>
</div>
<div v-else-if="error" class="py-2">
<p class="text-[10px] text-red-400/60">{{ error }}</p>
<p class="text-xs text-red-400/60">{{ error }}</p>
</div>
<a
:href="`https://mempool.space/tx/${txid}`"
target="_blank"
rel="noopener noreferrer"
class="block w-full py-2 rounded-lg text-[10px] text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="block w-full py-2 rounded-lg text-xs text-center bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
>
View on Mempool.space
</a>
@@ -46,7 +46,7 @@
>
<span class="text-xs font-bold"></span>
</button>
<span class="text-[10px] text-white/40 tabular-nums w-10 text-center">{{ Math.round(scale * 100) }}%</span>
<span class="text-xs text-white/40 tabular-nums w-10 text-center">{{ Math.round(scale * 100) }}%</span>
<button
class="w-8 h-8 flex items-center justify-center rounded-lg text-white/60 hover:text-white/80 hover:bg-white/10 transition-colors disabled:opacity-30"
:disabled="scale >= 2"
@@ -4,21 +4,21 @@
<div class="px-4 py-3 border-b border-white/5">
<h3 class="text-sm font-semibold text-white/90">{{ recipe.title }}</h3>
<div class="flex gap-3 mt-1.5">
<span v-if="recipe.time" class="text-[10px] text-white/40 flex items-center gap-1">
<span v-if="recipe.time" class="text-xs text-white/40 flex items-center gap-1">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
{{ recipe.time }}
</span>
<span v-if="recipe.servings" class="text-[10px] text-white/40 flex items-center gap-1">
<span v-if="recipe.servings" class="text-xs text-white/40 flex items-center gap-1">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
{{ scaledServings }} servings
</span>
<span v-if="recipe.calories" class="text-[10px] text-white/40">{{ recipe.calories }} cal</span>
<span v-if="recipe.calories" class="text-xs text-white/40">{{ recipe.calories }} cal</span>
</div>
</div>
<!-- Scale slider -->
<div class="px-4 py-2 border-b border-white/5 flex items-center gap-3">
<label class="text-[10px] text-white/30">Scale</label>
<label class="text-xs text-white/30">Scale</label>
<input
v-model.number="scaleFactor"
type="range"
@@ -27,12 +27,12 @@
step="0.5"
class="flex-1 h-1 accent-[#F7931A] bg-white/10 rounded-full appearance-none cursor-pointer"
/>
<span class="text-[10px] text-white/50 tabular-nums w-8 text-right">{{ scaleFactor }}×</span>
<span class="text-xs text-white/50 tabular-nums w-8 text-right">{{ scaleFactor }}×</span>
</div>
<!-- Ingredients -->
<div class="px-4 py-3 border-b border-white/5">
<h4 class="text-[11px] text-white/40 uppercase tracking-wider mb-2">Ingredients</h4>
<h4 class="text-xs text-white/40 uppercase tracking-wider mb-2">Ingredients</h4>
<ul class="space-y-1">
<li
v-for="(ing, i) in scaledIngredients"
@@ -52,14 +52,14 @@
<!-- Steps -->
<div class="px-4 py-3">
<h4 class="text-[11px] text-white/40 uppercase tracking-wider mb-2">Steps</h4>
<h4 class="text-xs text-white/40 uppercase tracking-wider mb-2">Steps</h4>
<ol class="space-y-2">
<li
v-for="(step, i) in recipe.steps"
:key="i"
class="flex gap-2 text-xs text-white/70"
>
<span class="shrink-0 w-5 h-5 rounded-full bg-accent/15 text-accent text-[10px] flex items-center justify-center font-medium">{{ i + 1 }}</span>
<span class="shrink-0 w-5 h-5 rounded-full bg-accent/15 text-accent text-xs flex items-center justify-center font-medium">{{ i + 1 }}</span>
<span class="leading-relaxed">{{ step }}</span>
</li>
</ol>
@@ -20,16 +20,16 @@
<!-- Date (mobile: inline, desktop: left/right side) -->
<div class="hidden md:block w-[calc(50%-2rem)] text-right shrink-0" :class="i % 2 === 0 ? '' : 'order-last text-left'">
<p class="text-[10px] text-white/40 tabular-nums pt-1">{{ formatDate(event.date) }}</p>
<p class="text-xs text-white/40 tabular-nums pt-1">{{ formatDate(event.date) }}</p>
</div>
<!-- Card -->
<div class="ml-10 md:ml-0 md:w-[calc(50%-2rem)] shrink-0">
<div class="rounded-lg bg-white/5 border border-white/10 px-3 py-2">
<p class="text-[10px] text-white/30 md:hidden tabular-nums">{{ formatDate(event.date) }}</p>
<p class="text-xs text-white/30 md:hidden tabular-nums">{{ formatDate(event.date) }}</p>
<h4 class="text-xs font-medium text-white/90">{{ event.title }}</h4>
<p v-if="event.location" class="text-[10px] text-white/40 mt-0.5">{{ event.location }}</p>
<p v-if="event.description" class="text-[10px] text-white/50 mt-1 line-clamp-2">{{ event.description }}</p>
<p v-if="event.location" class="text-xs text-white/40 mt-0.5">{{ event.location }}</p>
<p v-if="event.description" class="text-xs text-white/50 mt-1 line-clamp-2">{{ event.description }}</p>
</div>
</div>
</div>
@@ -22,7 +22,7 @@
{{ provider.name }}
</div>
<div
class="text-[10px] font-mono mt-0.5"
class="text-xs font-mono mt-0.5"
:class="isDark ? 'text-white/30' : 'text-gray-400'"
>
{{ provider.masked ?? 'Not configured' }}
@@ -30,7 +30,7 @@
</div>
<button
v-if="provider.hasKey"
class="text-[10px] px-2 py-1 rounded-md transition-colors"
class="text-xs px-2 py-1 rounded-md transition-colors"
:class="isDark
? 'text-red-400/60 hover:text-red-400 hover:bg-red-500/10'
: 'text-red-500/60 hover:text-red-600 hover:bg-red-50'"
@@ -83,7 +83,7 @@
<p
v-if="statusMessage"
class="text-[10px]"
class="text-xs"
:class="statusError ? 'text-red-400' : isDark ? 'text-green-400' : 'text-green-600'"
>
{{ statusMessage }}
@@ -25,7 +25,7 @@
Connected
</div>
<button
class="text-[10px] font-mono mt-0.5 hover:underline"
class="text-xs font-mono mt-0.5 hover:underline"
:class="isDark ? 'text-purple-400/60' : 'text-purple-600/60'"
@click="copyNpub"
>
@@ -33,7 +33,7 @@
</button>
</div>
<button
class="text-[10px] px-2 py-1 rounded-md transition-colors"
class="text-xs px-2 py-1 rounded-md transition-colors"
:class="isDark
? 'text-red-400/60 hover:text-red-400 hover:bg-red-500/10'
: 'text-red-500/60 hover:text-red-600 hover:bg-red-50'"
@@ -85,7 +85,7 @@
<!-- Error -->
<p
v-if="error"
class="text-[10px] text-red-400"
class="text-xs text-red-400"
>
{{ error }}
</p>
@@ -4,7 +4,7 @@
<div class="flex items-center justify-between mb-3">
<h3 class="text-sm font-bold text-white/90">Plugins</h3>
<div class="flex items-center gap-2">
<span v-if="store.hasUpdates" class="text-[8px] px-1.5 py-0.5 rounded-full bg-accent/20 text-accent/80">
<span v-if="store.hasUpdates" class="text-xs px-1.5 py-0.5 rounded-full bg-accent/20 text-accent/80">
Updates
</span>
</div>
@@ -14,7 +14,7 @@
<button
v-for="tab in tabs"
:key="tab.id"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeTab === tab.id
? 'nav-tab-active'
: 'text-white/40 hover:text-white/70 hover:bg-white/5'"
@@ -34,7 +34,7 @@
<div v-else-if="store.registryError && store.registryPlugins.length === 0" class="py-8 text-center">
<p class="text-xs text-red-400/60">{{ store.registryError }}</p>
<button class="mt-2 text-[10px] text-accent/60 hover:text-accent/80" @click="store.fetchRegistry()">Retry</button>
<button class="mt-2 text-xs text-accent/60 hover:text-accent/80" @click="store.fetchRegistry()">Retry</button>
</div>
<div
@@ -45,22 +45,22 @@
<div class="flex items-center justify-between">
<div class="flex-1 min-w-0">
<p class="text-xs font-semibold text-white/80">{{ plugin.name }}</p>
<p class="text-[9px] text-white/30">{{ plugin.author }} · v{{ plugin.version }}</p>
<p class="text-xs text-white/30">{{ plugin.author }} · v{{ plugin.version }}</p>
</div>
<button
v-if="!store.isInstalled(plugin.id)"
class="text-[10px] px-3 py-1.5 rounded-lg bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors shrink-0"
class="text-xs px-3 py-1.5 rounded-lg bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors shrink-0"
@click="showPermissionsDialog(plugin)"
>
Install
</button>
<span v-else class="text-[9px] text-emerald-400/60 shrink-0">Installed</span>
<span v-else class="text-xs text-emerald-400/60 shrink-0">Installed</span>
</div>
<p class="text-[10px] text-white/50">{{ plugin.description }}</p>
<p class="text-xs text-white/50">{{ plugin.description }}</p>
<div class="flex items-center gap-2">
<span class="text-[8px] px-1.5 py-0.5 rounded bg-white/5 text-white/30">{{ plugin.type }}</span>
<span class="text-xs px-1.5 py-0.5 rounded bg-white/5 text-white/30">{{ plugin.type }}</span>
<div class="flex items-center gap-0.5">
<span v-for="i in 5" :key="i" class="text-[8px]" :class="i <= plugin.rating ? 'text-accent/60' : 'text-white/10'"></span>
<span v-for="i in 5" :key="i" class="text-xs" :class="i <= plugin.rating ? 'text-accent/60' : 'text-white/10'"></span>
</div>
</div>
</div>
@@ -83,18 +83,18 @@
<div class="flex items-center justify-between">
<div class="flex-1 min-w-0">
<p class="text-xs font-semibold text-white/80">{{ plugin.name }}</p>
<p class="text-[9px] text-white/30">v{{ plugin.version }} · {{ plugin.author }}</p>
<p class="text-xs text-white/30">v{{ plugin.version }} · {{ plugin.author }}</p>
</div>
<div class="flex items-center gap-1.5 shrink-0">
<button
v-if="store.updatesAvailable.has(plugin.id)"
class="text-[9px] px-2 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="text-xs px-2 py-1 rounded bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
@click="store.updatePlugin(plugin.id)"
>
Update to v{{ store.updatesAvailable.get(plugin.id) }}
</button>
<button
class="text-[9px] p-1 rounded text-white/30 hover:text-white/60 hover:bg-white/5 transition-colors"
class="text-xs p-1 rounded text-white/30 hover:text-white/60 hover:bg-white/5 transition-colors"
@click="editingPlugin = editingPlugin === plugin.id ? null : plugin.id"
>
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -103,7 +103,7 @@
</svg>
</button>
<button
class="text-[9px] px-2 py-1 rounded text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors"
class="text-xs px-2 py-1 rounded text-red-400/50 hover:text-red-400/80 hover:bg-red-400/10 transition-colors"
@click="store.uninstallPlugin(plugin.id)"
>
Remove
@@ -116,7 +116,7 @@
<span
v-for="perm in plugin.permissions"
:key="perm"
class="text-[8px] px-1.5 py-0.5 rounded"
class="text-xs px-1.5 py-0.5 rounded"
:class="plugin.grantedPermissions.includes(perm)
? 'bg-emerald-400/15 text-emerald-400/60'
: 'bg-red-400/15 text-red-400/60'"
@@ -150,14 +150,14 @@
<!-- Import -->
<template v-else-if="activeTab === 'import'">
<div class="space-y-3">
<p class="text-[10px] text-white/40">
<p class="text-xs text-white/40">
Paste a GitHub raw URL or IPFS CID to the plugin's manifest (aiui-plugin.json).
</p>
<input
v-model="importUrl"
type="text"
placeholder="https://raw.githubusercontent.com/.../aiui-plugin.json"
class="w-full px-3 py-2.5 rounded-lg text-xs bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
class="w-full px-3 py-2.5 rounded-lg text-base bg-white/5 text-white/80 placeholder:text-white/25 outline-none focus:bg-white/10 transition-colors font-mono"
/>
<button
class="w-full py-2.5 rounded-lg text-xs font-medium bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors disabled:opacity-30"
@@ -166,15 +166,15 @@
>
{{ isImporting ? 'Fetching manifest...' : 'Import Plugin' }}
</button>
<p v-if="importError" class="text-[10px] text-red-400/60">{{ importError }}</p>
<p v-if="importError" class="text-xs text-red-400/60">{{ importError }}</p>
<!-- Imported plugin preview -->
<div v-if="importedManifest" class="rounded-xl bg-white/[0.03] border border-white/5 p-3 space-y-2">
<p class="text-xs font-semibold text-white/80">{{ importedManifest.name }}</p>
<p class="text-[10px] text-white/50">{{ importedManifest.description }}</p>
<p class="text-[9px] text-white/30">{{ importedManifest.author }} · v{{ importedManifest.version }}</p>
<p class="text-xs text-white/50">{{ importedManifest.description }}</p>
<p class="text-xs text-white/30">{{ importedManifest.author }} · v{{ importedManifest.version }}</p>
<button
class="w-full py-2 rounded-lg text-[10px] bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="w-full py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
@click="showPermissionsDialog(importedManifest)"
>
Install
@@ -187,31 +187,31 @@
<template v-else-if="activeTab === 'dev'">
<div v-if="!isDevMode" class="flex flex-col items-center justify-center py-12 gap-2">
<p class="text-xs text-white/30">Dev mode not enabled</p>
<p class="text-[10px] text-white/20">Set VITE_PLUGIN_DEV=true to enable</p>
<p class="text-xs text-white/20">Set VITE_PLUGIN_DEV=true to enable</p>
</div>
<template v-else>
<div class="rounded-xl bg-white/[0.03] border border-white/5 p-3 space-y-2">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Plugin Dev Mode</p>
<p class="text-[10px] text-white/40">Hot-reload from src/plugins/dev/</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Plugin Dev Mode</p>
<p class="text-xs text-white/40">Hot-reload from src/plugins/dev/</p>
<div v-if="devErrors.length > 0" class="space-y-1 mt-2">
<p class="text-[9px] text-red-400/60 uppercase tracking-wider font-bold">Errors</p>
<p class="text-xs text-red-400/60 uppercase tracking-wider font-bold">Errors</p>
<div
v-for="(err, i) in devErrors"
:key="i"
class="text-[9px] text-red-400/50 font-mono bg-red-400/5 rounded p-2"
class="text-xs text-red-400/50 font-mono bg-red-400/5 rounded p-2"
>
{{ err }}
</div>
</div>
<div v-if="devTimings.length > 0" class="space-y-1 mt-2">
<p class="text-[9px] text-white/30 uppercase tracking-wider font-bold">Init Timing</p>
<p class="text-xs text-white/30 uppercase tracking-wider font-bold">Init Timing</p>
<div
v-for="t in devTimings"
:key="t.id"
class="flex items-center justify-between text-[9px]"
class="flex items-center justify-between text-xs"
>
<span class="text-white/50">{{ t.id }}</span>
<span class="text-white/30 tabular-nums">{{ t.ms }}ms</span>
@@ -227,7 +227,7 @@
<div v-if="pendingInstall" class="fixed inset-0 z-50 flex items-center justify-center bg-black/60">
<div class="w-full max-w-sm mx-4 rounded-2xl bg-[#0a0a0a] border border-white/10 p-5 space-y-4">
<h4 class="text-sm font-bold text-white/90">Plugin Permissions</h4>
<p class="text-[10px] text-white/40">
<p class="text-xs text-white/40">
"{{ pendingInstall.name }}" requests the following permissions:
</p>
<div class="space-y-2">
@@ -243,8 +243,8 @@
@change="togglePermission(perm)"
/>
<div>
<p class="text-[11px] text-white/70">{{ permissionLabel(perm) }}</p>
<p class="text-[9px] text-white/30">{{ permissionDescription(perm) }}</p>
<p class="text-xs text-white/70">{{ permissionLabel(perm) }}</p>
<p class="text-xs text-white/30">{{ permissionDescription(perm) }}</p>
</div>
</label>
</div>
@@ -1,14 +1,14 @@
<template>
<div class="mt-2 pt-2 border-t border-white/[0.05] space-y-3">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Settings</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Settings</p>
<!-- Generic key-value settings editor -->
<div class="space-y-2">
<div v-for="(value, key) in localSettings" :key="key" class="flex items-center gap-2">
<span class="text-[10px] text-white/40 min-w-[60px]">{{ key }}</span>
<span class="text-xs text-white/40 min-w-[60px]">{{ key }}</span>
<input
:value="String(value ?? '')"
class="flex-1 px-2 py-1.5 rounded-md text-[10px] bg-white/5 text-white/70 outline-none focus:bg-white/10 transition-colors"
class="flex-1 px-2 py-1.5 rounded-md text-base bg-white/5 text-white/70 outline-none focus:bg-white/10 transition-colors"
@input="updateSetting(key as string, ($event.target as HTMLInputElement).value)"
/>
</div>
@@ -19,16 +19,16 @@
v-model="newSettingKey"
type="text"
placeholder="Key"
class="flex-1 px-2 py-1.5 rounded-md text-[10px] bg-white/5 text-white/70 placeholder:text-white/20 outline-none focus:bg-white/10 transition-colors"
class="flex-1 px-2 py-1.5 rounded-md text-base bg-white/5 text-white/70 placeholder:text-white/20 outline-none focus:bg-white/10 transition-colors"
/>
<input
v-model="newSettingValue"
type="text"
placeholder="Value"
class="flex-1 px-2 py-1.5 rounded-md text-[10px] bg-white/5 text-white/70 placeholder:text-white/20 outline-none focus:bg-white/10 transition-colors"
class="flex-1 px-2 py-1.5 rounded-md text-base bg-white/5 text-white/70 placeholder:text-white/20 outline-none focus:bg-white/10 transition-colors"
/>
<button
class="text-[9px] px-2 py-1.5 rounded-md bg-white/5 text-white/40 hover:text-white/70 hover:bg-white/10 transition-colors disabled:opacity-30"
class="text-xs px-2 py-1.5 rounded-md bg-white/5 text-white/40 hover:text-white/70 hover:bg-white/10 transition-colors disabled:opacity-30"
:disabled="!newSettingKey.trim()"
@click="addSetting"
>
@@ -39,12 +39,12 @@
<!-- Permissions toggles -->
<div v-if="permissions.length > 0">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold mb-2">Permissions</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold mb-2">Permissions</p>
<div class="space-y-1">
<label
v-for="perm in permissions"
:key="perm"
class="flex items-center gap-2 text-[10px] cursor-pointer"
class="flex items-center gap-2 text-xs cursor-pointer"
>
<input
type="checkbox"
@@ -58,7 +58,7 @@
</div>
<button
class="w-full py-2 rounded-lg text-[10px] bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
class="w-full py-2 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
@click="save"
>
Save Settings
@@ -19,7 +19,7 @@
<button
v-for="tab in tabs"
:key="tab.id"
class="text-[10px] px-2 py-1 rounded-md whitespace-nowrap transition-all duration-150"
class="text-xs px-2 py-1 rounded-md whitespace-nowrap transition-all duration-150"
:class="activeTab === tab.id
? 'nav-tab-active'
: 'text-white/40 hover:text-white/70 hover:bg-white/5'"
@@ -35,7 +35,7 @@
<template v-if="activeTab === 'appearance'">
<!-- M15.1 Accent colour -->
<div class="space-y-2">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Accent Colour</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Accent Colour</p>
<div class="flex gap-2 flex-wrap">
<button
v-for="color in accentPresets"
@@ -47,7 +47,7 @@
@click="store.accentColor = color.value"
/>
<label class="w-8 h-8 rounded-lg border-2 border-white/10 flex items-center justify-center cursor-pointer overflow-hidden relative">
<span class="text-[8px] text-white/30">+</span>
<span class="text-xs text-white/30">+</span>
<input
type="color"
:value="store.accentColor"
@@ -60,12 +60,12 @@
<!-- M15.2 Glass intensity -->
<div class="space-y-2">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Glass Intensity</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Glass Intensity</p>
<div class="flex gap-2">
<button
v-for="opt in glassOptions"
:key="opt.value"
class="flex-1 py-2 rounded-lg text-[10px] transition-all"
class="flex-1 py-2 rounded-lg text-xs transition-all"
:class="store.glassIntensity === opt.value
? 'bg-accent/15 text-accent/80'
: 'bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10'"
@@ -78,12 +78,12 @@
<!-- M15.3 Font size -->
<div class="space-y-2">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Font Size</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Font Size</p>
<div class="flex gap-2">
<button
v-for="opt in fontOptions"
:key="opt.value"
class="flex-1 py-2 rounded-lg text-[10px] transition-all"
class="flex-1 py-2 rounded-lg text-xs transition-all"
:class="store.fontSize === opt.value
? 'bg-accent/15 text-accent/80'
: 'bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10'"
@@ -99,8 +99,8 @@
<template v-else-if="activeTab === 'content'">
<!-- M15.4 Content type visibility -->
<div class="space-y-2">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Content Types</p>
<p class="text-[9px] text-white/30">Hidden types still extract but don't show in the panel</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Content Types</p>
<p class="text-xs text-white/30">Hidden types still extract but don't show in the panel</p>
<div class="space-y-1">
<label
v-for="ct in contentTypes"
@@ -113,7 +113,7 @@
class="rounded accent-[#F7931A]"
@change="store.toggleTabVisibility(ct.tab)"
/>
<span class="text-[11px] text-white/70">{{ ct.label }}</span>
<span class="text-xs text-white/70">{{ ct.label }}</span>
</label>
</div>
</div>
@@ -123,16 +123,16 @@
<template v-else-if="activeTab === 'shortcuts'">
<!-- M15.5 Keyboard shortcuts -->
<div class="space-y-2">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Keyboard Shortcuts</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Keyboard Shortcuts</p>
<div class="space-y-1">
<div
v-for="(binding, action) in store.settings.shortcuts"
:key="action"
class="flex items-center justify-between p-2.5 rounded-lg bg-white/[0.03] border border-white/5"
>
<span class="text-[11px] text-white/60">{{ formatAction(action as string) }}</span>
<span class="text-xs text-white/60">{{ formatAction(action as string) }}</span>
<button
class="text-[10px] px-2 py-1 rounded bg-white/5 text-white/40 hover:text-white/70 font-mono transition-colors"
class="text-xs px-2 py-1 rounded bg-white/5 text-white/40 hover:text-white/70 font-mono transition-colors"
:class="recordingAction === action ? 'bg-accent/15 text-accent/80' : ''"
@click="startRecording(action as string)"
>
@@ -147,7 +147,7 @@
<template v-else-if="activeTab === 'notifications'">
<!-- M15.6 Push notifications -->
<div class="space-y-3">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Notifications</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Notifications</p>
<label class="flex items-center gap-3 p-3 rounded-lg bg-white/[0.03] border border-white/5 cursor-pointer">
<input
type="checkbox"
@@ -156,11 +156,11 @@
@change="toggleNotifications"
/>
<div>
<p class="text-[11px] text-white/70">Generation complete</p>
<p class="text-[9px] text-white/30">Notify when AI finishes while tab is backgrounded</p>
<p class="text-xs text-white/70">Generation complete</p>
<p class="text-xs text-white/30">Notify when AI finishes while tab is backgrounded</p>
</div>
</label>
<p v-if="notificationStatus" class="text-[10px]" :class="notificationOk ? 'text-emerald-400/60' : 'text-yellow-400/60'">
<p v-if="notificationStatus" class="text-xs" :class="notificationOk ? 'text-emerald-400/60' : 'text-yellow-400/60'">
{{ notificationStatus }}
</p>
</div>
@@ -170,13 +170,13 @@
<template v-else-if="activeTab === 'storage'">
<!-- M15.7 Auto-archive -->
<div class="space-y-2">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Auto-Archive</p>
<p class="text-[9px] text-white/30">Archive conversations older than:</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Auto-Archive</p>
<p class="text-xs text-white/30">Archive conversations older than:</p>
<div class="flex gap-2">
<button
v-for="opt in archiveOptions"
:key="opt.value"
class="flex-1 py-2 rounded-lg text-[10px] transition-all"
class="flex-1 py-2 rounded-lg text-xs transition-all"
:class="store.autoArchiveDays === opt.value
? 'bg-accent/15 text-accent/80'
: 'bg-white/5 text-white/40 hover:text-white/60 hover:bg-white/10'"
@@ -189,19 +189,19 @@
<!-- M15.8 Full data export -->
<div class="space-y-2">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Data Export</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Data Export</p>
<button
class="w-full py-2.5 rounded-lg text-xs bg-accent/15 text-accent/80 hover:bg-accent/25 transition-colors"
@click="exportData"
>
{{ isExporting ? 'Exporting...' : 'Export All Data' }}
</button>
<p class="text-[9px] text-white/20">Exports conversations, favorites, settings, tags, and collections as JSON</p>
<p class="text-xs text-white/20">Exports conversations, favorites, settings, tags, and collections as JSON</p>
</div>
<!-- M15.9 Data wipe -->
<div class="space-y-2">
<p class="text-[10px] text-red-400/60 uppercase tracking-wider font-bold">Danger Zone</p>
<p class="text-xs text-red-400/60 uppercase tracking-wider font-bold">Danger Zone</p>
<button
v-if="!confirmWipe"
class="w-full py-2.5 rounded-lg text-xs bg-red-400/10 text-red-400/60 hover:bg-red-400/20 hover:text-red-400/80 transition-colors"
@@ -210,21 +210,21 @@
Wipe All Data
</button>
<div v-else class="space-y-2 p-3 rounded-lg bg-red-400/5 border border-red-400/20">
<p class="text-[11px] text-red-400/80 font-semibold">Are you sure?</p>
<p class="text-[9px] text-red-400/50">This will clear all conversations, favorites, settings, and cached data.</p>
<label class="flex items-center gap-2 text-[10px] text-red-400/60 cursor-pointer">
<p class="text-xs text-red-400/80 font-semibold">Are you sure?</p>
<p class="text-xs text-red-400/50">This will clear all conversations, favorites, settings, and cached data.</p>
<label class="flex items-center gap-2 text-xs text-red-400/60 cursor-pointer">
<input v-model="wipeApiKeys" type="checkbox" class="rounded" />
Also clear API key vault
</label>
<div class="flex gap-2">
<button
class="flex-1 py-2 rounded-lg text-[10px] text-white/40 hover:text-white/70 hover:bg-white/5 transition-colors"
class="flex-1 py-2 rounded-lg text-xs text-white/40 hover:text-white/70 hover:bg-white/5 transition-colors"
@click="confirmWipe = false"
>
Cancel
</button>
<button
class="flex-1 py-2 rounded-lg text-[10px] bg-red-400/20 text-red-400/80 hover:bg-red-400/30 transition-colors"
class="flex-1 py-2 rounded-lg text-xs bg-red-400/20 text-red-400/80 hover:bg-red-400/30 transition-colors"
@click="wipeData"
>
Confirm Wipe
@@ -238,17 +238,17 @@
<template v-else-if="activeTab === 'chat'">
<!-- M15.10 Default conversation settings -->
<div class="space-y-3">
<p class="text-[10px] text-accent/60 uppercase tracking-wider font-bold">Default Conversation Settings</p>
<p class="text-[9px] text-white/30">Applied to all new conversations</p>
<p class="text-xs text-accent/60 uppercase tracking-wider font-bold">Default Conversation Settings</p>
<p class="text-xs text-white/30">Applied to all new conversations</p>
<div class="space-y-2">
<label class="block">
<span class="text-[10px] text-white/40">Default Model</span>
<span class="text-xs text-white/40">Default Model</span>
<input
v-model="store.settings.defaultModel"
type="text"
placeholder="e.g. claude-sonnet-4-6"
class="w-full mt-1 px-3 py-2 rounded-lg text-xs bg-white/5 text-white/70 placeholder:text-white/20 outline-none focus:bg-white/10 transition-colors font-mono"
class="w-full mt-1 px-3 py-2 rounded-lg text-base bg-white/5 text-white/70 placeholder:text-white/20 outline-none focus:bg-white/10 transition-colors font-mono"
/>
</label>
@@ -258,7 +258,7 @@
type="checkbox"
class="rounded accent-[#F7931A]"
/>
<span class="text-[11px] text-white/60">Enable web search by default</span>
<span class="text-xs text-white/60">Enable web search by default</span>
</label>
<label class="flex items-center gap-3 p-2.5 rounded-lg bg-white/[0.03] border border-white/5 cursor-pointer">
@@ -267,7 +267,7 @@
type="checkbox"
class="rounded accent-[#F7931A]"
/>
<span class="text-[11px] text-white/60">Show token counts by default</span>
<span class="text-xs text-white/60">Show token counts by default</span>
</label>
</div>
</div>
@@ -36,7 +36,7 @@
<!-- Invoice string (truncated) -->
<div
class="text-[10px] font-mono break-all leading-relaxed"
class="text-xs font-mono break-all leading-relaxed"
:class="isDark ? 'text-white/30' : 'text-gray-400'"
>
{{ truncatedInvoice }}
@@ -15,7 +15,7 @@
<template v-else>
<div v-for="group in groupedResults" :key="group.type" class="py-1">
<div
class="px-3 py-1 text-[10px] font-bold uppercase tracking-wider"
class="px-3 py-1 text-xs font-bold uppercase tracking-wider"
:class="isDark ? 'text-white/30' : 'text-gray-400'"
>
{{ group.label }}
@@ -33,7 +33,7 @@
@mouseenter="selectedIndex = group.startIndex + i"
>
<span
class="text-[10px] w-5 h-5 rounded flex items-center justify-center shrink-0"
class="text-xs w-5 h-5 rounded flex items-center justify-center shrink-0"
:class="typeColor(result.type)"
>
{{ typeIcon(result.type) }}
@@ -46,7 +46,7 @@
{{ result.title }}
</div>
<div
class="text-[10px] truncate"
class="text-xs truncate"
:class="isDark ? 'text-white/40' : 'text-gray-500'"
>
{{ result.subtitle }}
+3 -3
View File
@@ -42,7 +42,7 @@
<button
v-for="tab in availableTabs"
:key="tab"
class="text-[10px] px-2 py-1 rounded-md transition-all duration-150"
class="text-xs px-2 py-1 rounded-md transition-all duration-150"
:class="activeTab === tab
? 'nav-tab-active'
: isDark
@@ -195,7 +195,7 @@
<button
v-for="tab in availableTabs"
:key="tab"
class="text-[10px] px-2.5 py-1.5 rounded-lg font-medium whitespace-nowrap transition-all duration-150"
class="text-xs px-2.5 py-1.5 rounded-lg font-medium whitespace-nowrap transition-all duration-150"
:class="activeTab === tab
? 'nav-tab-active'
: isDark
@@ -273,7 +273,7 @@
</svg>
Prev
</button>
<span class="text-[10px] font-mono tabular-nums"
<span class="text-xs font-mono tabular-nums"
:class="isDark ? 'text-white/25' : 'text-black/25'">
{{ currentContextIndex + 1 }}/{{ contextItems.length }}
</span>
@@ -10,12 +10,12 @@
</router-link>
<div class="flex-1 min-w-0">
<h1 class="text-sm font-semibold text-white/90 truncate">{{ title }}</h1>
<p class="text-[10px] text-white/40">
<p class="text-xs text-white/40">
<template v-if="authorName">by {{ authorName }}</template>
<template v-if="publishedAt"> · {{ formattedDate }}</template>
</p>
</div>
<span class="text-[10px] px-2 py-1 rounded-full bg-white/5 text-white/40">Read-only</span>
<span class="text-xs px-2 py-1 rounded-full bg-white/5 text-white/40">Read-only</span>
</div>
</header>
@@ -44,7 +44,7 @@
>
<div class="flex items-center gap-2 mb-2">
<span
class="text-[10px] font-bold uppercase tracking-wider"
class="text-xs font-bold uppercase tracking-wider"
:class="msg.role === 'user' ? 'text-accent/70' : 'text-white/30'"
>
{{ msg.role === 'user' ? 'Human' : 'Assistant' }}
@@ -59,7 +59,7 @@
<!-- Footer -->
<footer class="max-w-3xl mx-auto px-4 py-8 text-center">
<p class="text-[10px] text-white/20">
<p class="text-xs text-white/20">
Shared via AIUI · Powered by Nostr
</p>
</footer>