prototype mostly finished
parent
7c36f87149
commit
4757c3e0a9
@ -0,0 +1,116 @@
|
|||||||
|
import { useEffect, useState } from 'preact/hooks'
|
||||||
|
import { Funnel } from '@phosphor-icons/react'
|
||||||
|
import { marked } from 'marked'
|
||||||
|
|
||||||
|
import type { Database } from '@/data/domande-esami.yaml'
|
||||||
|
|
||||||
|
const useRemoteValue = <T,>(url: string): T | null => {
|
||||||
|
const [value, setValue] = useState<T | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(value => setValue(value))
|
||||||
|
}, [url])
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
course: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DomandeEsamiCourse = ({ course }: Props) => {
|
||||||
|
const database = useRemoteValue<Database>(`/domande-esami/api/${course}.json`)
|
||||||
|
if (!database) {
|
||||||
|
return <>Loading...</>
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
requestIdleCallback(() => window.renderMath())
|
||||||
|
|
||||||
|
console.log(database)
|
||||||
|
|
||||||
|
const courseTags = [
|
||||||
|
...new Set(
|
||||||
|
database.questions
|
||||||
|
.filter(question => question.course === course)
|
||||||
|
.flatMap(question => question.tags)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
const [selectedTags, setSelectedTags] = useState<string[]>([])
|
||||||
|
|
||||||
|
const filteredQuestions = database.questions
|
||||||
|
.filter(question => question.course === course)
|
||||||
|
.filter(
|
||||||
|
question => selectedTags.length === 0 || selectedTags.every(tag => question.tags.includes(tag))
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="grid-center">
|
||||||
|
<h3>
|
||||||
|
<a href="/domande-esami">Domande Esami</a>
|
||||||
|
</h3>
|
||||||
|
<h1>{database.names[course]}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card filter">
|
||||||
|
<div class="grid-h">
|
||||||
|
<Funnel />
|
||||||
|
<strong>Filtra Tag</strong>
|
||||||
|
</div>
|
||||||
|
<div class="flex-row-wrap">
|
||||||
|
{selectedTags.length === 0
|
||||||
|
? courseTags.map(tag => (
|
||||||
|
<div class="chip clickable" onClick={() => setSelectedTags([tag])}>
|
||||||
|
{tag}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
: courseTags.map(tag => (
|
||||||
|
<div
|
||||||
|
class={
|
||||||
|
selectedTags.includes(tag)
|
||||||
|
? 'chip clickable'
|
||||||
|
: 'chip clickable disabled'
|
||||||
|
}
|
||||||
|
onClick={() =>
|
||||||
|
setSelectedTags(
|
||||||
|
selectedTags.includes(tag)
|
||||||
|
? selectedTags.filter(t => t !== tag)
|
||||||
|
: [...selectedTags, tag]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="wide-card-list" id="questions">
|
||||||
|
{filteredQuestions.length === 0 ? (
|
||||||
|
<div class="grid-center">
|
||||||
|
<em>No questions found</em>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
filteredQuestions.map(question => (
|
||||||
|
<div class="card">
|
||||||
|
<div
|
||||||
|
class="text"
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: marked(question.content, { async: false }),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div class="metadata">
|
||||||
|
{question.tags.map(tag => (
|
||||||
|
<div class="chip small">{tag}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
import type { APIRoute } from 'astro'
|
||||||
|
|
||||||
|
import database from '@/data/domande-esami.yaml'
|
||||||
|
|
||||||
|
export const GET: APIRoute = ({}) => {
|
||||||
|
return new Response(JSON.stringify(database), {
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import type { APIRoute, GetStaticPaths } from 'astro'
|
||||||
|
|
||||||
|
import database from '@/data/domande-esami.yaml'
|
||||||
|
|
||||||
|
export const getStaticPaths = (() => {
|
||||||
|
return Object.keys(database.names).map(course => ({
|
||||||
|
params: { course },
|
||||||
|
}))
|
||||||
|
}) satisfies GetStaticPaths
|
||||||
|
|
||||||
|
export const GET: APIRoute = ({ params: { course } }) => {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
groups: [],
|
||||||
|
names: Object.fromEntries(Object.entries(database.names).filter(([key]) => key === course)),
|
||||||
|
questions: database.questions.filter(question => question.course === course),
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue