Copy and layout improvements.
This commit is contained in:
parent
39eb9e039a
commit
02222a5c16
20 changed files with 464 additions and 652 deletions
|
|
@ -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">×</button>
|
||||
</span>
|
||||
<span v-if="peerSupportFilter === 'true'" class="af-tag">
|
||||
Offering Support
|
||||
<button type="button" @click="clearPeerSupportFilter">×</button>
|
||||
</span>
|
||||
<span v-for="slug in directoryCraftTags" :key="'c-' + slug" class="af-tag">
|
||||
{{ craftTagLabel(slug) }}
|
||||
<button type="button" @click="toggleDirectoryCraftTag(slug)">×</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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue