New Website in VueJS #6
9 changed files with 104 additions and 36 deletions
|
|
@ -8,4 +8,4 @@ cover: "/img/wifi-pass.png"
|
|||
link: "https://auth.lab.students.cs.unibo.it"
|
||||
---
|
||||
|
||||
In ADM Lab è presente una rete Wi-Fi dedicata agli studenti, che consente di accedere a Internet e alle risorse del laboratorio. Per connettersi alla rete Wi-Fi, è necessario conoscere le credenziali per connettersi all'Access Point. Una volta connessi si aprirà il captive portal, dove potete registarvi e creare le vostre credenziali ADM. Queste possono essere usate per accedere sì alla rete, ma anche a tutti i servizi che abbiamo realizzato e richiedono un'autenticazione, come [sasso](projects/sasso).
|
||||
In ADM Lab è presente una rete Wi-Fi dedicata agli studenti, che consente di accedere a Internet e alle risorse del laboratorio. Per connettersi alla rete Wi-Fi, è necessario conoscere le credenziali per connettersi all'Access Point. Una volta connessi si aprirà il captive portal, dove potete registarvi e creare le vostre credenziali ADM. Queste possono essere usate per accedere sì alla rete, ma anche a tutti i servizi che abbiamo realizzato e richiedono un'autenticazione, come [sasso](projects/sasso).
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
href="/src/assets/ADMstaff_logo-favicon.png"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>ADMStaff - University of Bologna</title>
|
||||
<title>ADMStaff</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@
|
|||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="inline text-lg text-base-content/70 transition-colors group-hover:text-primary"
|
||||
<span
|
||||
class="inline text-lg text-base-content/70 transition-colors group-hover:text-primary"
|
||||
>ADMStaff</span
|
||||
>
|
||||
<span class="blinking-cursor ml-1"></span>
|
||||
|
|
@ -30,7 +31,10 @@
|
|||
<div class="navbar-center hidden lg:flex">
|
||||
<ul class="menu menu-horizontal px-1 gap-1">
|
||||
<li v-for="link in links" :key="link.path">
|
||||
<RouterLink :to="link.path" class="text-base-content hover:text-primary">
|
||||
<RouterLink
|
||||
:to="link.path"
|
||||
class="text-base-content hover:text-primary"
|
||||
>
|
||||
{{ $t(link.nameKey) }}
|
||||
</RouterLink>
|
||||
</li>
|
||||
|
|
@ -50,7 +54,11 @@
|
|||
</div>
|
||||
|
||||
<div class="dropdown dropdown-end lg:hidden">
|
||||
<label tabindex="0" class="btn btn-ghost btn-square" aria-label="Open navigation menu">
|
||||
<label
|
||||
tabindex="0"
|
||||
class="btn btn-ghost btn-square"
|
||||
aria-label="Open navigation menu"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { computed } from "vue";
|
|||
export function useMeta(options) {
|
||||
const {
|
||||
title,
|
||||
description = "ADMStaff - Amministratori di Sistemi e Reti - University of Bologna",
|
||||
description = "ADMStaff - gruppo di studenti di Informatica dell'Università di Bologna",
|
||||
image,
|
||||
url,
|
||||
type = "website",
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@ export function resolveAssetPath(url) {
|
|||
}
|
||||
|
||||
return `/${url}`;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- About Section con cursore -->
|
||||
<div class="flex flex-col md:flex-row md:items-center md:mx-[5%] mb-12 md:my-12 md:gap-5">
|
||||
<div
|
||||
class="flex flex-col md:flex-row md:items-center md:mx-[5%] mb-12 md:my-12 md:gap-5"
|
||||
>
|
||||
<img
|
||||
src="@/assets/ADMstaff_logo-modern-trasp.png"
|
||||
alt="ADMStaff Logo"
|
||||
class="md:w-1/3"
|
||||
/>
|
||||
<h4 id="about-text" class=" md:text-xl">
|
||||
<h4 id="about-text" class="md:text-xl">
|
||||
ADMstaff nasce come gruppo che fornisce servizi da studenti per
|
||||
studenti.<br /><br />
|
||||
Il nostro obiettivo è sperimentare e fare pratica su ciò che ci
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div v-if="loading" class="text-center py-12">
|
||||
<span class="text-primary">Loading<span class="blinking-cursor"></span></span>
|
||||
<span class="text-primary"
|
||||
>Loading<span class="blinking-cursor"></span
|
||||
></span>
|
||||
</div>
|
||||
|
||||
<div v-else-if="error" class="text-center py-12">
|
||||
|
|
|
|||
|
|
@ -4,14 +4,18 @@
|
|||
<p class="text-xs uppercase tracking-[0.3em] text-secondary mb-3">
|
||||
Selected work
|
||||
</p>
|
||||
<h1 class="text-4xl sm:text-5xl font-bold text-primary mb-4 leading-tight">
|
||||
<h1
|
||||
class="text-4xl sm:text-5xl font-bold text-primary mb-4 leading-tight"
|
||||
>
|
||||
Projects<span class="blinking-cursor"></span>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
<div v-if="loading" class="space-y-8">
|
||||
<div class="grid gap-6 lg:grid-cols-[1.25fr_0.75fr]">
|
||||
<div class="animate-pulse rounded-3xl border border-base-300 bg-base-200/70 p-6 lg:p-8 min-h-[22rem]">
|
||||
<div
|
||||
class="animate-pulse rounded-3xl border border-base-300 bg-base-200/70 p-6 lg:p-8 min-h-[22rem]"
|
||||
>
|
||||
<div class="h-4 w-24 rounded bg-base-300 mb-6"></div>
|
||||
<div class="h-10 w-3/4 rounded bg-base-300 mb-4"></div>
|
||||
<div class="h-4 w-full rounded bg-base-300 mb-3"></div>
|
||||
|
|
@ -34,7 +38,9 @@
|
|||
</div>
|
||||
|
||||
<div v-else-if="error" class="text-center py-12">
|
||||
<div class="max-w-md mx-auto rounded-3xl border border-base-300 bg-base-200 p-8">
|
||||
<div
|
||||
class="max-w-md mx-auto rounded-3xl border border-base-300 bg-base-200 p-8"
|
||||
>
|
||||
<span class="text-red-500 block mb-4">Error loading projects</span>
|
||||
<p class="text-base-content/75 mb-6">
|
||||
Non riesco a caricare l’elenco in questo momento.
|
||||
|
|
@ -55,12 +61,18 @@
|
|||
class="group overflow-hidden rounded-[2rem] border border-base-300 bg-base-200/80 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-xl hover:border-primary/40"
|
||||
>
|
||||
<div class="grid lg:grid-cols-[1.2fr_0.8fr] min-h-[20rem]">
|
||||
<div class="order-2 lg:order-1 p-6 sm:p-8 lg:p-10 flex flex-col justify-between gap-6">
|
||||
<div
|
||||
class="order-2 lg:order-1 p-6 sm:p-8 lg:p-10 flex flex-col justify-between gap-6"
|
||||
>
|
||||
<div>
|
||||
<p class="text-xs uppercase tracking-[0.28em] text-secondary mb-4">
|
||||
<p
|
||||
class="text-xs uppercase tracking-[0.28em] text-secondary mb-4"
|
||||
>
|
||||
Featured project
|
||||
</p>
|
||||
<h2 class="text-3xl sm:text-4xl font-bold text-primary mb-4 leading-tight group-hover:text-base-content transition-colors">
|
||||
<h2
|
||||
class="text-3xl sm:text-4xl font-bold text-primary mb-4 leading-tight group-hover:text-base-content transition-colors"
|
||||
>
|
||||
{{ featuredProject.frontmatter.title }}
|
||||
</h2>
|
||||
<div
|
||||
|
|
@ -80,7 +92,11 @@
|
|||
v-if="featuredServiceLink"
|
||||
:href="featuredServiceLink"
|
||||
:target="isExternalLink(featuredServiceLink) ? '_blank' : null"
|
||||
:rel="isExternalLink(featuredServiceLink) ? 'noopener noreferrer' : null"
|
||||
:rel="
|
||||
isExternalLink(featuredServiceLink)
|
||||
? 'noopener noreferrer'
|
||||
: null
|
||||
"
|
||||
class="inline-flex items-center rounded-full border border-base-300 bg-base-100/80 px-4 py-2 text-base-content/80 hover:border-primary/50 hover:text-primary transition-colors"
|
||||
>
|
||||
Vai al servizio
|
||||
|
|
@ -99,14 +115,20 @@
|
|||
class="h-auto max-h-[10rem] w-full max-w-[20rem] object-contain transition-transform duration-500 group-hover:scale-[1.03]"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="flex h-full min-h-[12rem] lg:min-h-[20rem] items-center justify-center p-8 text-secondary">
|
||||
<div
|
||||
v-else
|
||||
class="flex h-full min-h-[12rem] lg:min-h-[20rem] items-center justify-center p-8 text-secondary"
|
||||
>
|
||||
No cover available
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div v-if="items.length > 1" class="grid gap-5 md:grid-cols-2 xl:grid-cols-3">
|
||||
<div
|
||||
v-if="items.length > 1"
|
||||
class="grid gap-5 md:grid-cols-2 xl:grid-cols-3"
|
||||
>
|
||||
<article
|
||||
v-for="project in items.slice(1)"
|
||||
:key="project.path"
|
||||
|
|
@ -119,16 +141,24 @@
|
|||
:alt="project.frontmatter.title"
|
||||
class="h-full w-full object-contain transition-transform duration-500 group-hover:scale-[1.03]"
|
||||
/>
|
||||
<div v-else class="flex h-full items-center justify-center text-secondary">
|
||||
<div
|
||||
v-else
|
||||
class="flex h-full items-center justify-center text-secondary"
|
||||
>
|
||||
No cover available
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-5 sm:p-6">
|
||||
<h2 class="text-xl sm:text-2xl font-bold text-primary mb-3 leading-snug group-hover:text-base-content transition-colors">
|
||||
<h2
|
||||
class="text-xl sm:text-2xl font-bold text-primary mb-3 leading-snug group-hover:text-base-content transition-colors"
|
||||
>
|
||||
{{ project.frontmatter.title }}
|
||||
</h2>
|
||||
<div class="text-base-content/75 line-clamp-3" v-html="getExcerpt(project.html, 140)"></div>
|
||||
<div
|
||||
class="text-base-content/75 line-clamp-3"
|
||||
v-html="getExcerpt(project.html, 140)"
|
||||
></div>
|
||||
<div class="mt-5 flex flex-wrap items-center gap-2 text-sm">
|
||||
<RouterLink
|
||||
:to="`/projects/${project.slug}`"
|
||||
|
|
@ -139,8 +169,14 @@
|
|||
<a
|
||||
v-if="getProjectLink(project)"
|
||||
:href="getProjectLink(project)"
|
||||
:target="isExternalLink(getProjectLink(project)) ? '_blank' : null"
|
||||
:rel="isExternalLink(getProjectLink(project)) ? 'noopener noreferrer' : null"
|
||||
:target="
|
||||
isExternalLink(getProjectLink(project)) ? '_blank' : null
|
||||
"
|
||||
:rel="
|
||||
isExternalLink(getProjectLink(project))
|
||||
? 'noopener noreferrer'
|
||||
: null
|
||||
"
|
||||
class="inline-flex items-center rounded-full border border-base-300 bg-base-100/80 px-3 py-1.5 font-medium text-base-content/80 hover:border-primary/50 hover:text-primary transition-colors"
|
||||
>
|
||||
|
|
||||
Vai al servizio
|
||||
|
|
@ -150,11 +186,17 @@
|
|||
</article>
|
||||
</div>
|
||||
|
||||
<div v-else-if="items.length === 1" class="rounded-3xl border border-dashed border-base-300 bg-base-200/50 p-8 text-secondary">
|
||||
<div
|
||||
v-else-if="items.length === 1"
|
||||
class="rounded-3xl border border-dashed border-base-300 bg-base-200/50 p-8 text-secondary"
|
||||
>
|
||||
Solo un progetto disponibile per ora.
|
||||
</div>
|
||||
|
||||
<div v-else class="rounded-3xl border border-dashed border-base-300 bg-base-200/50 p-8 text-secondary">
|
||||
<div
|
||||
v-else
|
||||
class="rounded-3xl border border-dashed border-base-300 bg-base-200/50 p-8 text-secondary"
|
||||
>
|
||||
Nessun progetto trovato.
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -173,14 +215,18 @@ const { items, loading, error, reload } = useContentList("/content/projects/");
|
|||
const resolveCover = (cover) => resolveAssetPath(cover);
|
||||
|
||||
const featuredProject = computed(() => items.value[0] ?? null);
|
||||
const featuredServiceLink = computed(() => getProjectLink(featuredProject.value));
|
||||
const featuredServiceLink = computed(() =>
|
||||
getProjectLink(featuredProject.value),
|
||||
);
|
||||
|
||||
function getExcerpt(html, length) {
|
||||
if (!html) return "";
|
||||
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = html;
|
||||
const text = (div.textContent || div.innerText || "").replace(/\s+/g, " ").trim();
|
||||
const text = (div.textContent || div.innerText || "")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
|
||||
if (text.length <= length) {
|
||||
return `<p>${text}</p>`;
|
||||
|
|
@ -188,7 +234,8 @@ function getExcerpt(html, length) {
|
|||
|
||||
const shortened = text.substring(0, length);
|
||||
const lastSpace = shortened.lastIndexOf(" ");
|
||||
const finalText = lastSpace > 0 ? shortened.substring(0, lastSpace) : shortened;
|
||||
const finalText =
|
||||
lastSpace > 0 ? shortened.substring(0, lastSpace) : shortened;
|
||||
|
||||
return `<p>${finalText}...</p>`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,12 @@
|
|||
aria-controls="wiki-sidebar-panel"
|
||||
>
|
||||
<span class="flex flex-col items-start">
|
||||
<span class="text-sm font-semibold text-base-content">Sommario e Indice pagina</span>
|
||||
<span class="text-xs text-base-content/70">{{ mobileSidebarSummary }}</span>
|
||||
<span class="text-sm font-semibold text-base-content"
|
||||
>Sommario e Indice pagina</span
|
||||
>
|
||||
<span class="text-xs text-base-content/70">{{
|
||||
mobileSidebarSummary
|
||||
}}</span>
|
||||
</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
@ -45,7 +49,8 @@
|
|||
aria-label="Wiki sidebar"
|
||||
>
|
||||
<div class="mb-4 flex items-center justify-between md:hidden">
|
||||
<span class="text-sm font-semibold uppercase tracking-wide text-primary"
|
||||
<span
|
||||
class="text-sm font-semibold uppercase tracking-wide text-primary"
|
||||
>Wiki menu</span
|
||||
>
|
||||
<button
|
||||
|
samu
commented
An icon would look better :) An icon would look better :)
|
||||
|
|
@ -133,7 +138,9 @@
|
|||
v-else
|
||||
class="bg-base-200 rounded-lg border border-base-300 p-4 sm:p-6 lg:p-8"
|
||||
>
|
||||
<h1 class="mb-5 text-2xl font-bold text-primary sm:text-3xl lg:mb-6 lg:text-4xl">
|
||||
<h1
|
||||
class="mb-5 text-2xl font-bold text-primary sm:text-3xl lg:mb-6 lg:text-4xl"
|
||||
>
|
||||
{{ pageTitle }}<span class="blinking-cursor"></span>
|
||||
</h1>
|
||||
<div
|
||||
|
|
@ -230,7 +237,10 @@ function parseSidebarLine(line) {
|
|||
if (line.startsWith("###") || line.startsWith("- ###")) {
|
||||
return {
|
||||
type: "heading",
|
||||
text: line.replace(/^-\s*/, "").replace(/^###\s*/, "").trim(),
|
||||
text: line
|
||||
.replace(/^-\s*/, "")
|
||||
.replace(/^###\s*/, "")
|
||||
.trim(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -400,8 +410,7 @@ async function loadPage(slug) {
|
|||
}
|
||||
// Estrai titolo
|
||||
const titleMatch = content.match(/^#\s+(.+)$/m);
|
||||
pageTitle.value =
|
||||
titleMatch?.[1] || normalizedSlug.replace(/-/g, " ");
|
||||
pageTitle.value = titleMatch?.[1] || normalizedSlug.replace(/-/g, " ");
|
||||
|
||||
// Rimuovi solo il primo H1 iniziale (se presente)
|
||||
const contentWithoutMainTitle = content.replace(/^\s*#\s+.+(?:\r?\n)+/, "");
|
||||
|
|
|
|||
Loading…
Reference in a new issue
Same story of HomeView for the parser and sanitize