From 64200cd6548c7b3ea8f841fc27b7b56596ede853 Mon Sep 17 00:00:00 2001 From: Antonio De Lucreziis Date: Wed, 31 Aug 2022 01:22:08 +0200 Subject: [PATCH] Ulteriori aggiunte al prototipo della pagina Appunti Condivisi --- _frontend/rollup.config.js | 5 +- _frontend/src/appunti-condivisi.jsx | 212 --------- _frontend/src/appunti-condivisi/main.jsx | 526 +++++++++++++++++++++++ _frontend/src/appunti-condivisi/util.js | 17 + _public/style.css | 400 +++++++++++++++-- server/fiber.go | 6 +- 6 files changed, 912 insertions(+), 254 deletions(-) delete mode 100644 _frontend/src/appunti-condivisi.jsx create mode 100644 _frontend/src/appunti-condivisi/main.jsx create mode 100644 _frontend/src/appunti-condivisi/util.js diff --git a/_frontend/rollup.config.js b/_frontend/rollup.config.js index 2291d86..d8ca62e 100644 --- a/_frontend/rollup.config.js +++ b/_frontend/rollup.config.js @@ -49,7 +49,7 @@ export default defineConfig([ plugins: [esbuild({ minify: true })], }, { - input: 'src/appunti-condivisi.jsx', + input: 'src/appunti-condivisi/main.jsx', output: { file: 'out/appunti-condivisi.min.js', format: 'iife', @@ -68,7 +68,8 @@ export default defineConfig([ ], ], }), - terser(), + // https://rollupjs.org/guide/en/#-w--watch + !process.env.ROLLUP_WATCH && terser(), ], }, ]) diff --git a/_frontend/src/appunti-condivisi.jsx b/_frontend/src/appunti-condivisi.jsx deleted file mode 100644 index 0e5142c..0000000 --- a/_frontend/src/appunti-condivisi.jsx +++ /dev/null @@ -1,212 +0,0 @@ -import { render } from 'preact' -import { useEffect, useRef, useState } from 'preact/hooks' - -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('') - } - } - - return ( -
- {tags.map(tag => ( -
- {tag} - removeTag(tag)}> - - -
- ))} - setNextText(e.target.value)} - onKeyDown={onKeyDown} - /> - - {availableTags.map(({ id, label }) => ( - -
- ) -} - -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 ( - <> -
- Trascina qui un PDF oppure usa il tasto sottostante - -
-
-
-
Nome
-
Tags
-
Stato
- -
- -
- -
-
Appunti di Geometria 1
-
-
Geometria 1
-
Prof. 1
-
2016/2017
-
-
- -
- -
- -
-
- -
-
-

- 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. -

-
-
Nome
- -
Descrizione
- -
Tags
- -
PDF
- - -
- -
-
-
-
- -
- -
- -
-
Appunti di Geometria 2
-
-
Geometria 2
-
Prof. 2
-
2017/2018
-
Tanti Tag
-
Tanti Tag
-
Tanti Tag
-
Tanti Tag
-
Tanti Tag
-
Tanti Tag
-
-
- -
- -
- -
- -
-
F1Le SuP3R LeGaLe
-
-
Foo
-
Bar
-
-
- -
-
- - ) -} - -render(, document.querySelector('#app')) diff --git a/_frontend/src/appunti-condivisi/main.jsx b/_frontend/src/appunti-condivisi/main.jsx new file mode 100644 index 0000000..e5fcb13 --- /dev/null +++ b/_frontend/src/appunti-condivisi/main.jsx @@ -0,0 +1,526 @@ +import { render } from 'preact' +import { useCallback, useEffect, useRef, useState } from 'preact/hooks' +import { formatFileSize, intersperse } from './util.js' + +function randomHex(length = 16) { + return Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join('') +} + +/** + * Lista di tag "standard" disponibili nel completamento per i tags + */ +const availableTags = [ + // Genera una ventina di coppie come "2022/2023" + ...Array.from({ length: 20 }, (_, i) => { + const year = new Date().getFullYear() - i + + return { id: `${year}/${year + 1}`, label: `Anno Accademico ${year}/${year + 1}` } + }), + // List di tag "standard", l'id è la vera stringa del tag, mentre la label + { id: 'geometria-1', label: 'Geometria 1' }, + { id: 'geometria-2', label: 'Geometria 2' }, + { id: 'eti', label: 'Elementi di Teoria degli Insiemi' }, + { id: 'eta', label: 'Elementi di Topologia Algebrica' }, + { id: 'ega', label: 'Elementi di Geometria Algebrica' }, + { id: 'gtd', label: 'Geometria e Topologia Differenziale' }, + { id: 'ist-anal', label: 'Istituzioni di Analisi' }, + { id: 'ist-geom', label: 'Istituzioni di Geometria' }, + { id: 'ist-fis', label: 'Istituzioni di Fisica' }, + { id: 'ist-prob', label: 'Istituzioni di Probabilità' }, + { id: 'ist-alg', label: 'Istituzioni di Algebra' }, + { id: 'ist-num', label: 'Istituzioni di Analisi Numerica' }, + { id: 'analisi-1', label: 'Analisi 1' }, + { id: 'analisi-2', label: 'Analisi 2' }, + { id: 'aritmetica', label: 'Aritmetica' }, + { id: 'programmazione', label: 'Programmazione' }, + { id: 'fisica-1', label: 'Fisica 1' }, + { id: 'steffe-1', label: 'Laboratorio di Comunicazione Mediante Calcolatore' }, +] + +const useAutosizeTextarea = ({ minRows } = {}) => { + minRows ??= 1 + + const textareaRef = useRef(null) + + const updateTextareaHeight = useCallback(() => { + if (textareaRef.current) { + textareaRef.current.style.height = 'auto' + textareaRef.current.style.height = textareaRef.current.scrollHeight + 'px' + } + }) + + useEffect(() => { + updateTextareaHeight() + }) + + return { + rows: minRows, + ref: textareaRef, + onInput: updateTextareaHeight, + } +} + +const normalizeTag = tag => { + return tag + .toLowerCase() + .replace(/\s+/g, ' ') + .replace(/ /g, '-') + .replace(/[^\p{L}0-9\/\-]/gu, '') +} + +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(normalizeTag(trimmed)) + setNextText('') + } + } + + return ( +
+ {tags.map(tag => ( +
+ {tag} + removeTag(tag)}> + + +
+ ))} + setNextText(e.target.value)} + onKeyDown={onKeyDown} + /> + + {availableTags.map(({ id, label }) => ( + +
+ ) +} + +const withClasses = a => { + if (Array.isArray(a)) { + return { class: a.filter(className => !!className).join(' ') } + } else if (typeof a === 'object') { + return { + class: Object.entries(a) + .flatMap(([className, active]) => (active ? [className] : [])) + .join(' '), + } + } else if (typeof a === 'string') { + return { class: a } + } else { + throw new Error(`Invalid class format`) + } +} + +const UploadRegion = ({}) => { + const [draggingOver, setDraggingOver] = useState(false) + + const onDragOver = e => { + e.preventDefault() + e.dataTransfer.dropEffect = 'move' + + setDraggingOver(true) + } + + const onDragLeave = () => { + setDraggingOver(false) + } + + const onDropFiles = files => { + if (files.length !== 1) { + throw new Error('Must drop one file') + } + + const [file] = files + console.dir(file) + + if (file.type !== 'application/pdf') { + console.error('The file must be a PDF') + } + + console.log(formatFileSize(file.size)) + } + + const onDrop = e => { + e.preventDefault() + + if (e.dataTransfer.items) { + onDropFiles( + [...e.dataTransfer.items].flatMap(item => + item.kind === 'file' ? [item.getAsFile()] : [] + ) + ) + } else { + onDropFiles([...e.dataTransfer.files]) + } + + setDraggingOver(false) + } + + return ( +
+ {!draggingOver ? ( + <> + Trascina qui un PDF oppure usa il tasto sottostante + + + ) : ( + <> +
+ + Rilascia per iniziare il caricamento +
+ + )} +
+ ) +} + +const Progress = ({ value, max }) => { + return ( +
+
+
+ ) +} + +const CancellableUpload = ({ uploadedSize, totalSize, onCancel }) => { + return ( + <> +
+ {formatFileSize(uploadedSize)} / {formatFileSize(totalSize)} +
+
+ + +
+ + ) +} + +const UploadPopup = ({}) => { + const [shown, setShown] = useState(false) + + const descriptionTextareaProps = useAutosizeTextarea({ minRows: 2 }) + const [tags, setTags] = useState(['geometria-1', 'fortuna', 'frigerio', '2013/2014']) + + const [doneUploading, setDoneUploading] = useState(false) + + const hash = '59e514dd50c63051' + + return ( + <> + {shown && ( +
+ +
+ )} + + ) +} + +const InputFile = ({ accept, onFile }) => { + const inputFileRef = useRef() + + const [file, setFile] = useState(null) + + const onButtonClick = e => { + inputFileRef.current.click() + } + + const onInputFile = e => { + if (e.target.files.length === 1) { + const f = e.target.files[0] + + setFile(f) + onFile?.(f) + } + } + + return ( +
+ + + {file &&
{file.name}
} +
+ ) +} + +const TabellaApprovazioni = ({ pendingApprovazioni }) => { + return ( +
+
+
PDF (Hash)
+
Dispensa
+
Proprietario
+
Azioni
+ + {intersperse( + pendingApprovazioni.map(({ id, title, owner, hash }) => ( + <> +
+ + + +
+
+ {hash} +
+ +
+ @{owner} +
+
+ + +
+ + )), +
+ )} +
+ ) +} + +const App = ({}) => { + const descriptionTextareaProps = useAutosizeTextarea({ minRows: 2 }) + + const [tags, setTags] = useState(['geometria-1', 'fortuna', 'frigerio', '2013/2014']) + + return ( + <> + + + +
+

Le tue dispense

+
+
+
Nome
+
Tags
+
Stato
+ +
+ +
+
Appunti di Geometria 1
+
+
geometria-1
+
prof-1
+
2016/2017
+
+
+ +
+ +
+ +
+
+ +
+
+ +
+
Nome
+ +
Descrizione
+ +
Tags
+ +
+

+ Puoi anche caricare una nuova versione del PDF ma ricorda che se + carichi un file non precedentemente approvato inizialmente + scomparirà dall'elenco principale in attesa di apporvazione da parte + di un moderatore. +

+
+
Stato
+
+ + Approvata +
+ +
Cambia PDF
+ + +
+ +
+
+
+
+ +
+ +
+ +
+
Appunti di Geometria 2
+
+
geometria-2
+
prof-2
+
2017/2018
+
tanti-tag-1
+
tanti-tag-2
+
tanti-tag-3
+
tanti-tag-4
+
tanti-tag-5
+
tanti-tag-6
+
+
+ +
+ +
+ +
+ +
+
F1Le SuP3R LeGaLe
+
+
foo
+
bar
+
+
+ +
+
+
+
+

PDF da Approvare

+ +
+ + ) +} + +render(, document.querySelector('#app')) diff --git a/_frontend/src/appunti-condivisi/util.js b/_frontend/src/appunti-condivisi/util.js new file mode 100644 index 0000000..60a0c80 --- /dev/null +++ b/_frontend/src/appunti-condivisi/util.js @@ -0,0 +1,17 @@ +export function formatFileSize(bytes) { + if (bytes < 1024) { + return `${bytes} bytes` + } + if (bytes < 1024 ** 2) { + return `${(bytes / 1024).toFixed(1)} KB` + } + if (bytes < 1024 ** 3) { + return `${(bytes / 1024 ** 2).toFixed(1)} MB` + } + + return `${(bytes / 1024 ** 3).toFixed(1)} GB` +} + +export function intersperse(list, separator) { + return list.flatMap((el, i) => (i === 0 ? [el] : [separator, el])) +} diff --git a/_public/style.css b/_public/style.css index 0652002..de8a436 100644 --- a/_public/style.css +++ b/_public/style.css @@ -5,10 +5,12 @@ --bg: #eaeaea; --fg: #333; + --fg-lighter: #444; + --bg-lighter: #f0f0f0; - --bg-dark: hsl(220, 5%, 93%); - --bg-darker: hsl(220, 5%, 90%); + --bg-dark: #ecedee; + --bg-darker: #e4e5e7; --bg-darker-2: #d5d5d5; --bg-darker-2-1: #c8c8c8; --bg-darker-3: #c0c0c0; @@ -36,6 +38,8 @@ --accent-2: #4eaa59; --accent-2-darker: #2e974c; --accent-2-darkest: #002d0d; + + --accent-mix-bg: #dae4db; } * { @@ -420,6 +424,11 @@ hr { background-color: var(--bg-darker-2); } +sub, +sup { + font-size: 12px; +} + pre { margin: 0.5rem 0; @@ -445,6 +454,74 @@ p.center { /* Controls */ +.progress-bar { + background: var(--bg-darker-2-1); + color: var(--fg); + border-radius: 4px; + border: 1px solid var(--bg-darker-2); + box-shadow: 0 0 8px 0 #00000020, inset 0 0 8px 0 #00000030; + + overflow: hidden; + + height: 2rem; +} + +.progress-bar .indicator { + border-radius: 4px; + + height: 100%; + background: linear-gradient(to top, var(--accent-1), var(--accent-2)); + + position: relative; + + overflow: hidden; + + animation: test-progressbar 2s ease-in-out infinite; +} + +@keyframes test-progressbar { + 0% { + width: 0%; + } + 100% { + width: 100%; + } +} + +.progress-bar .indicator::after { + content: ''; + position: absolute; + inset: 0; + + /* background-size: 50px 50px; + + --highlight: rgba(255, 255, 255, 0.1); + + background-image: linear-gradient( + -45deg, + transparent 0%, + var(--highlight) 5%, + var(--highlight) 25%, + transparent 30%, + transparent 50%, + var(--highlight) 55%, + var(--highlight) 75%, + transparent 80%, + transparent 100% + ); + + animation: move 4s linear infinite; */ +} + +@keyframes move { + 0% { + background-position: 0 0; + } + 100% { + background-position: 50px 50px; + } +} + a:not(.button) { color: var(--accent-1-fg); font-weight: var(--font-weight-medium); @@ -464,7 +541,7 @@ a.button { button, .button { - display: inline-block; + display: flex; font-family: var(--font-sf); font-weight: var(--font-weight-medium); @@ -488,6 +565,9 @@ button, box-shadow: 0 4px 8px 0 #00000022; cursor: pointer; + + align-items: center; + justify-content: center; } button:hover, @@ -496,17 +576,20 @@ button:hover, box-shadow: 0 4px 8px 0 #00000033; } -button.primary { +button.primary, +.button.primary { border: 1px solid var(--accent-2-darker); background: var(--accent-2); color: var(--accent-2-darkest); } -button.primary:hover { +button.primary:hover, +.button.primary:hover { background: var(--accent-2-lighter); } -button.icon { +button.icon, +.button.icon { padding: 0; width: 2rem; } @@ -556,8 +639,8 @@ textarea { border: none; background: none; - height: 2rem; - padding: 0 0.5rem; + height: 2.25rem; + padding: 0.25rem 0.5rem; font-size: 17px; @@ -574,15 +657,14 @@ textarea { } textarea { - height: unset; + height: auto; min-height: 2rem; - padding: 0.5rem; + line-height: 1.5; } input[type='file'] { - padding: 0.25rem 0.5rem; - height: unset; + padding: 0.5rem; } input[type='password'] { @@ -602,6 +684,21 @@ input[type='password'].error { color: #311; } +/* Better File Input */ + +.input-file { + display: flex; + + align-items: center; + + gap: 0.5rem; +} + +.input-file > input[type='file'] { + position: fixed; + top: -100px; +} + /* Compound Controls */ .compound { @@ -873,16 +970,17 @@ form .field-set input { /* Appunti Condivisi */ .page-appunti-condivisi .main { - padding: 0 1rem 6rem; - max-width: 100ch; + padding: 0 1rem inherit; + max-width: 95ch; } .page-appunti-condivisi .upload-region { padding: 2rem; + width: 30rem; height: 30vh; - border: 2px dashed var(--bg-darker-4); + border: 3px dashed var(--bg-darker-4); border-radius: 0.5rem; display: flex; @@ -892,6 +990,128 @@ form .field-set input { flex-direction: column; gap: 1rem; + + transition: border-color 150ms ease-in-out, background-color 150ms ease-in-out; +} + +.page-appunti-condivisi .upload-region.dragging-over { + border-color: var(--accent-1); + color: var(--accent-1-fg); + + background: var(--accent-mix-bg); +} + +/* Serve altrimenti l'evento dropleave viene emesso anche quando si passa da ".upload-region" ad uno dei figli, così invece rendiamo tutti i figli trasparenti agli eventi del mouse */ +.page-appunti-condivisi .upload-region.dragging-over * { + pointer-events: none; +} + +.page-appunti-condivisi .upload-region.dragging-over .release-text { + display: flex; + gap: 0.5rem; + + font-size: 22px; + font-weight: var(--font-weight-medium); +} + +.page-appunti-condivisi .upload-popup { + z-index: 100; + background-color: #00000066; + + position: fixed; + inset: 0; + + display: flex; + flex-direction: column; + align-items: center; + + /* backdrop-filter: blur(0.5rem); */ +} + +.page-appunti-condivisi .upload-popup .popup { + position: relative; + top: 50%; + transform: translateY(-50%); + + background: var(--bg-dark); + border-radius: 4px; + border: 1px solid var(--bg-darker-2); + box-shadow: 0 0 32px #00000033; + + min-width: 40ch; + max-width: 60ch; + + display: flex; + flex-direction: column; + + gap: 1rem; +} + +.page-appunti-condivisi .upload-popup .popup .block { + padding: 0 1rem; +} + +.page-appunti-condivisi .upload-popup .popup .form { + padding: 0 1rem 1rem; + + gap: 1rem; +} + +.page-appunti-condivisi .popup .form .label { + min-width: 10ch; +} + +.form .progress-bytes { + display: flex; + align-items: center; + justify-content: center; + + font-size: 14px; +} + +.page-appunti-condivisi .upload-message { + font-size: 16px; + color: #666; + + user-select: none; + + display: flex; + align-items: center; + + gap: 0.5rem; +} + +.form .progress-and-action { + display: grid; + grid-template-columns: 1fr auto; + + align-items: center; + + gap: 1rem; +} + +.page-appunti-condivisi .upload-popup .popup > .header { + background: var(--bg-darker); + border-bottom: 1px solid var(--bg-darker-2); + + color: var(--fg-lighter); + + padding: 1rem; + + display: flex; + justify-content: space-between; +} + +.page-appunti-condivisi .upload-popup .popup .title { + font-size: 20px; + font-weight: var(--font-weight-medium); + + display: flex; + align-items: center; +} + +.page-appunti-condivisi .upload-popup .popup .title code { + font-size: 90%; } .page-appunti-condivisi #app { @@ -900,64 +1120,80 @@ form .field-set input { align-items: center; gap: 3rem; + + width: 100%; } -.page-appunti-condivisi .dispense-table { +.page-appunti-condivisi .table { + width: 100%; + 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); + + overflow: hidden; } -.page-appunti-condivisi .dispense-table .pending { +.page-appunti-condivisi .table.dispense { + grid-template-columns: auto 1fr minmax(auto, 50ch) auto; +} + +.page-appunti-condivisi .table.dispense .pending { color: royalblue; } -.page-appunti-condivisi .dispense-table .rejected { +.page-appunti-condivisi .table.dispense .rejected { color: darkred; } -.page-appunti-condivisi .dispense-table .header { +.page-appunti-condivisi .table > .header { font-weight: var(--font-weight-medium); + background: var(--bg-darker); + + border-bottom: 1px solid var(--bg-darker-2); } -.page-appunti-condivisi .dispense-table .separator { - grid-column: span 4; +.page-appunti-condivisi .table .separator { + grid-column: 1 / -1; 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 { +.page-appunti-condivisi .table.dispense .edit, +.page-appunti-condivisi .table.dispense .name, +.page-appunti-condivisi .table.dispense .tags, +.page-appunti-condivisi .table.dispense .status { padding: 1rem 0 1rem 1rem; display: flex; align-items: center; } -.page-appunti-condivisi .dispense-table .tags { +.page-appunti-condivisi .table.dispense .tags { flex-wrap: wrap; - gap: 0.25rem; + gap: 0.5rem; } -.page-appunti-condivisi .dispense-table .status { +.page-appunti-condivisi .table.dispense .status { place-self: center; padding: 1rem 1.25rem 1rem 2rem; } -.page-appunti-condivisi .dispense-table .expanded { +.page-appunti-condivisi .table.dispense .expanded { grid-column: span 4; display: grid; grid-template-columns: auto 1fr; } -.page-appunti-condivisi .dispense-table .edit-container { +.page-appunti-condivisi .table.dispense .expanded p { + width: 100%; +} + +.page-appunti-condivisi .table.dispense .edit-container { display: flex; flex-direction: column; gap: 1rem; @@ -965,20 +1201,85 @@ form .field-set input { padding: 1rem 1rem 1rem 0; } -.page-appunti-condivisi .dispense-table .edit-close { +.page-appunti-condivisi .table.dispense .edit-container > .header { + display: flex; + align-items: center; + + gap: 0.5rem; +} + +.page-appunti-condivisi .table.dispense .edit-container > .header code { + padding: 0 0.125rem; +} + +.page-appunti-condivisi .table.dispense .edit-container > .header .title { + font-size: 24px; + font-weight: var(--font-weight-medium); +} + +.page-appunti-condivisi .table.dispense .edit-container .stato-approvazione { + font-weight: var(--font-weight-medium); + display: flex; + align-items: center; + + gap: 1rem; +} + +.page-appunti-condivisi .table.dispense .edit-container .stato-approvazione.approved { + color: var(--accent-1); +} + +.page-appunti-condivisi .table.dispense h1 { + margin: 0; +} + +.page-appunti-condivisi .table.dispense .edit-close { + padding: 1rem; +} + +.page-appunti-condivisi .table.approvazioni { + grid-template-columns: auto auto 1fr auto auto; + + width: 80ch; + max-width: 100%; +} + +.page-appunti-condivisi .table.approvazioni .download, +.page-appunti-condivisi .table.approvazioni .hash, +.page-appunti-condivisi .table.approvazioni .title, +.page-appunti-condivisi .table.approvazioni .owner, +.page-appunti-condivisi .table.approvazioni .actions { padding: 1rem; + + display: flex; + align-items: center; +} + +.page-appunti-condivisi .table.approvazioni .hash { + padding-left: 0; +} + +.page-appunti-condivisi .table.approvazioni .actions { + display: flex; + gap: 1rem; + + justify-content: center; } -.page-appunti-condivisi .dispense-table .edit-form { +.page-appunti-condivisi .form { display: grid; grid-template-columns: auto 1fr; - gap: 0.5rem 1rem; + gap: 1rem 2rem; align-items: center; } -.page-appunti-condivisi .dispense-table .edit-form > .label { +.page-appunti-condivisi .form button:not(.icon) { + min-width: 6rem; +} + +.page-appunti-condivisi .form > .label { height: 2rem; align-self: flex-start; @@ -989,18 +1290,22 @@ form .field-set input { font-weight: var(--font-weight-medium); } -.page-appunti-condivisi .dispense-table .edit-form > textarea { +.page-appunti-condivisi .form > textarea { resize: vertical; overflow-y: hidden; } -.page-appunti-condivisi .dispense-table .edit-form > .right { +.page-appunti-condivisi .form > .fill { + grid-column: span 2; +} + +.page-appunti-condivisi .form > .right { grid-column: span 2; display: flex; justify-content: end; - padding-top: 0.5rem; + gap: 1rem; } .page-appunti-condivisi .input-tags { @@ -1212,3 +1517,22 @@ table td { table tbody tr:hover { background: var(--bg-darker); } + +/* Utils */ + +.flex { + display: flex; + align-items: center; +} + +.flex.col { + flex-direction: column; +} + +.flex.gap-1 { + gap: 1rem; +} + +.fill-h { + width: 100%; +} diff --git a/server/fiber.go b/server/fiber.go index 66af044..9526920 100644 --- a/server/fiber.go +++ b/server/fiber.go @@ -1,6 +1,7 @@ package server import ( + "log" "time" "git.phc.dm.unipi.it/phc/website/config" @@ -61,14 +62,15 @@ func routes(h handler.Service, r fiber.Router) { staticConfig := fiber.Static{} if config.Mode == "development" { + log.Printf("Disabling Cache-Control in development mode") + // if no "Cache-Control" is present the browser will cache heuristically (and we don't want that) r.Use(func(c *fiber.Ctx) error { c.Set("Cache-Control", "no-cache") return c.Next() }) - staticConfig.CacheDuration = -1 - staticConfig.MaxAge = -1 + staticConfig.CacheDuration = 1 * time.Millisecond } r.Static("/", "./_frontend/out", staticConfig)