
3D Extruded Buildings & Urban Footprints
Real-world 3D building extrusions with dynamic sunlight shadows, terrain DEM elevations, and pitch/bearing camera controls.
Culture Amp style company pulse and eNPS engagement survey results dashboard featuring executive KPI scorecards, department sentiment heatmaps, and priority engagement drivers with action items.
Also available for React ->$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/employee-pulse-survey-results.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/employee-pulse-survey-results.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/employee-pulse-survey-results.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/employee-pulse-survey-results.jsonnpx shadcn-vue@latest add @uipkge/employee-pulse-survey-resultsInstalls to:app/components/blocks/| Name | Type / Values | Default | Required |
|---|---|---|---|
class | HTMLAttributes['class'] | — | optional |
Type aliases exported from this item's source. Use these to shape the data you pass in.
PrimaryMetricinterface PrimaryMetric {
id: string
title: string
value: string
unit?: string
badgeText: string
badgeVariant: 'success' | 'secondary' | 'default' | 'outline' | 'warning'
detail: string
subtext: string
progress: number
icon: typeof TrendingUp
}DepartmentRowinterface DepartmentRow {
name: string
responseCount: string
participationRate: string
cultureValues: number
managementEffectiveness: number
workLifeBalance: number
compensationGrowth: number
enps: number
enpsFormatted: string
enpsRank: string
}DriverIteminterface DriverItem {
id: string
title: string
score: string
scoreValue: number
tag: string
impact: string
description: string
benchmarkDiff: string
}OpportunityIteminterface OpportunityItem {
id: string
title: string
score: string
scoreValue: number
statusBadge: string
statusVariant: 'warning' | 'default' | 'secondary'
owner: string
targetDate: string
actionSummary: string
}<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import {
AlertCircle,
Award,
FileDown,
HeartHandshake,
Lightbulb,
ShieldCheck,
TrendingUp,
Users,
Zap,
} from 'lucide-vue-next'
import { cn } from '@/lib/utils'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Progress } from '@/components/ui/progress'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
interface Props {
class?: HTMLAttributes['class']
}
const props = defineProps<Props>()
interface PrimaryMetric {
id: string
title: string
value: string
unit?: string
badgeText: string
badgeVariant: 'success' | 'secondary' | 'default' | 'outline' | 'warning'
detail: string
subtext: string
progress: number
icon: typeof TrendingUp
}
interface DepartmentRow {
name: string
responseCount: string
participationRate: string
cultureValues: number
managementEffectiveness: number
workLifeBalance: number
compensationGrowth: number
enps: number
enpsFormatted: string
enpsRank: string
}
interface DriverItem {
id: string
title: string
score: string
scoreValue: number
tag: string
impact: string
description: string
benchmarkDiff: string
}
interface OpportunityItem {
id: string
title: string
score: string
scoreValue: number
statusBadge: string
statusVariant: 'warning' | 'default' | 'secondary'
owner: string
targetDate: string
actionSummary: string
}
const primaryMetrics: PrimaryMetric[] = [
{
id: 'enps-score',
title: 'Employee Net Promoter Score',
value: '+54',
unit: 'eNPS',
badgeText: '+22 vs tech benchmark',
badgeVariant: 'success',
detail: '64% Promoters · 26% Passives · 10% Detractors',
subtext: 'Benchmark: +32 eNPS across peer tech scaleups',
progress: 77,
icon: TrendingUp,
},
{
id: 'engagement-index',
title: 'Overall Engagement Index',
value: '86%',
unit: 'Favorable',
badgeText: '+4% vs Q2',
badgeVariant: 'success',
detail: '86% Favorable · 10% Neutral · 4% Unfavorable',
subtext: '4.3 / 5.0 mean agreement across all survey items',
progress: 86,
icon: HeartHandshake,
},
{
id: 'participation-rate',
title: 'Survey Participation Rate',
value: '94%',
unit: '139 / 148',
badgeText: 'High Confidence',
badgeVariant: 'secondary',
detail: '94% across 5 active departments',
subtext: 'Statistically significant sample size (p < 0.01)',
progress: 94,
icon: Users,
},
{
id: 'retention-intent',
title: 'Intent to Stay 2+ Years',
value: '88%',
unit: 'Retention',
badgeText: '+6% vs Q2',
badgeVariant: 'success',
detail: '88% positive retention sentiment',
subtext: 'Low voluntary flight risk across engineering & product',
progress: 88,
icon: ShieldCheck,
},
]
const departments: DepartmentRow[] = [
{
name: 'Engineering',
responseCount: '46 / 48 responses',
participationRate: '96%',
cultureValues: 92,
managementEffectiveness: 88,
workLifeBalance: 84,
compensationGrowth: 74,
enps: 62,
enpsFormatted: '+62',
enpsRank: 'Top Quartile',
},
{
name: 'Product & Design',
responseCount: '28 / 30 responses',
participationRate: '93%',
cultureValues: 94,
managementEffectiveness: 91,
workLifeBalance: 82,
compensationGrowth: 76,
enps: 58,
enpsFormatted: '+58',
enpsRank: 'Top Quartile',
},
{
name: 'Marketing',
responseCount: '22 / 24 responses',
participationRate: '92%',
cultureValues: 89,
managementEffectiveness: 85,
workLifeBalance: 86,
compensationGrowth: 71,
enps: 48,
enpsFormatted: '+48',
enpsRank: 'Above Average',
},
{
name: 'Sales & GTM',
responseCount: '25 / 26 responses',
participationRate: '96%',
cultureValues: 86,
managementEffectiveness: 84,
workLifeBalance: 78,
compensationGrowth: 68,
enps: 45,
enpsFormatted: '+45',
enpsRank: 'Above Average',
},
{
name: 'Operations',
responseCount: '18 / 20 responses',
participationRate: '90%',
cultureValues: 90,
managementEffectiveness: 87,
workLifeBalance: 88,
compensationGrowth: 72,
enps: 52,
enpsFormatted: '+52',
enpsRank: 'Top Quartile',
},
]
const topDrivers: DriverItem[] = [
{
id: 'driver-1',
title: 'Psychological safety & peer collaboration',
score: '96% favorable',
scoreValue: 96,
tag: 'Highest Scored Driver',
impact: 'Highest correlation with company eNPS (+0.74 r)',
benchmarkDiff: '+14% vs tech benchmark',
description:
'Squads report high mutual trust, blameless incident reviews, and transparent pairing culture without fear of failure.',
},
{
id: 'driver-2',
title: 'Mission alignment & executive transparency',
score: '92% favorable',
scoreValue: 92,
tag: 'Core Driver',
impact: 'Strongest predictor of organizational retention',
benchmarkDiff: '+11% vs tech benchmark',
description:
'Bi-weekly all-hands, transparent financials, and crisp quarterly OKRs provide unequivocal clarity on company trajectory.',
},
{
id: 'driver-3',
title: 'Manager trust & day-to-day autonomy',
score: '90% favorable',
scoreValue: 90,
tag: 'Core Driver',
impact: 'Key catalyst for execution velocity & morale',
benchmarkDiff: '+9% vs tech benchmark',
description:
'Team members highlight minimal micromanagement, supportive weekly 1:1 coaching, and autonomy over technical decisions.',
},
]
const opportunityAreas: OpportunityItem[] = [
{
id: 'opp-1',
title: 'Clarity on promotion cycles and IC compensation bands',
score: '68% favorable',
scoreValue: 68,
statusBadge: 'Action plan active',
statusVariant: 'warning',
owner: 'People Ops & Total Rewards',
targetDate: 'Q4 2026 Rollout',
actionSummary:
'Publish transparent engineering & IC level matrices with defined salary bands, equity guidelines, and semi-annual calibration windows.',
},
{
id: 'opp-2',
title: 'Cross-functional roadmap visibility & tool sprawl',
score: '71% favorable',
scoreValue: 71,
statusBadge: 'Action plan active',
statusVariant: 'warning',
owner: 'Product Ops & Platform Squad',
targetDate: 'End of Q3',
actionSummary:
'Consolidate sprint tracking into unified Linear workspaces and establish bi-weekly cross-discipline demo showcases.',
},
{
id: 'opp-3',
title: 'Focus time & meeting cadence optimization',
score: '73% favorable',
scoreValue: 73,
statusBadge: 'Action plan active',
statusVariant: 'warning',
owner: 'Engineering Leadership Council',
targetDate: 'Active Trial',
actionSummary:
'Implement company-wide "No Meeting Wednesdays" and audit recurring status meetings in favor of asynchronous updates.',
},
]
const getScoreBadgeClass = (score: number) => {
if (score >= 80) {
return 'border-success/20 bg-success/10 text-success'
}
if (score >= 70) {
return 'border-warning/20 bg-warning/10 text-warning'
}
return 'border-destructive/20 bg-destructive/10 text-destructive'
}
</script>
<template>
<div data-uipkge data-slot="employee-pulse-survey-results" :class="cn('w-full space-y-6', props.class)">
<!-- Header Section -->
<Card class="border-border bg-card shadow-xs">
<CardContent class="p-6">
<div class="flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between">
<div class="space-y-1.5">
<div class="flex flex-wrap items-center gap-2.5">
<h2 class="text-foreground text-xl font-bold tracking-tight sm:text-2xl">
Company Pulse & eNPS Engagement Survey
</h2>
<Badge wrap variant="outline" class="font-mono text-xs"> Q3 2026 </Badge>
</div>
<p class="text-muted-foreground text-xs leading-relaxed sm:text-sm">
Q3 2026 Pulse Survey · 94% Participation Rate · 139 / 148 Responses
</p>
</div>
<div class="flex flex-wrap items-center gap-3">
<div
class="border-success/30 bg-success/10 text-success dark:text-foreground flex min-w-0 items-center gap-2 rounded-lg border px-3.5 py-2 shadow-xs"
>
<TrendingUp class="text-success size-4 shrink-0" />
<span class="text-sm font-bold tracking-tight tabular-nums">+54 eNPS · Excellent</span>
</div>
<Button variant="outline" size="sm" class="gap-2 shadow-xs">
<FileDown class="size-4" />
<span>Export Executive Summary</span>
</Button>
</div>
</div>
</CardContent>
</Card>
<!-- 4 Primary Engagement KPI Cards -->
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
<Card
v-for="metric in primaryMetrics"
:key="metric.id"
class="border-border bg-card hover:border-border/80 shadow-xs transition-colors"
>
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle class="text-muted-foreground text-xs font-medium">
{{ metric.title }}
</CardTitle>
<component :is="metric.icon" class="text-muted-foreground size-4" />
</CardHeader>
<CardContent class="space-y-3">
<div class="flex flex-wrap items-baseline justify-between gap-2">
<div class="flex items-baseline gap-1.5">
<span class="text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl">
{{ metric.value }}
</span>
<span v-if="metric.unit" class="text-muted-foreground text-xs font-medium">
{{ metric.unit }}
</span>
</div>
<Badge wrap :variant="metric.badgeVariant" class="text-xs font-medium tabular-nums">
{{ metric.badgeText }}
</Badge>
</div>
<div class="space-y-1.5">
<Progress :model-value="metric.progress" class="h-1.5 w-full" />
<div class="space-y-0.5 pt-0.5">
<p class="text-foreground text-xs leading-normal font-medium">{{ metric.detail }}</p>
<p class="text-muted-foreground text-xs leading-normal">{{ metric.subtext }}</p>
</div>
</div>
</CardContent>
</Card>
</div>
<!-- Department Sentiment Heatmap Table -->
<Card class="border-border bg-card shadow-xs">
<CardHeader class="pb-4">
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div>
<div class="flex min-w-0 items-center gap-2">
<CardTitle class="text-base font-semibold">Department Sentiment Heatmap</CardTitle>
<Badge wrap variant="outline" class="text-xs font-normal">5 Departments · 139 Responses</Badge>
</div>
<CardDescription class="mt-1 text-xs">
Culture Amp style multidimensional sentiment matrix mapped across key operational pillars.
</CardDescription>
</div>
<!-- Heatmap Legend -->
<div class="flex flex-wrap items-center gap-2 pt-1 text-xs sm:pt-0">
<span class="text-muted-foreground font-medium">Sentiment Scale:</span>
<div
class="border-success/20 bg-success/10 text-success flex items-center gap-1 rounded-md border px-2 py-0.5"
>
<span class="bg-success size-1.5 rounded-full" />
<span class="font-medium">Favorable (≥80%)</span>
</div>
<div
class="border-warning/20 bg-warning/10 text-warning flex items-center gap-1 rounded-md border px-2 py-0.5"
>
<span class="bg-warning size-1.5 rounded-full" />
<span class="font-medium">Moderate (70-79%)</span>
</div>
<div
class="border-destructive/20 bg-destructive/10 text-destructive flex items-center gap-1 rounded-md border px-2 py-0.5"
>
<span class="bg-destructive size-1.5 rounded-full" />
<span class="font-medium">Opportunity (<70%)</span>
</div>
</div>
</div>
</CardHeader>
<CardContent class="p-0">
<div class="border-border overflow-x-auto border-t">
<Table>
<TableHeader class="bg-muted/40">
<TableRow class="hover:bg-transparent">
<TableHead class="text-foreground w-60 text-xs font-semibold">
Department & Participation
</TableHead>
<TableHead class="text-foreground text-center text-xs font-semibold"> Culture & Values </TableHead>
<TableHead class="text-foreground text-center text-xs font-semibold">
Management Effectiveness
</TableHead>
<TableHead class="text-foreground text-center text-xs font-semibold"> Work-Life Balance </TableHead>
<TableHead class="text-foreground text-center text-xs font-semibold">
Compensation & Growth
</TableHead>
<TableHead class="text-foreground text-right text-xs font-semibold"> Overall eNPS Score </TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="dept in departments" :key="dept.name" class="hover:bg-muted/30">
<!-- Department Name & Sample -->
<TableCell class="py-3.5">
<div class="space-y-0.5">
<p class="text-foreground text-sm font-semibold">{{ dept.name }}</p>
<p class="text-muted-foreground text-xs tabular-nums">
{{ dept.responseCount }} ·
<span class="text-foreground font-medium">{{ dept.participationRate }}</span>
</p>
</div>
</TableCell>
<!-- Culture & Values -->
<TableCell class="py-3.5 text-center">
<div class="inline-flex flex-col items-center gap-1">
<div
:class="
cn(
'flex min-w-[72px] items-center justify-center rounded-md border px-3 py-1.5 text-xs font-bold tabular-nums shadow-xs',
getScoreBadgeClass(dept.cultureValues),
)
"
>
{{ dept.cultureValues }}%
</div>
</div>
</TableCell>
<!-- Management Effectiveness -->
<TableCell class="py-3.5 text-center">
<div class="inline-flex flex-col items-center gap-1">
<div
:class="
cn(
'flex min-w-[72px] items-center justify-center rounded-md border px-3 py-1.5 text-xs font-bold tabular-nums shadow-xs',
getScoreBadgeClass(dept.managementEffectiveness),
)
"
>
{{ dept.managementEffectiveness }}%
</div>
</div>
</TableCell>
<!-- Work-Life Balance -->
<TableCell class="py-3.5 text-center">
<div class="inline-flex flex-col items-center gap-1">
<div
:class="
cn(
'flex min-w-[72px] items-center justify-center rounded-md border px-3 py-1.5 text-xs font-bold tabular-nums shadow-xs',
getScoreBadgeClass(dept.workLifeBalance),
)
"
>
{{ dept.workLifeBalance }}%
</div>
</div>
</TableCell>
<!-- Compensation & Growth -->
<TableCell class="py-3.5 text-center">
<div class="inline-flex flex-col items-center gap-1">
<div
:class="
cn(
'flex min-w-[72px] items-center justify-center rounded-md border px-3 py-1.5 text-xs font-bold tabular-nums shadow-xs',
getScoreBadgeClass(dept.compensationGrowth),
)
"
>
{{ dept.compensationGrowth }}%
</div>
</div>
</TableCell>
<!-- Overall eNPS Score -->
<TableCell class="py-3.5 text-right">
<div class="flex flex-col items-end gap-1">
<div
class="border-success/30 bg-success/10 text-success text-success inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-bold tabular-nums"
>
<TrendingUp class="text-success size-3" />
<span>{{ dept.enpsFormatted }} eNPS</span>
</div>
<span class="text-muted-foreground text-xs font-normal">
{{ dept.enpsRank }}
</span>
</div>
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
</CardContent>
</Card>
<!-- Top Engagement Drivers & Action Items Card -->
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
<!-- Left Column: Top Engagement Drivers (Superpowers) -->
<Card class="border-border bg-card shadow-xs">
<CardHeader class="pb-4">
<div class="flex flex-wrap items-center justify-between gap-2">
<div class="space-y-1">
<div class="flex min-w-0 items-center gap-2">
<CardTitle class="text-base font-semibold">Top Engagement Drivers</CardTitle>
<Badge wrap variant="success" class="text-xs">Organizational Strengths</Badge>
</div>
<CardDescription class="text-xs">
Highest scored sentiment drivers providing outsized positive impact on overall eNPS.
</CardDescription>
</div>
<Award class="text-success size-5 shrink-0" />
</div>
</CardHeader>
<CardContent class="space-y-4">
<div
v-for="driver in topDrivers"
:key="driver.id"
class="bg-muted/30 border-border/80 space-y-2.5 rounded-lg border p-4 shadow-xs"
>
<div class="flex flex-wrap items-start justify-between gap-2">
<div class="space-y-1">
<div class="flex flex-wrap items-center gap-2">
<h4 class="text-foreground text-sm font-semibold">{{ driver.title }}</h4>
<Badge wrap variant="outline" class="text-xs font-normal">
{{ driver.tag }}
</Badge>
</div>
<p class="text-muted-foreground text-xs">{{ driver.impact }}</p>
</div>
<div
class="border-success/20 bg-success/10 text-success text-success flex shrink-0 items-center gap-1 rounded-md border px-2.5 py-1 text-xs font-bold tabular-nums"
>
<TrendingUp class="text-success size-3" />
<span>{{ driver.score }}</span>
</div>
</div>
<p class="text-muted-foreground text-xs leading-relaxed">
{{ driver.description }}
</p>
<div class="border-border/60 flex items-center justify-between border-t pt-2 text-xs">
<span class="text-muted-foreground">Peer Benchmark:</span>
<span class="text-success text-success font-semibold tabular-nums">
{{ driver.benchmarkDiff }}
</span>
</div>
</div>
</CardContent>
</Card>
<!-- Right Column: Priority Opportunity Areas & Action Items -->
<Card class="border-border bg-card shadow-xs">
<CardHeader class="pb-4">
<div class="flex flex-wrap items-center justify-between gap-2">
<div class="space-y-1">
<div class="flex min-w-0 items-center gap-2">
<CardTitle class="text-base font-semibold">Priority Opportunity Areas</CardTitle>
<Badge wrap variant="warning" class="text-xs">Active Remediation</Badge>
</div>
<CardDescription class="text-xs">
Key focus areas requiring leadership follow-through and documented action plans.
</CardDescription>
</div>
<Lightbulb class="text-warning size-5 shrink-0" />
</div>
</CardHeader>
<CardContent class="space-y-4">
<div
v-for="opp in opportunityAreas"
:key="opp.id"
class="bg-muted/30 border-border/80 space-y-2.5 rounded-lg border p-4 shadow-xs"
>
<div class="flex flex-wrap items-start justify-between gap-2">
<div class="space-y-1">
<h4 class="text-foreground text-sm font-semibold">{{ opp.title }}</h4>
<div class="flex flex-wrap items-center gap-2">
<Badge wrap variant="warning" class="text-xs font-medium">
{{ opp.statusBadge }}
</Badge>
<span class="text-muted-foreground text-xs">
Target: <strong class="text-foreground font-medium">{{ opp.targetDate }}</strong>
</span>
</div>
</div>
<div
class="border-warning/20 bg-warning/10 text-warning text-warning flex shrink-0 items-center gap-1 rounded-md border px-2.5 py-1 text-xs font-bold tabular-nums"
>
<AlertCircle class="text-warning size-3" />
<span>{{ opp.score }}</span>
</div>
</div>
<div class="bg-card/70 border-border/60 space-y-1 rounded-md border p-2.5">
<div class="text-foreground flex items-center gap-1 text-xs font-medium">
<Zap class="text-primary size-3 shrink-0" />
<span>Action Plan & Deliverables</span>
</div>
<p class="text-muted-foreground text-xs leading-relaxed">
{{ opp.actionSummary }}
</p>
</div>
<div class="border-border/60 flex items-center justify-between border-t pt-2 text-xs">
<span class="text-muted-foreground">Action Owner:</span>
<span class="text-foreground font-medium">
{{ opp.owner }}
</span>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
</template>
Raw manifest:https://uipkge.dev/r/vue/employee-pulse-survey-results.json