Copy and layout improvements.

This commit is contained in:
Jennie Robinson Faber 2026-04-16 21:11:05 +01:00
parent 39eb9e039a
commit 02222a5c16
20 changed files with 464 additions and 652 deletions

View file

@ -1,8 +1,5 @@
<template>
<PageShell
title="Members"
:subtitle="pageSubtitle"
>
<PageShell title="Members">
<!-- Filter Bar -->
<div class="filter-bar">
<input
@ -11,34 +8,25 @@
class="filter-search"
placeholder="Search members..."
@input="debouncedSearch"
/>
<select
v-model="selectedCircle"
class="filter-select"
@change="loadMembers"
>
<option
v-for="opt in circleOptions"
:key="opt.value"
:value="opt.value"
>
{{ opt.label }}
</option>
</select>
<label class="filter-toggle">
<input
type="checkbox"
:checked="peerSupportFilter === 'true'"
@change="togglePeerSupport"
/>
Offering support
</label>
<span class="filter-count">Showing {{ totalCount }} member{{ totalCount === 1 ? '' : 's' }} across 3 circles</span>
</div>
<!-- Tags Drawer Toggle -->
<div v-if="craftTagOptions.length > 0" class="tags-drawer-toggle">
<button type="button" class="drawer-btn" @click="showTagsDrawer = !showTagsDrawer">
<USelectMenu
v-model="selectedCircle"
:items="circleOptions"
value-key="value"
:search-input="false"
class="zine-select circle-select"
:ui="{
content: 'tz-content',
item: 'tz-item',
}"
@update:model-value="loadMembers"
/>
<button
v-if="craftTagOptions.length > 0"
type="button"
class="drawer-btn"
@click="showTagsDrawer = !showTagsDrawer"
>
Tags...
<span v-if="directoryCraftTags.length > 0" class="tag-count-badge">{{ directoryCraftTags.length }}</span>
</button>
@ -76,10 +64,6 @@
{{ circleLabels[selectedCircle] }}
<button type="button" @click="clearCircleFilter">&times;</button>
</span>
<span v-if="peerSupportFilter === 'true'" class="af-tag">
Offering Support
<button type="button" @click="clearPeerSupportFilter">&times;</button>
</span>
<span v-for="slug in directoryCraftTags" :key="'c-' + slug" class="af-tag">
{{ craftTagLabel(slug) }}
<button type="button" @click="toggleDirectoryCraftTag(slug)">&times;</button>
@ -108,7 +92,7 @@
:src="`/ghosties/Ghost-${capitalize(member.avatar)}.png`"
:alt="member.name"
class="mc-avatar-img"
/>
>
<span v-else>{{ getInitials(member.name) }}</span>
</div>
<div class="mc-info">
@ -130,16 +114,16 @@
v-if="member.bio"
class="mc-bio"
v-html="renderMarkdown(member.bio)"
></div>
/>
<div v-if="member.craftTags?.length > 0" class="mc-tags">
<span class="tag-label">Craft:</span>
<span
v-for="tag in member.craftTags.slice(0, 5)"
v-for="tag in member.craftTags.slice(0, 3)"
:key="tag"
class="skill-tag"
>{{ craftTagLabel(tag) }}</span>
<span v-if="member.craftTags.length > 5" class="tag-overflow">+{{ member.craftTags.length - 5 }}</span>
<span v-if="member.craftTags.length > 3" class="tag-overflow">+{{ member.craftTags.length - 3 }} more</span>
</div>
</div>
</div>
@ -159,7 +143,6 @@
<script setup>
definePageMeta({ middleware: ['members-auth'] })
const route = useRoute()
const { render: renderMarkdown } = useMarkdown()
// ---- Directory state ----
@ -168,7 +151,6 @@ const totalCount = ref(0)
const loading = ref(true)
const searchQuery = ref('')
const selectedCircle = ref('all')
const peerSupportFilter = ref('all')
const directoryCraftTags = ref([])
const craftTagOptions = ref([])
const showAllTags = ref(false)
@ -218,14 +200,9 @@ const visibleTagOptions = computed(() =>
const hasActiveFilters = computed(() =>
(selectedCircle.value && selectedCircle.value !== 'all') ||
peerSupportFilter.value === 'true' ||
directoryCraftTags.value.length > 0
)
const pageSubtitle = computed(() =>
`${totalCount.value} member${totalCount.value === 1 ? '' : 's'} across 3 circles`
)
// ---- Load members ----
const loadMembers = async () => {
loading.value = true
@ -233,7 +210,6 @@ const loadMembers = async () => {
const params = {}
if (searchQuery.value) params.search = searchQuery.value
if (selectedCircle.value && selectedCircle.value !== 'all') params.circle = selectedCircle.value
if (peerSupportFilter.value === 'true') params.peerSupport = 'true'
if (directoryCraftTags.value.length === 1) params.craftTag = directoryCraftTags.value[0]
const data = await $fetch('/api/members/directory', { params })
@ -266,11 +242,6 @@ const loadTagOptions = async () => {
}
// ---- Filter helpers ----
const togglePeerSupport = (e) => {
peerSupportFilter.value = e.target.checked ? 'true' : 'all'
loadMembers()
}
let searchTimeout
const debouncedSearch = () => {
clearTimeout(searchTimeout)
@ -294,15 +265,9 @@ const clearCircleFilter = () => {
loadMembers()
}
const clearPeerSupportFilter = () => {
peerSupportFilter.value = 'all'
loadMembers()
}
const clearAllFilters = () => {
searchQuery.value = ''
selectedCircle.value = 'all'
peerSupportFilter.value = 'all'
directoryCraftTags.value = []
showTagsDrawer.value = false
loadMembers()
@ -325,10 +290,6 @@ useHead({
// ---- Init ----
onMounted(async () => {
if (route.query.peerSupport === 'true') {
peerSupportFilter.value = 'true'
}
await loadTagOptions()
await loadMembers()
})
@ -363,51 +324,15 @@ onMounted(async () => {
border-color: var(--candle-faint);
}
.filter-select {
font-family: "Commit Mono", monospace;
font-size: 11px;
padding: 5px 10px;
border: 1px dashed var(--border);
background: transparent;
color: var(--text-dim);
cursor: pointer;
outline: none;
-webkit-appearance: none;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%238a7e6a' stroke-width='1.2'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 8px center;
padding-right: 26px;
}
.filter-select:focus {
border-color: var(--candle-faint);
}
.filter-toggle {
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
color: var(--text-dim);
cursor: pointer;
}
.filter-toggle input {
accent-color: var(--candle-dim);
}
.filter-count {
margin-left: auto;
font-size: 11px;
color: var(--text-faint);
/* Constrain the circle USelectMenu button width so it doesn't stretch. */
:deep(.circle-select) {
width: auto !important;
min-width: 150px;
}
/* ---- TAGS DRAWER ---- */
.tags-drawer-toggle {
padding: 8px 24px;
border-bottom: 1px dashed var(--border);
}
.drawer-btn {
margin-left: auto;
font-family: "Commit Mono", monospace;
font-size: 11px;
color: var(--text-dim);
@ -579,7 +504,7 @@ onMounted(async () => {
.mc-avatar {
width: 32px;
height: 32px;
background: var(--surface);
background: transparent;
display: flex;
align-items: center;
justify-content: center;
@ -720,15 +645,12 @@ onMounted(async () => {
align-items: stretch;
padding: 14px 20px;
}
.filter-count {
.drawer-btn {
margin-left: 0;
}
.skills-bar {
padding: 10px 20px;
}
.tags-drawer-toggle {
padding: 8px 20px;
}
.active-filters {
padding: 8px 20px;
}
@ -748,14 +670,5 @@ onMounted(async () => {
flex: 1 1 auto;
min-width: 0;
}
.filter-select {
flex: 1 1 45%;
}
.filter-toggle {
flex: 1 1 45%;
}
.filter-count {
flex-basis: 100%;
}
}
</style>