feat: add Discover page — cypherpunk app store with sovereignty messaging
- New Discover.vue with hero banner, featured sovereignty stack apps, principle cards, manifesto footer, and full app grid - Featured apps (Bitcoin Knots, LND, BTCPay, Vaultwarden) with expanded privacy/sovereignty descriptions - Discover is first tab in categories bar on App Store pages - Smart back navigation: detail pages return to Discover when navigated from there - Category clicks from Discover navigate to Marketplace with category pre-selected - Cypherpunk aesthetic: terminal tags, scanline overlays, gradient accents, animated Bitcoin orange headings - Global CSS classes: discover-hero, discover-terminal-tag, discover-featured-card, discover-principle-card, discover-manifesto - Route added: /dashboard/discover Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
aabeb2e679
commit
5e19a80f9d
@@ -82,6 +82,10 @@
|
||||
<RouterLink to="/dashboard/apps?tab=services" class="mode-switcher-btn">Services</RouterLink>
|
||||
</div>
|
||||
<div class="mode-switcher flex-shrink-0">
|
||||
<RouterLink
|
||||
to="/dashboard/discover"
|
||||
class="mode-switcher-btn"
|
||||
>Discover</RouterLink>
|
||||
<button
|
||||
v-for="category in categoriesWithApps"
|
||||
:key="category.id"
|
||||
@@ -131,7 +135,8 @@
|
||||
:data-controller-install="!(isInstalled(app.id) || installingApps.has(app.id)) && (app.source === 'local' || !!app.dockerImage) ? '1' : undefined"
|
||||
tabindex="0"
|
||||
role="link"
|
||||
class="glass-card card-stagger p-6 hover:bg-white/10 transition-all cursor-pointer flex flex-col"
|
||||
class="glass-card p-6 hover:bg-white/10 transition-all cursor-pointer flex flex-col"
|
||||
:class="{ 'card-stagger': showStagger }"
|
||||
:style="{ '--stagger-index': index }"
|
||||
@click="viewAppDetails(app)"
|
||||
@keydown.enter="viewAppDetails(app)"
|
||||
@@ -365,9 +370,13 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
let marketplaceAnimationDone = false
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||
import { useRouter, RouterLink } from 'vue-router'
|
||||
import { useRouter, useRoute, RouterLink } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { rpcClient } from '@/api/rpc-client'
|
||||
@@ -378,13 +387,16 @@ import { useModalKeyboard } from '@/composables/useModalKeyboard'
|
||||
type MarketplaceApp = Partial<MarketplaceAppInfo> & { id: string; trustScore?: number; trustTier?: string; relayCount?: number }
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const store = useAppStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
const showStagger = !marketplaceAnimationDone
|
||||
const { setCurrentApp } = useMarketplaceApp()
|
||||
const appLauncher = useAppLauncherStore()
|
||||
|
||||
// Category state
|
||||
const selectedCategory = ref('all')
|
||||
// Category state — read initial value from query param (set by Discover page navigation)
|
||||
const selectedCategory = ref((route.query.category as string) || 'all')
|
||||
|
||||
const categories = computed(() => [
|
||||
{ id: 'all', name: t('marketplace.all') },
|
||||
@@ -721,6 +733,7 @@ function launchInstalledApp(app: MarketplaceApp) {
|
||||
|
||||
// Load community marketplace on mount
|
||||
onMounted(() => {
|
||||
marketplaceAnimationDone = true
|
||||
if (communityApps.value.length === 0 && !loadingCommunity.value) {
|
||||
loadCommunityMarketplace()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user