Primi prototipi nella pagina di appunti condivisi
parent
63ec0d559b
commit
8c4ed0b70e
@ -1,24 +1,212 @@
|
||||
import { render } from 'preact'
|
||||
import { useState } from 'preact/hooks'
|
||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||
|
||||
const Counter = ({}) => {
|
||||
const [value, setValue] = useState(0)
|
||||
function randomHex(length = 16) {
|
||||
return Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join('')
|
||||
}
|
||||
|
||||
const useAutosizeTextarea = () => {
|
||||
const [rows, setRows] = useState(1)
|
||||
|
||||
const onInput = e => {
|
||||
const lines = e.target.value.split('\n')
|
||||
console.log(lines)
|
||||
|
||||
setRows(lines.length)
|
||||
}
|
||||
|
||||
return { rows, onInput }
|
||||
}
|
||||
|
||||
const InputTags = ({ tags, setTags, availableTags }) => {
|
||||
availableTags ??= []
|
||||
|
||||
const [id] = useState('tags-' + randomHex())
|
||||
|
||||
const nextRef = useRef()
|
||||
const [nextText, setNextText] = useState('')
|
||||
|
||||
const onFocus = e => {
|
||||
if (!e.target.closest('.tags .tag .remove')) {
|
||||
nextRef.current?.focus()
|
||||
}
|
||||
}
|
||||
|
||||
const removeTag = tag => {
|
||||
setTags(tags => tags.filter(t => t !== tag))
|
||||
}
|
||||
|
||||
const addTag = tag => {
|
||||
setTags(tags => [...tags, tag])
|
||||
}
|
||||
|
||||
const onKeyDown = e => {
|
||||
if (e.key === 'Backspace' && nextText.length === 0) {
|
||||
removeTag(tags.at(-1))
|
||||
}
|
||||
|
||||
const trimmed = nextText.trim()
|
||||
if (e.key === 'Enter' && trimmed.length > 0) {
|
||||
addTag(trimmed)
|
||||
setNextText('')
|
||||
}
|
||||
}
|
||||
|
||||
const increment = () => {
|
||||
setValue(value => value + 1)
|
||||
return (
|
||||
<div class="input-tags" onClick={onFocus}>
|
||||
{tags.map(tag => (
|
||||
<div class="tag">
|
||||
<span>{tag}</span>
|
||||
<span class="remove" onClick={() => removeTag(tag)}>
|
||||
<i class="fa-solid fa-remove"></i>
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
<input
|
||||
type="text"
|
||||
ref={nextRef}
|
||||
list={id}
|
||||
value={nextText}
|
||||
onInput={e => setNextText(e.target.value)}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<datalist id={id}>
|
||||
{availableTags.map(({ id, label }) => (
|
||||
<option value={id} label={label} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const App = ({}) => {
|
||||
const descriptionTextareaProps = useAutosizeTextarea()
|
||||
|
||||
const [tags, setTags] = useState(['Geometria 1', 'Fortuna', 'Frigerio', '2013/2014'])
|
||||
|
||||
const availableTags = [
|
||||
...Array.from({ length: 10 }, (_, i) => {
|
||||
const year = new Date().getFullYear() - i
|
||||
|
||||
return { id: `${year}/${year + 1}`, label: `Anno Accademico ${year}/${year + 1}` }
|
||||
}),
|
||||
{ id: 'G1', label: 'Geometria 1' },
|
||||
{ id: 'G2', label: 'Geometria 2' },
|
||||
{ id: 'ETI', label: 'Elementi di Teoria degli Insiemi' },
|
||||
{ id: 'ETA', label: 'Elementi di Topologia Algebrica' },
|
||||
{ id: 'Analisi 1', label: 'Analisi 1' },
|
||||
{ id: 'Aritmetica', label: 'Aritmetica' },
|
||||
{ id: 'Programmazione', label: 'Programmazione' },
|
||||
{ id: 'Fisica 1', label: 'Fisica 1' },
|
||||
{ id: 'Steffe 1', label: 'Laboratorio di Comunicazione Mediante Calcolatore' },
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<div class="upload-region">
|
||||
<span>Trascina qui un PDF oppure usa il tasto sottostante</span>
|
||||
<button>Carica PDF</button>
|
||||
</div>
|
||||
<div class="dispense-table">
|
||||
<div class="edit header"></div>
|
||||
<div class="name header">Nome</div>
|
||||
<div class="tags header">Tags</div>
|
||||
<div class="status header">Stato</div>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<div class="edit">
|
||||
<button class="icon flat">
|
||||
<i class="fa-solid fa-angle-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="name">Appunti di Geometria 1</div>
|
||||
<div class="tags">
|
||||
<div class="tag">Geometria 1</div>
|
||||
<div class="tag">Prof. 1</div>
|
||||
<div class="tag">2016/2017</div>
|
||||
</div>
|
||||
<div class="status approved">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<div class="expanded">
|
||||
<div class="edit-close">
|
||||
<button class="icon flat">
|
||||
<i class="fa-solid fa-angle-up"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="edit-container">
|
||||
<p>
|
||||
Counter: {value} <button onClick={increment}>+</button>
|
||||
Qui puoi modificare le varie proprietà della dispensa, ricorda che se
|
||||
carichi un nuovo PDF diverso dal precedente dovrà essere nuovamente
|
||||
sottoposto a approvazione quindi inizialmente scomparirà dall'elenco
|
||||
principale.
|
||||
</p>
|
||||
<div class="edit-form">
|
||||
<div class="label">Nome</div>
|
||||
<input type="text" placeholder="Nome" value="Mezzedimi" />
|
||||
<div class="label">Descrizione</div>
|
||||
<textarea
|
||||
placeholder="Descrizione..."
|
||||
value="Best dispensa di Geometria 1 ever written anche se non in LaTeX"
|
||||
{...descriptionTextareaProps}
|
||||
></textarea>
|
||||
<div class="label">Tags</div>
|
||||
<InputTags {...{ tags, setTags, availableTags }} />
|
||||
<div class="label">PDF</div>
|
||||
<input type="file" value="/mezzedimi.pdf" accept="application/pdf" />
|
||||
|
||||
<div class="right">
|
||||
<button class="primary">Salva</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<div class="edit">
|
||||
<button class="icon flat">
|
||||
<i class="fa-solid fa-angle-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="name pending">Appunti di Geometria 2</div>
|
||||
<div class="tags">
|
||||
<div class="tag">Geometria 2</div>
|
||||
<div class="tag">Prof. 2</div>
|
||||
<div class="tag">2017/2018</div>
|
||||
<div class="tag">Tanti Tag</div>
|
||||
<div class="tag">Tanti Tag</div>
|
||||
<div class="tag">Tanti Tag</div>
|
||||
<div class="tag">Tanti Tag</div>
|
||||
<div class="tag">Tanti Tag</div>
|
||||
<div class="tag">Tanti Tag</div>
|
||||
</div>
|
||||
<div class="status pending" title="In attesa di approvazione...">
|
||||
<i class="fas fa-hourglass"></i>
|
||||
</div>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<div class="edit">
|
||||
<button class="icon flat">
|
||||
<i class="fa-solid fa-angle-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="name rejected">F1Le SuP3R LeGaLe</div>
|
||||
<div class="tags">
|
||||
<div class="tag">Foo</div>
|
||||
<div class="tag">Bar</div>
|
||||
</div>
|
||||
<div class="status rejected">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
render(
|
||||
<>
|
||||
<h1>Preact is Working!</h1>
|
||||
<Counter />
|
||||
</>,
|
||||
document.querySelector('#app')
|
||||
)
|
||||
render(<App />, document.querySelector('#app'))
|
||||
|
Loading…
Reference in New Issue