mio primo commit

This commit is contained in:
AV77web 2026-05-25 09:48:11 +02:00
parent 8c18ba80bb
commit e664963226
27 changed files with 1292 additions and 1537 deletions

3
.eslintrc.json Normal file
View file

@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

52
.github/workflows/deploy.yml vendored Normal file
View file

@ -0,0 +1,52 @@
name: Deploy to VPS
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: magricambi
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: app/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
echo "START DEPLOY"
cd /root/app
pwd
ls -la
git pull
docker compose up -d --build

2
.gitignore vendored
View file

@ -39,3 +39,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
node_modules
.env

8
Annotazioni Normal file
View file

@ -0,0 +1,8 @@
Per domani 25/05/2026
- configurare il file .gitignore in locale
- eseguire il primo commit e il primo push
- completare la configurazione git/githut/VPS con l'attivazione della action e del runner con il file workflow/deploy.yml
- sistemare il dokcerfile con myslq/phpmyadmin al posto di monog db
- configurare il DB magazzino con la tabella Utenti
- implementare la configurazione di Auth.js ( cercare di capire come impostare l'autenticazione: con Google, con Github o qualche altro provider?)

View file

@ -1,33 +0,0 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">{children}</body>
</html>
);
}

View file

@ -1,3 +1,4 @@
// Copia per quando torni a Next 16 + ESLint 9: rinomina in eslint.config.mjs
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
@ -5,9 +6,7 @@ import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",

4
next.config.mjs Normal file
View file

@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default nextConfig;

View file

@ -1,7 +0,0 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;

2343
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,20 +6,20 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
"lint": "next lint"
},
"dependencies": {
"next": "16.2.4",
"react": "19.2.4",
"react-dom": "19.2.4"
"next": "14.2.28",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.4",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8.57.0",
"eslint-config-next": "14.2.28",
"tailwindcss": "^4",
"typescript": "^5"
}

View file

@ -0,0 +1,39 @@
interface Post {
slug: string;
title: string;
content: string;
}
const blogPosts: Post[] = [
{
slug: "primo-post",
title: "Il mio primo post",
content: "Questo è il contenuto del primo post...",
},
{
slug: "secondo-post",
title: "Il mio secondo post",
content: "Questo è il contenuto del secondo post...",
},
{
slug: "terzo-post",
title: "Il mio terzo post",
content: "Questo è il contenuto del terzo post...",
},
];
/** Next 14: `params` è un oggetto sincrono. */
export default function BlogPost({ params }: { params: { slug: string } }) {
const post = blogPosts.find((p) => p.slug === params.slug);
if (!post) {
return <div>Post non trovato</div>;
}
return (
<article className="max-w-4xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-4">{post.title}</h1>
<p>{post.content}</p>
</article>
);
}

View file

@ -0,0 +1,3 @@
export default function Categorie(){
return <h1>Blog Categorie</h1>
}

View file

@ -0,0 +1,49 @@
import Link from "next/link";
interface Post {
slug: string;
title: string;
excerpt: string;
}
const blogPosts: Post[]= [
{
slug: "primo-post",
title: "Il mio primo post",
excerpt: "Una breve introduzione al mio primo post...",
},
{
slug: "secondo-post",
title: "Il mio secondo post",
excerpt: "Qualcosa di interessante sul seondo post",
},
{
slug: "terzo post",
title: "Il mio terzo post",
excerpt: "Un altro post interessante da leggere",
}
]
export default function BlogPage() {
return (
<div className="max-w-4xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-8">Blog</h1>
<div className="space-y-6">
{ blogPosts.map((post) => (
<article key={post.slug} className="p-6 bg-zinc-800 reounded-lg">
<h2 className="text-xl font-bold mb-2">
<Link href={`/blog/${post.slug}`}
className="hover:text-zinc-200 transition-colors">
{post.title}
</Link>
</h2>
<p className="text-zinc-400">{post.excerpt}</p>
</article>
))}
</div>
</div>
);
}

View file

@ -0,0 +1,42 @@
interface DocPage {
path: string[],
title: string,
content: string,
}
const docs: DocPage[] = [
{
path: ["intro"],
title: "Introduzione",
content: "Benvenuti alla documentazione...",
},
{
path: ["intro", "getting-started"],
title: "Getting Started",
content: "Ecco come iniziare...",
},
{
path: ["advanced", "configuration"],
title: "Configurazione Avanzata",
content: "Configurazioni dettagliate..."
},
];
export default function DocPage({ params }: { params: { slug: string[] } }) {
const currentPath = params.slug;
console.log(currentPath);
const doc = docs.find(doc => doc.path.join("/") === currentPath.join("/"));
if (!doc) {
return <div>Pagina non trovata</div>;
}
return (
<div className="max-w-4xl ma-auto p-8">
<h1 className="text-3xl font-bold mb-4">{doc.title}</h1>
<p>{doc.content}</p>
<div className="mt-r text-sm text-gray-500">Path: /{currentPath.join("/")}</div>
</div>
)
}

View file

@ -0,0 +1,67 @@
//app/docs/page.tsx
import Link from "next/link";
interface DocSection {
path: string;
title: string;
subsections?: { path: string; title: string}[];
}
// dati hardcodati
const docSections: DocSection[] = [
{
path: "intro",
title: "introduzione",
subsections: [
{ path: "getting-started", title: "Getting Started"},
{ path: "installation", title: "Installazione"},
],
},
{
path: "advanced",
title: "Guide Avanzate",
subsections: [
{path: "configuration", title: "Configurazione"},
{path: "deployment", title: "Deployment"},
],
},
];
export default function DocPage() {
return (
<div className="max-w-4xl mx-auro p-8">
<h1 className="text-3xl font-bold mb-g">Documentazione</h1>
<div className="space-y-8">
{docSections.map((section)=> (
<div key={section.path} className="bg-zinc-800 rounded-lg p-6">
<h2 className="text-xl font-bold mb-4">
<Link
href={`/docs/${section.path}
`}
className="hover:text-zinc-300 transition-colors">
{section.title}
</Link>
</h2>
{section.subsections && (
<ul className="space-y-2 ml-4">{section.subsections.map((sub)=> {
return (
<li key={sub.path}>
<Link
href={`/docs/${section.path}/${sub.path}`}
className="text-zinc-400 hover:text-zinc-300 transition-colors"
>
{sub.title}
</Link>
</li>)
})}
</ul>
)}
</div>
))}
</div>
</div>
)
}

View file

@ -0,0 +1,22 @@
import { redirect } from "next/navigation";
export default function ContentLayout({
children,
}: {
children: React.ReactNode;
}) {
const user = false;
if (!user) {
redirect("/");
}
return (
<div>
<p className="bg-violet-700 text-white w-full text-center py-2">
Sono del layout (content)
</p>
<main>{children}</main>
</div>
);
}

15
src/app/(main)/layout.tsx Normal file
View file

@ -0,0 +1,15 @@
export default function MainLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div>
<p className="bg-violet-700 text-white w-full text-center py-2">
Sono del layout (main)
</p>
<main>{children}</main>
</div>
);
}

View file

@ -14,7 +14,7 @@ export default function Home() {
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
To get started, PROVA PROVA edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}

View file

@ -0,0 +1,3 @@
export default function About(){
return <h1>About page</h1>
}

View file

@ -0,0 +1,9 @@
import Link from "next/link";
export default function Contact() {
return <>
<h1>Contatti</h1>
<Link href="/about">about1</Link>
<a href="/about">about2</a>
</>
}

View file

@ -0,0 +1,15 @@
export default function MarketingLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div>
<p className="bg-violet-700 text-white w-full text-center py-2">
Sono del layout (marketing)
</p>
<main>{children}</main>
</div>
);
}

16
src/app/Layout.txt Normal file
View file

@ -0,0 +1,16 @@
Layout.tsx:
Tutto quello che è presente nel Layout di root, viene poi "trasportato" a cascata in tutta l'applicazione e quindi in
tutte le altre pagine.
In qualsiasi pagina mi sposto, tutto quello che è presente nel layout di root viene portato nelle altre pagine.
Possiamo avere più layout.
In qualsiasi cartella raggruppata, ma anche nelle cartelle delle pagine, posso creare un layout.
Possiamo aver quindi il ContentLayout.tsx, il MarketingLayout.tsx etc...
L'importante è che il nome sia in minuscolo perché in Next.js le convenzioni
file-based sono case-sensitive per i nome speciali: layout, page.tsx, loading.tsx, not-found.tsx.
Ogni pagina potenzialmente può aver il suo layout. Se andiamo a mettere qualcosa nel layout di root però, questa
viene portata in tutte le altre pagine.
In realtà una cosa che si fa spesso e volentieri è creare un layout per i raggruppamenti: (content), (marekting) e (main). Questi raggruppamenti al di là della questione logica di andare a raggruppare in modo logico, viene fatto per creare un layout specifici. Possono essere server side o client side e quindi possono fetchare dati e mantengono lo stato navigando tra le routes: ciò significa che se posso forzare un redirect verso un'altra pagina.

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

38
src/app/layout.tsx Normal file
View file

@ -0,0 +1,38 @@
import type { Metadata } from "next";
import { Inter, JetBrains_Mono } from "next/font/google";
import Navbar from "../components/Navbar";
import "./globals.css";
/** Stesse variabili CSS di globals.css; Geist non è disponibile in next/font su Next 14. */
const geistSans = Inter({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = JetBrains_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}>
<p className="bg-purple-700 text-white w-full text-center py-2">
Sono del layout root
</p>
<Navbar />
{children}
</body>
</html>
);
}

22
src/components/Navbar.tsx Normal file
View file

@ -0,0 +1,22 @@
//====================================
// File: Navbar.tsx
// componente Navbar
// @author: "villari.andrea@libero.it"
// @version: "1.0.0 2026-05-07"
//====================================
export default function Navbar() {
return (
<>
<div className="flex direction-row gap-7" >
<div className="text-3xl">Home</div>
<div className="text-3xl">About</div>
<div className="text-3xl">Document</div>
<div className="text-3xl">Contact</div>
<div className="text-3xl">Sources</div>
</div>
</>
)
}

View file

@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@ -11,7 +15,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"jsx": "preserve",
"incremental": true,
"plugins": [
{
@ -19,7 +23,9 @@
}
],
"paths": {
"@/*": ["./*"]
"@/*": [
"./*"
]
}
},
"include": [
@ -30,5 +36,7 @@
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
"exclude": [
"node_modules"
]
}