Primi prototipi nella pagina di appunti condivisi
This commit is contained in:
@@ -1,24 +1,212 @@
|
|||||||
import { render } from 'preact'
|
import { render } from 'preact'
|
||||||
import { useState } from 'preact/hooks'
|
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||||
|
|
||||||
const Counter = ({}) => {
|
function randomHex(length = 16) {
|
||||||
const [value, setValue] = useState(0)
|
return Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join('')
|
||||||
|
}
|
||||||
|
|
||||||
const increment = () => {
|
const useAutosizeTextarea = () => {
|
||||||
setValue(value => value + 1)
|
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('')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p>
|
<div class="input-tags" onClick={onFocus}>
|
||||||
Counter: {value} <button onClick={increment}>+</button>
|
{tags.map(tag => (
|
||||||
</p>
|
<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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
render(
|
const App = ({}) => {
|
||||||
<>
|
const descriptionTextareaProps = useAutosizeTextarea()
|
||||||
<h1>Preact is Working!</h1>
|
|
||||||
<Counter />
|
const [tags, setTags] = useState(['Geometria 1', 'Fortuna', 'Frigerio', '2013/2014'])
|
||||||
</>,
|
|
||||||
document.querySelector('#app')
|
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>
|
||||||
|
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(<App />, document.querySelector('#app'))
|
||||||
|
|||||||
+270
-1
@@ -511,6 +511,17 @@ button.icon {
|
|||||||
width: 2rem;
|
width: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.flat {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.flat:hover {
|
||||||
|
background: var(--bg-darker-2);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
font-family: var(--font-sf);
|
font-family: var(--font-sf);
|
||||||
font-weight: var(--font-weight-medium);
|
font-weight: var(--font-weight-medium);
|
||||||
@@ -539,7 +550,9 @@ select {
|
|||||||
/* Text Fields */
|
/* Text Fields */
|
||||||
|
|
||||||
input[type='text'],
|
input[type='text'],
|
||||||
input[type='password'] {
|
input[type='file'],
|
||||||
|
input[type='password'],
|
||||||
|
textarea {
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
|
|
||||||
@@ -560,6 +573,18 @@ input[type='password'] {
|
|||||||
font-weight: var(--font-weight-normal);
|
font-weight: var(--font-weight-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
height: unset;
|
||||||
|
min-height: 2rem;
|
||||||
|
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='file'] {
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
input[type='password'] {
|
input[type='password'] {
|
||||||
font-family: caption;
|
font-family: caption;
|
||||||
}
|
}
|
||||||
@@ -845,6 +870,250 @@ form .field-set input {
|
|||||||
height: calc(var(--size) * 1rem);
|
height: calc(var(--size) * 1rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Appunti Condivisi */
|
||||||
|
|
||||||
|
.page-appunti-condivisi .main {
|
||||||
|
padding: 0 1rem 6rem;
|
||||||
|
max-width: 100ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .upload-region {
|
||||||
|
padding: 2rem;
|
||||||
|
|
||||||
|
height: 30vh;
|
||||||
|
|
||||||
|
border: 2px dashed var(--bg-darker-4);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi #app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr minmax(auto, 50ch) auto;
|
||||||
|
|
||||||
|
background: var(--bg-dark);
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--bg-darker-2);
|
||||||
|
box-shadow: var(--shadow-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .pending {
|
||||||
|
color: royalblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .rejected {
|
||||||
|
color: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .header {
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .separator {
|
||||||
|
grid-column: span 4;
|
||||||
|
border-bottom: 1px solid var(--bg-darker-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .edit,
|
||||||
|
.page-appunti-condivisi .dispense-table .name,
|
||||||
|
.page-appunti-condivisi .dispense-table .tags,
|
||||||
|
.page-appunti-condivisi .dispense-table .status {
|
||||||
|
padding: 1rem 0 1rem 1rem;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .tags {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .status {
|
||||||
|
place-self: center;
|
||||||
|
|
||||||
|
padding: 1rem 1.25rem 1rem 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .expanded {
|
||||||
|
grid-column: span 4;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .edit-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
padding: 1rem 1rem 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .edit-close {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .edit-form {
|
||||||
|
display: grid;
|
||||||
|
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: 0.5rem 1rem;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .edit-form > .label {
|
||||||
|
height: 2rem;
|
||||||
|
|
||||||
|
align-self: flex-start;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .edit-form > textarea {
|
||||||
|
resize: vertical;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .dispense-table .edit-form > .right {
|
||||||
|
grid-column: span 2;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .input-tags {
|
||||||
|
padding: 0.5rem;
|
||||||
|
min-height: 2rem;
|
||||||
|
|
||||||
|
font-size: 17px;
|
||||||
|
|
||||||
|
background: var(--text-input-bg);
|
||||||
|
color: var(--fg);
|
||||||
|
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--bg-darker-2);
|
||||||
|
box-shadow: 0 0 8px 0 #00000020;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .input-tags .tag {
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
height: 1.5rem;
|
||||||
|
border-radius: calc(1.5rem / 2);
|
||||||
|
padding: 0 calc(1.5rem / 2);
|
||||||
|
|
||||||
|
background: var(--bg-darker-2);
|
||||||
|
color: var(--card-date);
|
||||||
|
|
||||||
|
font-size: 15px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .input-tags .tag .remove {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .input-tags .tag .remove:hover {
|
||||||
|
color: var(--card-content);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-appunti-condivisi .input-tags input[type='text'] {
|
||||||
|
box-shadow: none;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
height: 1.5rem;
|
||||||
|
|
||||||
|
min-height: unset;
|
||||||
|
max-width: 10rem;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animazioni */
|
||||||
|
|
||||||
|
/* Pending hourglass with a bit of overshoot */
|
||||||
|
/* @keyframes pending-rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
transform: rotate(-5deg);
|
||||||
|
}
|
||||||
|
45% {
|
||||||
|
transform: rotate(190deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: rotate(175deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate(185deg);
|
||||||
|
}
|
||||||
|
95% {
|
||||||
|
transform: rotate(370deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
@keyframes pending-rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes rotate {
|
@keyframes rotate {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ body.dark-mode {
|
|||||||
filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.4));
|
filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.4));
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark-mode input[type] {
|
.dark-mode input[type],
|
||||||
|
.dark-mode textarea {
|
||||||
background: #4b4342;
|
background: #4b4342;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,10 @@
|
|||||||
{{define "title"}}Condivisione Appunti • PHC{{end}}
|
{{define "title"}}Condivisione Appunti • PHC{{end}}
|
||||||
|
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<section>
|
<h1>
|
||||||
<h1>
|
<i class="fas fa-book"></i>
|
||||||
<i class="fas fa-book"></i>
|
Condivisione Appunti
|
||||||
Condivisione Appunti
|
</h1>
|
||||||
</h1>
|
<div id="app"></div>
|
||||||
<div id="app"></div>
|
|
||||||
</section>
|
|
||||||
<script src="/public/appunti-condivisi.min.js"></script>
|
<script src="/public/appunti-condivisi.min.js"></script>
|
||||||
{{end}}
|
{{end}}
|
||||||
Reference in New Issue
Block a user