ghostguild-org/app/components/OnboardingWidget.vue
Jennie Robinson Faber c6b970a621
Some checks failed
Test / vitest (push) Successful in 10m47s
Test / playwright (push) Failing after 9m11s
Test / visual (push) Failing after 9m11s
Test / Notify on failure (push) Successful in 2s
Design token updates.
2026-04-11 23:24:38 +01:00

147 lines
3.9 KiB
Vue

<template>
<ClientOnly>
<div v-if="!loading" class="onboarding-widget">
<!-- Welcome mode: onboarding in progress -->
<template v-if="!isComplete">
<div class="ow-prompt">&gt; welcome</div>
<div class="ow-message">You are in the <strong>Ghost Guild</strong>. A few passages remain unexplored.</div>
<div class="ow-hint">Next: {{ currentSuggestion.text }}</div>
<NuxtLink
v-if="currentSuggestion.action && !currentSuggestion.isExternal"
:to="currentSuggestion.action"
class="ow-action"
>
{{ currentSuggestion.actionText }} &rarr;
</NuxtLink>
<a
v-else-if="currentSuggestion.isExternal"
:href="currentSuggestion.action"
target="_blank"
rel="noopener"
class="ow-action"
@click="trackGoal('wikiClicked')"
>
{{ currentSuggestion.actionText }} &rarr;
</a>
<div class="ow-progress">
<span class="ow-bar"><span class="ow-bar-fill">{{ barFill }}</span><span class="ow-bar-empty">{{ barEmpty }}</span></span>
{{ completedCount }} of 4 explored
</div>
</template>
<!-- Suggestion mode: onboarding complete -->
<template v-else>
<!-- Empty state -->
<div v-if="currentSuggestion.key === 'empty'" class="ow-prompt">&gt; look</div>
<div v-if="currentSuggestion.key === 'empty'" class="ow-message ow-message--dim">{{ currentSuggestion.text }}</div>
<!-- Recommendation (event, ecology, or wiki) -->
<template v-if="currentSuggestion.key !== 'empty'">
<div class="ow-prompt">&gt; look</div>
<div class="ow-message">{{ currentSuggestion.text }}</div>
<a
v-if="currentSuggestion.isExternal && currentSuggestion.action"
:href="currentSuggestion.action"
target="_blank"
rel="noopener"
class="ow-action"
>
{{ currentSuggestion.actionText }} &rarr;
</a>
<NuxtLink
v-else-if="currentSuggestion.action"
:to="currentSuggestion.action"
class="ow-action"
>
{{ currentSuggestion.actionText }} &rarr;
</NuxtLink>
</template>
</template>
</div>
</ClientOnly>
</template>
<script setup>
const { goals, isComplete, currentSuggestion, trackGoal, loading } = useOnboarding()
const completedCount = computed(() => {
const g = goals.value
return [g.hasProfileTags, g.hasVisitedEvent, g.hasEngagedEcology, g.hasClickedWiki]
.filter(Boolean).length
})
const barFill = computed(() => '[' + '#'.repeat(completedCount.value * 2))
const barEmpty = computed(() => '-'.repeat((4 - completedCount.value) * 2) + ']')
</script>
<style scoped>
.onboarding-widget {
padding: 16px 20px;
border-bottom: 1px dashed var(--parch-border);
background: var(--parch);
color: var(--parch-text);
font-size: 12px;
line-height: 1.7;
}
.ow-prompt {
color: var(--parch-accent);
margin-bottom: 6px;
}
.ow-message {
color: var(--parch-text);
margin-bottom: 2px;
}
.ow-message--dim {
color: var(--parch-text-dim);
}
.ow-hint {
color: var(--parch-text-dim);
font-size: 11px;
}
.ow-action {
display: inline-block;
margin-top: 8px;
padding: 4px 12px;
border: 1px dashed rgba(237, 228, 208, 0.25);
color: var(--parch-accent);
font-size: 11px;
text-decoration: none;
letter-spacing: 0.04em;
}
.ow-action:hover {
border-color: var(--parch-accent);
border-style: solid;
text-decoration: none;
}
.ow-progress {
margin-top: 10px;
padding-top: 8px;
border-top: 1px dashed rgba(237, 228, 208, 0.12);
font-size: 11px;
color: var(--parch-text-dim);
display: flex;
align-items: center;
gap: 6px;
}
.ow-bar {
display: inline-flex;
gap: 0;
letter-spacing: 0;
}
.ow-bar-fill {
color: var(--parch-accent);
}
.ow-bar-empty {
color: rgba(237, 228, 208, 0.2);
}
</style>