New Website in VueJS #6

Open
alice wants to merge 11 commits from new-website into main
14 changed files with 103 additions and 66 deletions
Showing only changes of commit 659151d876 - Show all commits

View file

@ -20,6 +20,8 @@ The command creates `content/events/my_new_event.md` and fills front matter defa
- `date`: current local timestamp with timezone.
- `author`: `ADMStaff`.
Any kind of attachment (images, PDFs, etc.) can be placed in `static/img`, and referenced in markdown with `/img/filename.ext`.
Optional overrides:
```bash

View file

@ -28,3 +28,5 @@ Utilizziamo tecnologie open source come Linux, Proxmox, Docker, Ansible, Git/For
Cerchiamo studenti curiosi e motivati. Non importa il livello di esperienza: conta la voglia di imparare e mettersi in gioco. Passa a trovarci in laboratorio o scopri i nostri [eventi](/events).
Se sei interessato scrivici su Telegram [t.me/admstaff_Chat](https://t.me/admstaff_Chat)
![ADM 2024](/img/team2024.jpg)

View file

@ -29,3 +29,5 @@ We use open-source technologies such as Linux, Proxmox, Docker, Ansible, Git/For
Were looking for curious and motivated students. Your experience level doesnt matter: what counts is the desire to learn and get involved. Drop by the lab or check out our [events](/events).
If youre interested, write to us on Telegram: [t.me/admstaff_Chat](https://t.me/admstaff_Chat)
![ADM 2024](/img/team2024.jpg)

View file

@ -2,7 +2,11 @@
<html lang="en" data-theme="admtheme">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<link
rel="icon"
type="image/png"
href="/assets/ADMstaff_logo-favicon.png"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ADMStaff - University of Bologna</title>
</head>

View file

@ -110,9 +110,7 @@ export async function generateAllOGImages() {
// Leggi tutti i file markdown
const files = getAllMarkdownFiles(contentDir);
console.log(
`\n🎨 Generating OpenGraph images for ${files.length} files...\n`,
);
console.log(`\nGenerating OpenGraph images for ${files.length} files...\n`);
for (const file of files) {
const content = fs.readFileSync(file, "utf-8");
@ -127,7 +125,7 @@ export async function generateAllOGImages() {
}
}
console.log(`\nAll OpenGraph images generated!\n`);
console.log(`\nAll OpenGraph images generated!\n`);
}
/**

BIN
src/assets/ADMstaff_logo-favicon.png (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

View file

@ -10,13 +10,7 @@ import { useI18n } from "vue-i18n";
// Importa tutti i file markdown dalla directory content (più specifico)
const contentFiles = import.meta.glob(
["/content/**/*.md", "!**/node_modules/**", "!**/public/**"],
Review

We don't need the last two matching strings, only the first one

We don't need the last two matching strings, only the first one
{ as: "raw", eager: false },
);
// Debug: log dei file trovati
console.log(
"Content files loaded by import.meta.glob:",
Object.keys(contentFiles),
{ query: "?raw", import: "default", eager: false },
);
export function useContent(path) {
@ -73,9 +67,9 @@ export function useContentList(pattern) {
loading.value = true;
error.value = null;
console.log("=== DEBUG useContentList ===");
console.log("Pattern received:", pattern);
console.log("All available content files:", Object.keys(contentFiles));
// console.log("=== DEBUG useContentList ===");
// console.log("Pattern received:", pattern);
// console.log("All available content files:", Object.keys(contentFiles));
let basePath = pattern;
if (basePath.startsWith("/content/")) {
@ -87,13 +81,13 @@ export function useContentList(pattern) {
const localizedDir =
locale.value === "en" ? `/content/en/${basePath}` : defaultDir;
console.log("Search path:", localizedDir);
// console.log("Search path:", localizedDir);
const filesInDir = (dir) =>
Object.entries(contentFiles).filter(([fullPath]) => {
const pathDir = fullPath.substring(0, fullPath.lastIndexOf("/"));
const matches = pathDir === dir && !fullPath.endsWith("_index.md");
if (matches) console.log("✓ Matched file:", fullPath);
// if (matches) console.log("✓ Matched file:", fullPath);
return matches;
});
@ -116,18 +110,18 @@ export function useContentList(pattern) {
matchingFiles = [...localizedEntries, ...fallbackOnlyEntries];
}
console.log("Total matching files:", matchingFiles.length);
// console.log("Total matching files:", matchingFiles.length);
const contents = await Promise.all(
matchingFiles.map(async ([fullPath, loader]) => {
try {
console.log("Loading file:", fullPath);
// console.log("Loading file:", fullPath);
const raw = await loader();
const parsed = parseMarkdown(raw);
console.log("Parsed:", {
title: parsed.frontmatter.title,
date: parsed.frontmatter.date,
});
// console.log("Parsed:", {
// title: parsed.frontmatter.title,
// date: parsed.frontmatter.date,
// });
// Estrai slug dal path
const pathParts = fullPath.split("/");
@ -147,14 +141,14 @@ export function useContentList(pattern) {
// Filtra i null e ordina per data
const validContents = contents.filter((c) => c !== null);
console.log(
"Valid contents:",
validContents.length,
validContents.map((c) => ({
title: c.frontmatter.title,
date: c.frontmatter.date,
})),
);
// console.log(
// "Valid contents:",
// validContents.length,
// validContents.map((c) => ({
// title: c.frontmatter.title,
// date: c.frontmatter.date,
// })),
// );
items.value = validContents.sort((a, b) => {
// Ordina dal più recente al meno recente
@ -169,7 +163,7 @@ export function useContentList(pattern) {
return 0;
});
console.log("Final items:", items.value.length);
// console.log("Final items:", items.value.length);
loading.value = false;
} catch (e) {
console.error("Error loading content list:", e);

View file

@ -41,7 +41,7 @@ function parseYAMLFrontmatter(yamlContent) {
else if (/^-?\d+\.?\d*$/.test(value)) value = Number(value);
if (key === "cover") {
console.log("Cover value parsed:", value, "type:", typeof value);
// console.log("Cover value parsed:", value, "type:", typeof value);
}
frontmatter[key] = value;

View file

@ -3,13 +3,11 @@
<!-- About Section con cursore -->
<div class="about relative flex flex-row items-center mx-[5%] my-12 gap-5">
<img
src="/static/img/ADMstaff_logo-modern-trasp.png"
src="@/assets/ADMstaff_logo-modern-trasp.png"
alt="ADMStaff Logo"
class=" w-1/3" />
<h4
id="about-text"
class="leading-relaxed md:text-xl"
>
class="w-1/3"
/>
<h4 id="about-text" class="leading-relaxed 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
@ -142,12 +140,4 @@ function truncate(html, length) {
// Restituisci HTML semplice
return `<p>${finalText}...</p>`;
}
// Posiziona il cursore dopo il caricamento
onMounted(() => {
nextTick(() => {
updateCursorPosition();
window.addEventListener("resize", updateCursorPosition);
});
});
</script>

View file

@ -9,29 +9,56 @@
<div class="space-y-2 text-sm">
<div v-for="(item, index) in sidebarItems" :key="index">
<!-- Heading di sezione -->
<h3 v-if="item.type === 'heading'" class="text-xs font-bold text-secondary uppercase mt-4 mb-2">
<h3
v-if="item.type === 'heading'"
class="text-xs font-bold text-secondary uppercase mt-4 mb-2"
>
{{ item.text }}
</h3>
<!-- Link a pagina -->
<a v-else-if="item.type === 'link'" :href="item.isExternal ? item.url : '#'"
:target="item.isExternal ? '_blank' : null" :rel="item.isExternal ? 'noopener noreferrer' : null"
<a
v-else-if="item.type === 'link'"
:href="item.isExternal ? item.url : '#'"
:target="item.isExternal ? '_blank' : null"
:rel="item.isExternal ? 'noopener noreferrer' : null"
@click="onSidebarLinkClick($event, item)"
class="block py-1 px-2 rounded-lg hover:bg-base-300/20 transition truncate" :class="{
class="block py-1 px-2 rounded-lg hover:bg-base-300/20 transition truncate"
:class="{
'bg-base-300/20 text-primary font-bold':
!item.isExternal && currentPage === item.slug,
}" :title="item.text">
{{ item.text }}<span v-if="item.isExternal" class="ml-1 text-base-content/60"></span>
}"
:title="item.text"
>
{{ item.text
}}<span
v-if="item.isExternal"
class="ml-1 text-base-content/60"
></span
>
</a>
<!-- TOC (Table of Contents) - Outline minimal terminal style -->
<nav v-if="currentPage === item.slug && outline.length > 0" class="sticky top-4">
<ul class="space-y-0 text-xs font-mono leading-snug border-l border-base-300 pl-3">
<nav
v-if="currentPage === item.slug && outline.length > 0"
class="sticky top-4"
>
<ul
class="space-y-0 text-xs font-mono leading-snug border-l border-base-300 pl-3"
>
<li v-for="heading in outline" :key="heading.id">
<a :href="`#${heading.id}`" @click.prevent="scrollToHeading(heading.id)"
<a
:href="`#${heading.id}`"
@click.prevent="scrollToHeading(heading.id)"
class="block py-0.5 hover:text-base-content rounded-lg transition truncate"
:style="{ paddingLeft: `${(heading.level - 1) * 0.5}rem` }" :class="{
'text-primary bg-base-300/20': activeHeading === heading.id,
:style="{
paddingLeft: `${(heading.level - 1) * 0.5}rem`,
}"
:class="{
'text-primary bg-base-300/20':
Review

An icon would look better :)

An icon would look better :)
activeHeading === heading.id,
'text-base-content/60': activeHeading !== heading.id,
}" :title="heading.text">
}"
:title="heading.text"
>
{{ heading.text }}
</a>
</li>
@ -39,26 +66,39 @@
</nav>
</div>
</div>
</nav>
</aside>
<!-- Contenuto principale -->
<main class="lg:col-span-4">
<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>
<article v-else class="bg-base-200 rounded-lg p-8 border border-base-300">
<article
v-else
class="bg-base-200 rounded-lg p-8 border border-base-300"
>
<h1 class="text-4xl font-bold text-primary mb-6">
{{ pageTitle }}<span class="blinking-cursor"></span>
</h1>
<div class="markdown-content prose prose-invert max-w-none" v-html="pageContent"></div>
<div
class="markdown-content prose prose-invert max-w-none"
v-html="pageContent"
></div>
</article>
</main>
</div>
</div>
<button class="btn btn-circle btn-secondary bottom-4 right-4 fixed font-bold text-3xl" :class="{ 'hidden': !showScrollTopButton }" @click="scrollToTop"></button>
<button
class="btn btn-circle btn-secondary bottom-4 right-4 fixed font-bold text-3xl"
:class="{ hidden: !showScrollTopButton }"
@click="scrollToTop"
>
</button>
</div>
</template>
@ -302,7 +342,7 @@ onMounted(async () => {
window.addEventListener("scroll", () => {
const scrollTop = window.scrollY || document.documentElement.scrollTop;
showScrollTopButton.value = scrollTop > 300;
});
});
});
</script>

BIN
static/img/team2024.jpg (Stored with Git LFS) Normal file

Binary file not shown.