mio primo commit
This commit is contained in:
parent
8c18ba80bb
commit
e664963226
27 changed files with 1292 additions and 1537 deletions
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
||||
52
.github/workflows/deploy.yml
vendored
Normal file
52
.github/workflows/deploy.yml
vendored
Normal 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
2
.gitignore
vendored
|
|
@ -39,3 +39,5 @@ yarn-error.log*
|
|||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
node_modules
|
||||
.env
|
||||
|
|
|
|||
8
Annotazioni
Normal file
8
Annotazioni
Normal 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?)
|
||||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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
4
next.config.mjs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
2343
package-lock.json
generated
2343
package-lock.json
generated
File diff suppressed because it is too large
Load diff
16
package.json
16
package.json
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
39
src/app/(content)/blog/[slug]/page.tsx
Normal file
39
src/app/(content)/blog/[slug]/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
3
src/app/(content)/blog/categorie/page.tsx
Normal file
3
src/app/(content)/blog/categorie/page.tsx
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export default function Categorie(){
|
||||
return <h1>Blog Categorie</h1>
|
||||
}
|
||||
49
src/app/(content)/blog/page.tsx
Normal file
49
src/app/(content)/blog/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
42
src/app/(content)/docs/[...slug]/page.tsx
Normal file
42
src/app/(content)/docs/[...slug]/page.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
67
src/app/(content)/docs/page.tsx
Normal file
67
src/app/(content)/docs/page.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
22
src/app/(content)/layout.tsx
Normal file
22
src/app/(content)/layout.tsx
Normal 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
15
src/app/(main)/layout.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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{" "}
|
||||
3
src/app/(marketing)/about/page.tsx
Normal file
3
src/app/(marketing)/about/page.tsx
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export default function About(){
|
||||
return <h1>About page</h1>
|
||||
}
|
||||
9
src/app/(marketing)/contact/page.tsx
Normal file
9
src/app/(marketing)/contact/page.tsx
Normal 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>
|
||||
</>
|
||||
}
|
||||
15
src/app/(marketing)/layout.tsx
Normal file
15
src/app/(marketing)/layout.tsx
Normal 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
16
src/app/Layout.txt
Normal 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.
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
38
src/app/layout.tsx
Normal file
38
src/app/layout.tsx
Normal 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
22
src/components/Navbar.tsx
Normal 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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue