fiat combobox + happy utenti page uWu

dev
Francesco Minnocci 1 week ago
parent de28d3ad6e
commit 9a10fe1ff0

Binary file not shown.

@ -0,0 +1,60 @@
import { createContext, type ComponentChildren, type JSX } from 'preact'
import { useState, useRef, useEffect } from 'preact/hooks'
export const ComboBox = ({
value,
setValue,
children,
}: {
value: string
setValue: (s: string) => void
children: Record<string, ComponentChildren>
}) => {
const [cloak, setCloak] = useState(true)
const [open, setOpen] = useState(true)
const comboRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const handleClick = (e: MouseEvent) => {
if (comboRef.current && !comboRef.current.contains(e.target as Node)) {
setOpen(false)
}
}
document.addEventListener('mousedown', handleClick)
return () => document.removeEventListener('mousedown', handleClick)
}, [])
const [itemWidth, setItemWidth] = useState<number>(200)
useEffect(() => {
setOpen(false)
setCloak(false)
}, [])
return (
<div class="combobox" ref={comboRef} style={{ width: itemWidth + 48 + 'px' }}>
<div class="selected" onClick={() => setOpen(!open)}>
<div class="content">{children[value]}</div>
<span class="material-symbols-outlined">expand_more</span>
</div>
{open && (
<div
class={cloak ? 'dropdown invisible' : 'dropdown'}
ref={el => el && setItemWidth(el.offsetWidth)}
>
{Object.keys(children).map(key => (
<div
class="option"
onClick={() => {
setValue(key)
setOpen(false)
}}
>
{children[key]}
</div>
))}
</div>
)}
</div>
)
}

@ -2,12 +2,28 @@ import { effect, useComputed, useSignal } from '@preact/signals'
import Fuse from 'fuse.js'
import { useEffect } from 'preact/hooks'
import { ShowMore } from './Paginate'
import { ComboBox } from './ComboBox'
type User = {
uid: string
gecos: string
}
const FILTERS = {
utenti: {
icon: 'person',
label: 'Utenti',
},
macchinisti: {
icon: 'construction',
label: 'Macchinisti',
},
rappstud: {
icon: 'account_balance',
label: 'Rappresentanti',
},
}
function applyPatches(users: User[]) {
users.forEach(user => {
// strip ",+" from the end of the gecos field
@ -21,21 +37,25 @@ function applyPatches(users: User[]) {
users.reverse()
}
const MACCHINISTI = [
// Lista dei macchinisti attuali
'delucreziis',
'minnocci',
'baldino',
'mossa',
'manicastri',
'llombardo',
]
const MACCHINISTI = ['delucreziis', 'minnocci', 'baldino', 'manicastri', 'llombardo', 'serdyuk']
const RAPPSTUD = [
// Lista dei rappresentanti degli studenti attuali
'smannella',
'falcionella',
'piazza',
'lotti',
'rotolo',
'saccani',
'carbone',
'mburatti',
'ppuddu',
'marinari',
'evsilvestri',
'tateo',
'graccione',
'dilella',
'rocca',
'odetti',
'borso',
'numero',
]
export const UtentiPage = () => {
@ -80,20 +100,16 @@ export const UtentiPage = () => {
return (
<>
<div class="search-bar">
<div
class="filter-select"
onClick={e => {
e.currentTarget.querySelector('select')?.showPicker()
}}
>
<span class="material-symbols-outlined">filter_list</span>
<select onChange={e => ($filter.value = e.currentTarget.value)} value={$filter.value}>
<option value="utenti">Utenti</option>
<option value="macchinisti">Macchinisti</option>
<option value="rappstud">RappStud</option>
</select>
<span class="material-symbols-outlined">expand_more</span>
</div>
<ComboBox value={$filter.value} setValue={s => ($filter.value = s)}>
{Object.fromEntries(
Object.entries(FILTERS).map(([k, v]) => [
k,
<>
<span class="material-symbols-outlined">{v.icon}</span> {v.label}
</>,
]),
)}
</ComboBox>
<div class="search">
<input
type="text"
@ -110,7 +126,13 @@ export const UtentiPage = () => {
{poissonUser => (
<div class="search-result">
<div class="icon">
<span class="material-symbols-outlined">person</span>
<span class="material-symbols-outlined">
{RAPPSTUD.includes(poissonUser.uid)
? 'account_balance'
: MACCHINISTI.includes(poissonUser.uid)
? 'construction'
: 'person'}
</span>
</div>
<div class="text">{poissonUser.gecos}</div>
<div class="right">

@ -186,3 +186,24 @@ Varie sezioni del sito utilizzano diverse palette di colori. Questa è la palett
'var(--guide-lightest)',
]}
/>
## Combo Box
I combo box sono un componente per fare dropdown scritto in Preact. Questo è un esempio di come funzionano.
```js
import { ComboBox } from '$lib/components/ComboBox'
const [value, setValue] = useState('option-1')
```
```jsx
<ComboBox value={value} setValue={setValue}>
{{
'option-1': <>Option 1</>
'option-2': <>Option 2</>
'option-3': <>Option 3</>
}}
</ComboBox>
```

@ -608,7 +608,7 @@
gap: 1rem;
}
.filter-select {
/* .filter-select {
width: 100%;
height: 2.5rem;
@ -646,5 +646,63 @@
background: var(--filter-bg-color, #ddd);
}
} */
.combobox {
width: 100%;
height: 2.5rem;
position: relative;
padding: 0 0.25rem 0 0.25rem;
@include neo-brutalist-card;
cursor: pointer;
--filter-bg-color-hover: color-mix(in srgb, var(--filter-bg-color, #ddd), #000 10%);
background: var(--filter-bg-color, #ddd);
.material-symbols-outlined {
padding: 0 0.35rem;
}
.selected {
height: 100%;
gap: 0.25rem;
display: grid;
grid-auto-flow: column;
grid-template-columns: 1fr auto;
align-items: center;
.content {
display: grid;
grid-auto-flow: column;
align-items: center;
justify-content: start;
}
}
.dropdown {
position: absolute;
z-index: 10;
top: calc(100% + 8px);
left: -3px;
@include neo-brutalist-card;
background: #fff;
.option {
height: 2rem;
padding: 0 0.5rem 0 0.25rem;
display: grid;
grid-auto-flow: column;
align-items: center;
justify-content: start;
&:hover {
background: #ddd;
}
}
}
}
}

@ -184,3 +184,7 @@ body {
::selection {
background: #0002;
}
.invisible {
opacity: 0 !important;
}

@ -1,7 +1,7 @@
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"strict": false,
"strict": true,
"jsx": "react-jsx",
"jsxImportSource": "preact",
"strictNullChecks": true,

Loading…
Cancel
Save