feat(demo): wire DemoBanner, WelcomeModal, HintChip into app + views

This commit is contained in:
pyr0ball 2026-04-15 20:57:29 -07:00
parent 51b7dbb29b
commit cd5bd80a2a
6 changed files with 50 additions and 18 deletions

View file

@ -7,10 +7,9 @@
<!-- Skip to main content link (screen reader / keyboard nav) --> <!-- Skip to main content link (screen reader / keyboard nav) -->
<a href="#main-content" class="skip-link">Skip to main content</a> <a href="#main-content" class="skip-link">Skip to main content</a>
<!-- Demo mode banner sticky top bar, visible on all pages --> <!-- Demo mode banner + welcome modal rendered when isDemo -->
<div v-if="config.isDemo" class="demo-banner" role="status" aria-live="polite"> <DemoBanner v-if="config.isDemo" />
👁 Demo mode changes are not saved and AI features are disabled. <WelcomeModal v-if="config.isDemo" />
</div>
<RouterView /> <RouterView />
@ -32,6 +31,8 @@ import { useHackerMode, useKonamiCode } from './composables/useEasterEgg'
import { useTheme } from './composables/useTheme' import { useTheme } from './composables/useTheme'
import { useToast } from './composables/useToast' import { useToast } from './composables/useToast'
import AppNav from './components/AppNav.vue' import AppNav from './components/AppNav.vue'
import DemoBanner from './components/DemoBanner.vue'
import WelcomeModal from './components/WelcomeModal.vue'
import { useAppConfigStore } from './stores/appConfig' import { useAppConfigStore } from './stores/appConfig'
import { useDigestStore } from './stores/digest' import { useDigestStore } from './stores/digest'
@ -128,20 +129,6 @@ body {
padding-bottom: 0; padding-bottom: 0;
} }
/* Demo mode banner — sticky top bar */
.demo-banner {
position: sticky;
top: 0;
z-index: 200;
background: var(--color-warning);
color: #1a1a1a; /* forced dark — warning bg is always light enough */
text-align: center;
font-size: 0.85rem;
font-weight: 600;
padding: 6px var(--space-4, 16px);
letter-spacing: 0.01em;
}
/* Global toast — bottom-center, above tab bar */ /* Global toast — bottom-center, above tab bar */
.global-toast { .global-toast {
position: fixed; position: fixed;

View file

@ -1,6 +1,11 @@
<template> <template>
<!-- Mobile: full-width list --> <!-- Mobile: full-width list -->
<div v-if="isMobile" class="apply-list"> <div v-if="isMobile" class="apply-list">
<HintChip
v-if="config.isDemo"
view-key="apply"
message="The Spotify cover letter is ready — open it to see how AI drafts from your resume"
/>
<header class="apply-list__header"> <header class="apply-list__header">
<h1 class="apply-list__title">Apply</h1> <h1 class="apply-list__title">Apply</h1>
<p class="apply-list__subtitle">Approved jobs ready for applications</p> <p class="apply-list__subtitle">Approved jobs ready for applications</p>
@ -124,6 +129,10 @@ import { ref, onMounted, onUnmounted } from 'vue'
import { RouterLink } from 'vue-router' import { RouterLink } from 'vue-router'
import { useApiFetch } from '../composables/useApi' import { useApiFetch } from '../composables/useApi'
import ApplyWorkspace from '../components/ApplyWorkspace.vue' import ApplyWorkspace from '../components/ApplyWorkspace.vue'
import HintChip from '../components/HintChip.vue'
import { useAppConfigStore } from '../stores/appConfig'
const config = useAppConfigStore()
// Responsive // Responsive

View file

@ -1,6 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { useApiFetch } from '../composables/useApi' import { useApiFetch } from '../composables/useApi'
import HintChip from '../components/HintChip.vue'
import { useAppConfigStore } from '../stores/appConfig'
const config = useAppConfigStore()
interface Contact { interface Contact {
id: number id: number
@ -79,6 +83,11 @@ onMounted(fetchContacts)
<template> <template>
<div class="contacts-view"> <div class="contacts-view">
<HintChip
v-if="config.isDemo"
view-key="contacts"
message="Peregrine logs every recruiter email automatically — no manual entry needed"
/>
<header class="contacts-header"> <header class="contacts-header">
<h1 class="contacts-title">Contacts</h1> <h1 class="contacts-title">Contacts</h1>
<span class="contacts-count" v-if="total > 0">{{ total }} total</span> <span class="contacts-count" v-if="total > 0">{{ total }} total</span>

View file

@ -1,5 +1,10 @@
<template> <template>
<div class="home"> <div class="home">
<HintChip
v-if="config.isDemo"
view-key="home"
message="Start in Job Review — 12 jobs are waiting for your verdict"
/>
<!-- Header --> <!-- Header -->
<header class="home__header"> <header class="home__header">
<div> <div>
@ -371,6 +376,10 @@ import { RouterLink } from 'vue-router'
import { useJobsStore } from '../stores/jobs' import { useJobsStore } from '../stores/jobs'
import { useApiFetch } from '../composables/useApi' import { useApiFetch } from '../composables/useApi'
import WorkflowButton from '../components/WorkflowButton.vue' import WorkflowButton from '../components/WorkflowButton.vue'
import HintChip from '../components/HintChip.vue'
import { useAppConfigStore } from '../stores/appConfig'
const config = useAppConfigStore()
const store = useJobsStore() const store = useJobsStore()

View file

@ -8,6 +8,10 @@ import { useApiFetch } from '../composables/useApi'
import InterviewCard from '../components/InterviewCard.vue' import InterviewCard from '../components/InterviewCard.vue'
import MoveToSheet from '../components/MoveToSheet.vue' import MoveToSheet from '../components/MoveToSheet.vue'
import CompanyResearchModal from '../components/CompanyResearchModal.vue' import CompanyResearchModal from '../components/CompanyResearchModal.vue'
import HintChip from '../components/HintChip.vue'
import { useAppConfigStore } from '../stores/appConfig'
const config = useAppConfigStore()
const router = useRouter() const router = useRouter()
const store = useInterviewsStore() const store = useInterviewsStore()
@ -347,6 +351,11 @@ function formatRejectionDate(job: PipelineJob): string {
<template> <template>
<div class="interviews-view"> <div class="interviews-view">
<HintChip
v-if="config.isDemo"
view-key="interviews"
message="Figma sent an offer — open it to see the hired outcome and post-hire feedback"
/>
<canvas ref="confettiCanvas" class="confetti-canvas" aria-hidden="true" /> <canvas ref="confettiCanvas" class="confetti-canvas" aria-hidden="true" />
<Transition name="toast"> <Transition name="toast">

View file

@ -1,5 +1,10 @@
<template> <template>
<div class="review"> <div class="review">
<HintChip
v-if="config.isDemo"
view-key="review"
message="Swipe right to approve, left to skip. One of these jobs is a ghost post — can you spot it?"
/>
<!-- Header --> <!-- Header -->
<header class="review__header"> <header class="review__header">
<div class="review__title-row"> <div class="review__title-row">
@ -214,6 +219,10 @@ import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { useReviewStore } from '../stores/review' import { useReviewStore } from '../stores/review'
import JobCardStack from '../components/JobCardStack.vue' import JobCardStack from '../components/JobCardStack.vue'
import HintChip from '../components/HintChip.vue'
import { useAppConfigStore } from '../stores/appConfig'
const config = useAppConfigStore()
const store = useReviewStore() const store = useReviewStore()
const route = useRoute() const route = useRoute()