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:
co-authored by
Claude Opus 4.6
parent
dde3859a2e
commit
b2fcc23623
@@ -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 }} × {{ 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>
|
||||
|
||||
Reference in New Issue
Block a user