That's the icon in the background.
This commit is contained in:
BIN
public/images/growth-symbol.png
Normal file
BIN
public/images/growth-symbol.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
@@ -58,8 +58,8 @@ const updateTextValue = (event) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="py-4">
|
||||
<p class="text-white mb-3">{{ question.text }}</p>
|
||||
<div class="py-5 first:pt-0">
|
||||
<p class="text-white font-medium leading-relaxed mb-4">{{ question.text }}</p>
|
||||
|
||||
<!-- Text-only question (no radio buttons) -->
|
||||
<div v-if="isTextOnly">
|
||||
@@ -67,7 +67,7 @@ const updateTextValue = (event) => {
|
||||
:value="modelValue.text_value"
|
||||
@input="updateTextValue"
|
||||
rows="3"
|
||||
class="w-full rounded-lg border border-gray-600 bg-surface px-3 py-2 text-white placeholder-gray-500 focus:border-primary focus:ring-1 focus:ring-primary"
|
||||
class="w-full rounded-lg border border-white/10 bg-white/5 px-4 py-3 text-white placeholder-gray-600 focus:border-primary/50 focus:ring-1 focus:ring-primary/20 transition-colors duration-200"
|
||||
placeholder="Enter your response..."
|
||||
></textarea>
|
||||
</div>
|
||||
@@ -83,18 +83,27 @@ const updateTextValue = (event) => {
|
||||
/>
|
||||
|
||||
<!-- Details textarea (conditional) -->
|
||||
<div v-if="showDetails" class="mt-2">
|
||||
<label class="block text-sm text-gray-400 mb-1">
|
||||
Details{{ detailsRequired ? ' (required)' : ' (optional)' }}
|
||||
</label>
|
||||
<textarea
|
||||
:value="modelValue.text_value"
|
||||
@input="updateTextValue"
|
||||
rows="2"
|
||||
class="w-full rounded-lg border border-gray-600 bg-surface px-3 py-2 text-white placeholder-gray-500 focus:border-primary focus:ring-1 focus:ring-primary text-sm"
|
||||
placeholder="Enter details..."
|
||||
></textarea>
|
||||
</div>
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-300 ease-out"
|
||||
enter-from-class="opacity-0 -translate-y-1 max-h-0"
|
||||
enter-to-class="opacity-100 translate-y-0 max-h-40"
|
||||
leave-active-class="transition-all duration-200 ease-in"
|
||||
leave-from-class="opacity-100 translate-y-0 max-h-40"
|
||||
leave-to-class="opacity-0 -translate-y-1 max-h-0"
|
||||
>
|
||||
<div v-if="showDetails" class="mt-2">
|
||||
<label class="block text-sm text-gray-400 mb-1">
|
||||
Details{{ detailsRequired ? ' (required)' : ' (optional)' }}
|
||||
</label>
|
||||
<textarea
|
||||
:value="modelValue.text_value"
|
||||
@input="updateTextValue"
|
||||
rows="2"
|
||||
class="w-full rounded-lg border border-white/10 bg-white/5 px-4 py-3 text-white placeholder-gray-600 focus:border-primary/50 focus:ring-1 focus:ring-primary/20 text-sm transition-colors duration-200"
|
||||
placeholder="Enter details..."
|
||||
></textarea>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -29,36 +29,29 @@ const handleChange = (value) => {
|
||||
const getSegmentClasses = (index) => {
|
||||
const classes = [
|
||||
'px-6',
|
||||
'py-3',
|
||||
'py-2.5',
|
||||
'text-sm',
|
||||
'font-medium',
|
||||
'select-none',
|
||||
'transition-colors',
|
||||
'bg-primary',
|
||||
'text-gray-900',
|
||||
'transition-all',
|
||||
'duration-200',
|
||||
'bg-white/5',
|
||||
'text-gray-400',
|
||||
'cursor-pointer',
|
||||
'hover:bg-primary-dark',
|
||||
'peer-checked:bg-primary-dark',
|
||||
'hover:bg-white/10',
|
||||
'hover:text-gray-200',
|
||||
'peer-checked:bg-primary',
|
||||
'peer-checked:text-gray-900',
|
||||
'peer-checked:font-semibold',
|
||||
'peer-focus-visible:ring-2',
|
||||
'peer-focus-visible:ring-primary-dark',
|
||||
'peer-focus-visible:ring-primary',
|
||||
'peer-focus-visible:ring-offset-2',
|
||||
'peer-focus-visible:ring-offset-surface',
|
||||
]
|
||||
|
||||
// First segment
|
||||
if (index === 0) {
|
||||
classes.push('rounded-l-lg')
|
||||
}
|
||||
|
||||
// Last segment
|
||||
if (index === props.options.length - 1) {
|
||||
classes.push('rounded-r-lg')
|
||||
}
|
||||
|
||||
// All except last: add divider
|
||||
if (index < props.options.length - 1) {
|
||||
classes.push('border-r', 'border-primary-dark/40')
|
||||
classes.push('border-r', 'border-white/10')
|
||||
}
|
||||
|
||||
// Disabled state
|
||||
@@ -71,7 +64,7 @@ const getSegmentClasses = (index) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div role="radiogroup" :aria-label="name" class="inline-flex">
|
||||
<div role="radiogroup" :aria-label="name" class="inline-flex rounded-lg overflow-hidden border border-white/10">
|
||||
<label
|
||||
v-for="(option, index) in options"
|
||||
:key="option.value"
|
||||
|
||||
@@ -43,20 +43,33 @@ const scoreData = computed(() => {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const panelBorderClass = computed(() => {
|
||||
if (props.score >= 10) return 'border-green-500/20'
|
||||
if (props.score >= 5) return 'border-amber-500/20'
|
||||
if (props.score >= 1) return 'border-red-500/20'
|
||||
return 'border-white/10'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="visible" class="inline-flex items-center gap-3">
|
||||
<div
|
||||
v-if="visible"
|
||||
class="inline-flex items-center gap-3 bg-white/5 backdrop-blur-sm border rounded-xl px-5 py-3 transition-all duration-500"
|
||||
:class="panelBorderClass"
|
||||
>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<span class="text-4xl font-bold" :class="scoreData.textClass">
|
||||
<span class="text-3xl font-bold" :class="scoreData.textClass">
|
||||
{{ score }}
|
||||
</span>
|
||||
<span class="text-sm text-gray-400">points</span>
|
||||
<span class="text-xs uppercase tracking-wider text-gray-500">
|
||||
points
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
scoreData.bgClass,
|
||||
'px-4 py-2 rounded-lg text-white font-semibold text-sm',
|
||||
'px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wider text-white shadow-sm',
|
||||
]"
|
||||
>
|
||||
{{ scoreData.label }}
|
||||
|
||||
@@ -13,7 +13,16 @@ const pageTitle = computed(() => {
|
||||
<template>
|
||||
<div class="min-h-screen flex flex-col">
|
||||
<PageHeader :title="pageTitle" />
|
||||
<main class="flex-1">
|
||||
|
||||
<!-- Growth symbol watermark -->
|
||||
<img
|
||||
src="/images/growth-symbol.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="fixed bottom-0 right-0 w-[600px] translate-x-[15%] translate-y-[15%] opacity-[0.03] pointer-events-none select-none z-0"
|
||||
/>
|
||||
|
||||
<main class="flex-1 relative z-10">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -100,66 +100,77 @@ const hasScoredAnswers = computed(() => {
|
||||
<template>
|
||||
<Head :title="`${session.category.name} Questionnaire`" />
|
||||
|
||||
<div class="max-w-4xl mx-auto px-4 py-8">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold text-white">{{ session.category.name }} Questionnaire</h1>
|
||||
<ScoreIndicator :score="score" :visible="hasScoredAnswers" />
|
||||
<div class="max-w-3xl mx-auto px-4 py-10">
|
||||
<!-- Title area -->
|
||||
<div class="mb-10">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-2xl font-bold text-white">{{ session.category.name }} Questionnaire</h1>
|
||||
<ScoreIndicator :score="score" :visible="hasScoredAnswers" />
|
||||
</div>
|
||||
<div class="h-px bg-gradient-to-r from-primary/40 via-primary/10 to-transparent mt-4"></div>
|
||||
</div>
|
||||
|
||||
<!-- User Info Section -->
|
||||
<div class="bg-surface/50 rounded-lg p-6 mb-6">
|
||||
<h2 class="text-xl font-semibold text-white mb-4">Basic Information</h2>
|
||||
<div class="space-y-8">
|
||||
<!-- User Info Section -->
|
||||
<div class="bg-white/[0.03] border border-white/[0.06] rounded-xl p-8">
|
||||
<h2 class="text-lg font-semibold text-white mb-5">Basic Information</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-400 mb-1">Name</span>
|
||||
<span class="text-white">{{ session.user.name }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-400 mb-1">Email</span>
|
||||
<span class="text-white">{{ session.user.email }}</span>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-400 mb-1">Name</span>
|
||||
<span class="text-white text-[15px]">{{ session.user.name }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-400 mb-1">Email</span>
|
||||
<span class="text-white text-[15px]">{{ session.user.email }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Question Groups -->
|
||||
<div
|
||||
v-for="group in questionGroups"
|
||||
:key="group.id"
|
||||
class="bg-surface/50 rounded-lg p-6 mb-6"
|
||||
>
|
||||
<h2 class="text-xl font-semibold text-white mb-1">{{ group.name }}</h2>
|
||||
<p v-if="group.description" class="text-gray-400 text-sm mb-2">{{ group.description }}</p>
|
||||
<p v-if="group.scoring_instructions" class="text-amber-400 text-sm italic mb-4">{{ group.scoring_instructions }}</p>
|
||||
<!-- Question Groups -->
|
||||
<div
|
||||
v-for="group in questionGroups"
|
||||
:key="group.id"
|
||||
class="bg-white/[0.03] border border-white/[0.06] rounded-xl p-8"
|
||||
>
|
||||
<div class="flex items-center gap-3 mb-1">
|
||||
<div class="w-2 h-2 rounded-full bg-primary/60"></div>
|
||||
<h2 class="text-lg font-semibold text-white">{{ group.name }}</h2>
|
||||
</div>
|
||||
<p v-if="group.description" class="text-gray-400 text-sm mb-2">{{ group.description }}</p>
|
||||
<p v-if="group.scoring_instructions" class="text-amber-400 text-sm italic mb-4">{{ group.scoring_instructions }}</p>
|
||||
|
||||
<div class="divide-y divide-gray-700">
|
||||
<QuestionCard
|
||||
v-for="question in group.questions"
|
||||
:key="question.id"
|
||||
:question="question"
|
||||
:modelValue="answerData[question.id]"
|
||||
@update:modelValue="updateAnswer(question.id, $event)"
|
||||
/>
|
||||
<div class="divide-y divide-white/[0.06]">
|
||||
<QuestionCard
|
||||
v-for="question in group.questions"
|
||||
:key="question.id"
|
||||
:question="question"
|
||||
:modelValue="answerData[question.id]"
|
||||
@update:modelValue="updateAnswer(question.id, $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Comments -->
|
||||
<div class="bg-surface/50 rounded-lg p-6 mb-6">
|
||||
<h2 class="text-xl font-semibold text-white mb-4">Additional Comments</h2>
|
||||
<textarea
|
||||
v-model="additionalComments.additional_comments"
|
||||
@input="saveComments"
|
||||
rows="4"
|
||||
class="w-full rounded-lg border border-gray-600 bg-surface px-3 py-2 text-white placeholder-gray-500 focus:border-primary focus:ring-1 focus:ring-primary"
|
||||
placeholder="Enter any additional comments to support your decision..."
|
||||
></textarea>
|
||||
<!-- Additional Comments -->
|
||||
<div class="bg-white/[0.03] border border-white/[0.06] rounded-xl p-8">
|
||||
<h2 class="text-lg font-semibold text-white mb-5">Additional Comments</h2>
|
||||
<textarea
|
||||
v-model="additionalComments.additional_comments"
|
||||
@input="saveComments"
|
||||
rows="4"
|
||||
class="w-full rounded-lg border border-white/10 bg-white/5 px-4 py-3 text-white placeholder-gray-600 focus:border-primary/50 focus:ring-1 focus:ring-primary/20 transition-colors duration-200"
|
||||
placeholder="Enter any additional comments to support your decision..."
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Complete button - now enabled -->
|
||||
<div class="flex justify-end mt-8">
|
||||
<AppButton size="lg" @click="completeSession" data-cy="complete-session">
|
||||
Complete
|
||||
</AppButton>
|
||||
<div class="mt-12 pt-8 border-t border-white/[0.06]">
|
||||
<div class="flex justify-end">
|
||||
<AppButton size="lg" @click="completeSession" data-cy="complete-session">
|
||||
Complete
|
||||
</AppButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user