Skip to content

Commit 8fc85b6

Browse files
ryan-williamsclaude
andcommitted
Remove the UnitGrid experiment slide (unused)
Drops the standalone "Who gets hurt — by severity" slide and the `UnitGrid.vue` canvas component it was the sole consumer of. Both remain recoverable from history (`9f22aea`, `746c4f2`) if we revisit the unit-chart idea. `PersonIcon.vue` stays — slide 4's road-user selector still uses it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5854e3b commit 8fc85b6

2 files changed

Lines changed: 0 additions & 336 deletions

File tree

components/UnitGrid.vue

Lines changed: 0 additions & 145 deletions
This file was deleted.

slides.md

Lines changed: 0 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -721,194 +721,3 @@ class: thanks
721721
[ryanw@hudcostreets.org] · [hudcostreets.org](https://hudcostreets.org) · [@hudcostreets](https://instagram.com/hudcostreets)
722722

723723
Slides + source: [safe26.hccs.dev](https://safe26.hccs.dev)
724-
725-
---
726-
class: unitgrid-exp
727-
clicks: 0
728-
---
729-
730-
<script setup>
731-
import { computed, ref } from 'vue'
732-
733-
// Full-year (annualized) figures; the YTD toggle prorates these to today.
734-
const KSI = {
735-
killed: { driver: 301, passenger: 92, pedestrian: 173, cyclist: 16 },
736-
serious: { driver: 1977, passenger: 1001, pedestrian: 703, cyclist: 257 },
737-
moderate: { driver: 21249, passenger: 9545, pedestrian: 1840, cyclist: 1256 },
738-
minor: { driver: 26441, passenger: 12624, pedestrian: 1539, cyclist: 800 },
739-
}
740-
const TYPES = ['driver', 'passenger', 'pedestrian', 'cyclist']
741-
const TYPE_LABELS = { driver: 'Driver', passenger: 'Passenger', pedestrian: 'Ped', cyclist: 'Cyclist' }
742-
const COLORS = { driver: '#a94c9a', passenger: '#f08030', pedestrian: '#d85a6a', cyclist: '#7c5295' }
743-
const ROWS = [
744-
{ key: 'killed', label: 'Killed' },
745-
{ key: 'serious', label: 'Serious injury' },
746-
{ key: 'moderate', label: 'Moderate' },
747-
{ key: 'minor', label: 'Minor / other' },
748-
]
749-
750-
// Fraction of the calendar year elapsed (uniform proration).
751-
const now = new Date()
752-
const yStart = new Date(now.getFullYear(), 0, 1)
753-
const yEnd = new Date(now.getFullYear() + 1, 0, 1)
754-
const yearFrac = (now - yStart) / (yEnd - yStart)
755-
const asOf = now.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
756-
757-
const ytd = ref(false)
758-
const factor = computed(() => ytd.value ? yearFrac : 1)
759-
const scaledCounts = (key) => {
760-
const f = factor.value
761-
return Object.fromEntries(TYPES.map(t => [t, KSI[key][t] * f]))
762-
}
763-
764-
const selected = ref([...TYPES])
765-
const allSelected = () => TYPES.every(t => selected.value.includes(t))
766-
const isSel = (t) => selected.value.includes(t)
767-
function selectAll() { selected.value = [...TYPES] }
768-
function clickType(t) {
769-
if (allSelected()) { selected.value = [t]; return }
770-
const s = new Set(selected.value)
771-
s.has(t) ? s.delete(t) : s.add(t)
772-
if (s.size === 0 || s.size === TYPES.length) selectAll()
773-
else selected.value = TYPES.filter(x => s.has(x))
774-
}
775-
const rowTotal = (key) => Math.round(selected.value.reduce((sum, t) => sum + KSI[key][t], 0) * factor.value)
776-
</script>
777-
778-
<div class="exp-head">
779-
<h1>Who gets hurt — by severity <span class="exp-tag">experiment</span></h1>
780-
<div class="scope-toggle">
781-
<button :class="{ active: !ytd }" @mousedown.prevent @click="ytd = false">Annual</button>
782-
<button :class="{ active: ytd }" @mousedown.prevent @click="ytd = true">YTD · {{ asOf }}</button>
783-
</div>
784-
</div>
785-
786-
<div class="rows">
787-
<div class="urow" v-for="row in ROWS" :key="row.key">
788-
<div class="meta">
789-
<span class="n">{{ rowTotal(row.key).toLocaleString() }}</span>
790-
<span class="lab">{{ row.label }}</span>
791-
</div>
792-
<div class="box">
793-
<UnitGrid :counts="scaledCounts(row.key)" :colors="COLORS" :types="TYPES" :selected="selected" />
794-
</div>
795-
</div>
796-
</div>
797-
798-
<div class="vt-select">
799-
<button :class="{ active: allSelected() }" @mousedown.prevent @click="selectAll">All</button>
800-
<button
801-
v-for="t in TYPES"
802-
:key="t"
803-
:class="[t, { active: isSel(t) && !allSelected() }]"
804-
:title="TYPE_LABELS[t]"
805-
@mousedown.prevent
806-
@click="clickType(t)"
807-
><PersonIcon :type="t" /></button>
808-
</div>
809-
810-
<style>
811-
.slidev-layout.unitgrid-exp {
812-
padding: 1rem 2rem 0.8rem;
813-
display: flex;
814-
flex-direction: column;
815-
.exp-head {
816-
display: flex;
817-
align-items: center;
818-
justify-content: space-between;
819-
gap: 1rem;
820-
margin-bottom: 0.6rem;
821-
}
822-
h1 { font-size: 1.8rem; font-weight: 600; margin: 0; }
823-
.exp-tag {
824-
font-size: 0.8rem;
825-
font-weight: 400;
826-
opacity: 0.6;
827-
border: 1px solid rgba(255,255,255,0.4);
828-
border-radius: 999px;
829-
padding: 0.1rem 0.5rem;
830-
vertical-align: middle;
831-
}
832-
.scope-toggle {
833-
display: inline-flex;
834-
flex: 0 0 auto;
835-
border: 1px solid rgba(255,255,255,0.4);
836-
border-radius: 999px;
837-
overflow: hidden;
838-
button {
839-
font-family: inherit;
840-
font-size: 0.85rem;
841-
padding: 0.25rem 0.9rem;
842-
background: transparent;
843-
color: rgba(255,255,255,0.8);
844-
border: none;
845-
cursor: pointer;
846-
white-space: nowrap;
847-
}
848-
button.active { background: var(--hccs-accent); color: #14401f; font-weight: 600; }
849-
}
850-
.rows {
851-
flex: 1 1 auto;
852-
display: grid;
853-
grid-template-rows: repeat(4, 1fr);
854-
gap: 0.7rem;
855-
min-height: 0;
856-
}
857-
.urow {
858-
display: grid;
859-
grid-template-columns: 9rem 1fr;
860-
align-items: center;
861-
gap: 0.8rem;
862-
min-height: 0;
863-
}
864-
.meta {
865-
display: flex;
866-
flex-direction: column;
867-
align-items: flex-end;
868-
line-height: 1.05;
869-
}
870-
.meta .n { font-size: 1.5rem; font-weight: 700; color: var(--hccs-accent); font-variant-numeric: tabular-nums; }
871-
.meta .lab { font-size: 0.95rem; opacity: 0.9; }
872-
.box {
873-
height: 100%;
874-
min-height: 0;
875-
background: rgba(0,0,0,0.13);
876-
border-radius: 4px;
877-
}
878-
.vt-select {
879-
display: flex;
880-
flex-wrap: wrap;
881-
justify-content: center;
882-
align-items: center;
883-
gap: 0.4rem;
884-
margin-top: 0.7rem;
885-
button {
886-
display: inline-flex;
887-
align-items: center;
888-
justify-content: center;
889-
font-size: 0.85rem;
890-
padding: 0.2rem 0.55rem;
891-
border-radius: 999px;
892-
border: 1px solid rgba(255,255,255,0.55);
893-
background: rgba(255,255,255,0.92);
894-
color: #14401f;
895-
cursor: pointer;
896-
font-family: inherit;
897-
white-space: nowrap;
898-
}
899-
button .person-icon { width: 1.35em; height: 1.35em; }
900-
button.active { background: var(--hccs-accent); color: #14401f; border-color: var(--hccs-accent); font-weight: 600; }
901-
button.driver .person-icon { color: #a94c9a; }
902-
button.passenger .person-icon { color: #f08030; }
903-
button.pedestrian .person-icon { color: #d85a6a; }
904-
button.cyclist .person-icon { color: #7c5295; }
905-
button.driver.active { background: #a94c9a; border-color: #a94c9a; color: #fff; }
906-
button.passenger.active { background: #f08030; border-color: #f08030; color: #14401f; }
907-
button.pedestrian.active { background: #d85a6a; border-color: #d85a6a; color: #fff; }
908-
button.cyclist.active { background: #7c5295; border-color: #7c5295; color: #fff; }
909-
button.active .person-icon { color: inherit; }
910-
}
911-
}
912-
</style>
913-
914-
[ryanw@hudcostreets.org]: mailto:ryanw@hudcostreets.org

0 commit comments

Comments
 (0)