<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
Questo esempio inizialmente non funzionerà: utilizza la console del browser per risolvere i vari errori.
Il problema più frequente sarà la presenza di elementi non autoconclusi: ad esempio dovrai usare <input /> e non <input>.
Nota: avremmo potuto richiamarlo con Navbar() come una normale funzione, ma così è molto più semplice inserirlo nell'HTML.
nota: di fatto stai passando un oggetto JavaScript con una proprietà width.
Nota: quando in JSX vogliamo scrivere un blocco di JavaScript puro, lo mettiamo tra parentesi graffe, come ad esempio in { props.titolo }.
npx create-next-app@latest
Se vi compare un errore relativo all'aggiornamento di npm o altro fate così:npm install -g npm@latest
Se compare un errore relativo all'esecuzione di script in PowerShell aprirla come amministratore ed eseguire:Set-ExecutionPolicy Unrestricted
#todo
Apri la cartella dell'applicazione su Visual Studio Code
npm run dev
#todo
Apri nel browser l'url dell'applicazione:
Collegarsi via Browser a localhost:3000
#todo
Apri pages/index.js e modificalo in modo che appaia così:
Da quale file vengono importati gli stili CSS?
Come vengono usati poi all'interno della pagina?
Le rotte
pages/index.js sarà associato alla rotta /
pages/posts/primo-post.js sarà associato alla rotta /posts/primo-post
#todo
Usa il browser per visitare la nuova pagina.
Il componente Link non è un semplice link: si occupa anche di precaricare le pagine che il visitatore potrebbe selezionare, in modo da rendere l'esperienza di navigazione più reattiva e veloce.
#todo
Usa quello che hai imparato per creare anche nella pagina primo-post un link che rimanda alla home, inserendolo dentro un elemento h2.
Inserisci anche il componente Head per personalizzare il title della pagina.
#todo
Vai nella pagina primo-post e importa il componente appena creato.
Il modulo CSS creerà per noi una classe layout_container__2t4v2 ... potremo quindi creare delle classi con nomi semplici nei diversi moduli senza preoccuparci che possano interferire le une con le altre.
Inoltre Next.js si occuperà di caricare solo i moduli necessari, rendendo il caricamento della pagina più veloce.
App è un componente React di alto livello che racchiude tutte le pagine dell'applicazione: in questo modo sarà possibile mantenere lo stato navigando tra le varie pagine, o aggiungere degli stili globali come stiamo facendo.
Il componente Image di Next.js ottimizza il caricamento delle immagini: agli schermi piccoli saranno inviate versioni ridotte dell'immagine, e le immagini saranno caricate solo quando l'utente scrollerà sulla parte della pagina che le contiene (lazy loading).
.header { display: flex; flex-direction: column; align-items: center; } .backToHome { margin: 3rem 0 0; }
.heading2Xl { font-size: 2.5rem; line-height: 1.2; font-weight: 800; letter-spacing: -0.05rem; margin: 1rem 0; } .headingXl { font-size: 2rem; line-height: 1.3; font-weight: 800; letter-spacing: -0.05rem; margin: 1rem 0; } .headingLg { font-size: 1.5rem; line-height: 1.4; margin: 1rem 0; } .headingMd { font-size: 1.2rem; line-height: 1.5; } .borderCircle { border-radius: 9999px; } .colorInherit { color: inherit; } .padding1px { padding-top: 1px; } .list { list-style: none; padding: 0; margin: 0; } .listItem { margin: 0 0 1.25rem; } .lightText { color: #666; }
import Head from 'next/head'; import Image from 'next/image'; import styles from './layout.module.css'; import utilStyles from '../styles/utils.module.css'; import Link from 'next/link'; const name = 'Your Name'; export const siteTitle = 'Next.js Sample Website'; export default function Layout({ children, home }) { return ( <div className={styles.container}> <Head> <link rel="icon" href="/favicon.ico" /> <meta name="description" content="Learn how to build a personal website using Next.js" /> <meta property="og:image" content={`https://og-image.vercel.app/${encodeURI( siteTitle, )}.png?theme=light&md=0&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg`} /> <meta name="og:title" content={siteTitle} /> <meta name="twitter:card" content="summary_large_image" /> </Head> <header className={styles.header}> {home ? ( <> <Image priority src="/images/profile.jpg" className={utilStyles.borderCircle} height={144} width={144} alt="" /> <h1 className={utilStyles.heading2Xl}>{name}</h1> </> ) : ( <> <Link href="/"> <Image priority src="/images/profile.jpg" className={utilStyles.borderCircle} height={108} width={108} alt="" /> </Link> <h2 className={utilStyles.headingLg}> <Link href="/" className={utilStyles.colorInherit}> {name} </Link> </h2> </> )} </header> <main>{children}</main> {!home && ( <div className={styles.backToHome}> <Link href="/">← Back to home</Link> </div> )} </div> ); }
import Head from 'next/head'; import Layout, { siteTitle } from '../components/layout'; import utilStyles from '../styles/utils.module.css'; export default function Home() { return ( <Layout home> <Head> <title>{siteTitle}</title> </Head> <section className={utilStyles.headingMd}> <p>[Your Self Introduction]</p> <p> (This is a sample website - you’ll be building a site like this on{' '} <a href="https://nextjs.org/learn">our Next.js tutorial</a>.) </p> </section> </Layout> ); }
#todo
Aggiungi un Link alla pagina primo-post e modifica il testo della home page a tuo piacimento.
--- title: 'Two Forms of Pre-rendering' date: '2020-01-01' --- Next.js has two forms of pre-rendering: **Static Generation** and **Server-side Rendering**. The difference is in **when** it generates the HTML for a page. - **Static Generation** is the pre-rendering method that generates the HTML at **build time**. The pre-rendered HTML is then _reused_ on each request. - **Server-side Rendering** is the pre-rendering method that generates the HTML on **each request**. Importantly, Next.js lets you **choose** which pre-rendering form to use for each page. You can create a "hybrid" Next.js app by using Static Generation for most pages and using Server-side Rendering for others.
--- title: 'When to Use Static Generation v.s. Server-side Rendering' date: '2020-01-02' --- We recommend using **Static Generation** (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request. You can use Static Generation for many types of pages, including: - Marketing pages - Blog posts - E-commerce product listings - Help and documentation You should ask yourself: "Can I pre-render this page **ahead** of a user's request?" If the answer is yes, then you should choose Static Generation. On the other hand, Static Generation is **not** a good idea if you cannot pre-render a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request. In that case, you can use **Server-Side Rendering**. It will be slower, but the pre-rendered page will always be up-to-date. Or you can skip pre-rendering and use client-side JavaScript to populate data.
npm install gray-matter
import fs from 'fs'; import path from 'path'; import matter from 'gray-matter'; const postsDirectory = path.join(process.cwd(), 'posts');
export function getSortedPostsData() { // Get file names under /posts const fileNames = fs.readdirSync(postsDirectory); const allPostsData = fileNames.map((fileName) => { // Remove ".md" from file name to get id const id = fileName.replace(/\.md$/, ''); // Read markdown file as string const fullPath = path.join(postsDirectory, fileName); const fileContents = fs.readFileSync(fullPath, 'utf8'); // Use gray-matter to parse the post metadata section const matterResult = matter(fileContents); // Combine the data with the id return { id, ...matterResult.data, }; }); // Sort posts by date return allPostsData.sort((a, b) => { if (a.date < b.date) { return 1; } else { return -1; } }); }
Static generation with data
Nel server di produzione questa funzione viene eseguita una sola volta quando si costruisce il sito (build): NextJS prepara le pagine di HTML vero e proprio che i browser riceveranno. Il caricamento delle pagine così sarà più veloce.
#toDo
Apri la pagina index e importa la funzione creata al passaggio precedente:import { getSortedPostsData } from '../lib/posts';Esporta la funzione getStaticProps che informa NextJS del fatto che vuoi procedere a una generazione statica della pagina, dopo aver importato i dati dei post:export async function getStaticProps() { const allPostsData = getSortedPostsData(); return { props: { allPostsData, }, }; }La funzione restituisce un oggetto contenente i metadati di tutti i post (allPostsData), che saranno passati quindi sotto forma di props al componente Home della pagina con questa piccola modifica:
import Layout from '../../components/layout'; export default function Post() { return <Layout>...</Layout>; }
export function getAllPostIds() { const fileNames = fs.readdirSync(postsDirectory); // Restituisce un array di questo tipo: // [ // { // params: { // id: 'ssg-ssr' // } // }, // { // params: { // id: 'pre-rendering' // } // } // ] return fileNames.map((fileName) => { return { params: { id: fileName.replace(/\.md$/, ''), }, }; }); }
#todo
Torna al file pages/posts/[id].js e importa il metodo appena creato.
Prendi spunto dall'importazione di getSortedPostsData fatta nella pagina index e... occhio al percorso!
export function getPostData(id) { const fullPath = path.join(postsDirectory, `${id}.md`); const fileContents = fs.readFileSync(fullPath, 'utf8'); // Use gray-matter to parse the post metadata section const matterResult = matter(fileContents); // Combine the data with the id return { id, ...matterResult.data, }; }
...in apparenza niente di eccezionale, ma prova a pensare come sono state costruite: tu hai scritto l'articolo in formato md inserendo solo titolo, data e testo... tutto il resto lo ha fatto NextJS, e la cosa bella è che adesso che è tutto pronto lo farà anche per gli altri 100 articoli che inserirai in quella cartella.
L'altra cosa bella è che se un giorno vorrai cambiare il layout del sito, non avrai bisogno di modificare le pagine di tutti gli articoli, perché si aggiorneranno da sole!
npm install remark remark-html
import { remark } from 'remark'; import html from 'remark-html';
Nota: abbiamo aggiunto anche la parola chiave async che ci permetterà di caricare i dati in modo asincrono.
<div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
npm install date-fns
import { parseISO, format } from 'date-fns'; export default function Date({ dateString }) { const date = parseISO(dateString); return <time dateTime={dateString}>{format(date, 'd MMMM yyyy')}</time>; }
<Date dateString={postData.date} />
#todo
Provate a scoprire come cambiare il formato della data in modo che mostri anche il giorno della settimana, ad es. monday.
export default function Post({ postData }) { return ( <Layout> <Head> <title>{postData.title}</title> </Head> <article> <h1 className={utilStyles.headingXl}>{postData.title}</h1> <div className={utilStyles.lightText}> <Date dateString={postData.date} /> </div> <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} /> </article> </Layout> ); }
npm install @mui/material @emotion/react @emotion/styled npm install @fontsource/roboto npm install @mui/icons-material
#todo
Prova a creare un file per il componente BasicButtons col codice visto sopra (non serve la riga che importa React) e a importarlo nella tua pagina index.
<Box sx={{ width: 300, height: 300, backgroundColor: 'primary.dark', '&:hover': { backgroundColor: 'primary.main', opacity: [0.9, 0.8, 0.7], }, }} />
<Container maxWidth="sm"> <Box sx={{ bgcolor: '#cfe8fc', height: '100vh' }} /> </Container>
<Container fixed> <Box sx={{ bgcolor: '#cfe8fc', height: '100vh' }} /> </Container>
<Grid container spacing={2}> <Grid item xs={8}> <Item>xs=8</Item> </Grid> <Grid item xs={4}> <Item>xs=4</Item> </Grid> <Grid item xs={4}> <Item>xs=4</Item> </Grid> <Grid item xs={8}> <Item>xs=8</Item> </Grid> </Grid>
xs={6} md={4}
<Grid container spacing={12}>
#todo
Scegliete uno degli esempi del componente AppBar di MUI e usatelo per creare nella cartella components un componente BarraSuperiore.
Usate poi questo componente all'interno del componente Layout per far comparire la barra di navigazione su tutte le pagine del sito.
Nota: viene passata una funzione anonima usando la sintassi delle funzioni "freccia".
Nota come abbiamo usato il metodo map per creare i diversi Link partendo dall'array sezioni.
Ricordati di importare il componente.
npm install react-material-ui-carousel --save
Denominazione dei componenti
Denominiamo il componente MyCarousel per distinguerlo da quello che importiamo nella prima riga, e che ci servirà da base.
Nota però che nella pagina index abbiamo importato MyCarousel denominandolo semplicemente Carousel.
Transizioni
È possibile cambiare il tipo di transizione agendo su questi attributi del componente che abbiamo importato:
Vantaggi e svantaggi
Il visitatore vedrà sempre i dati più aggiornati, ma questo richiederà un maggiore tempo di esecuzione.
npm install swr
Progetto Open Source
Essendo il nostro un progetto open source nulla vi vieterà di usare un giorno questa collezione di componenti per realizzare dei siti per voi e i vostri clienti.
Requisiti per l'accettazione delle pull request
- corretta denominazione del componente e dei file
- corretta denominazione e passaggio delle props al componente
- uso di componenti MUI e non generici (ad es. Container, Grid, Box e non semplici div)
- corrispondenza del layout a quello richiesto
- corrispondenza dei font
- assenza di file esterni alla propria cartella dev
- nomi dei file (ad es. immagini) tutti in minuscolo
Denominazione dei componenti
Il nome del componente deve corrispondere a quello specificato nel listino qui su books.
Il nome del file deve essere uguale a quello del componente (maiuscole comprese), con l'aggiunta dell'estensione .js
Componente sviluppato da Filippo Bagnoli, Valentina Segato, Elia Barbaric, Lorenzo Alberti, 2F 2022-23
let menu = [ { title: 'Informatico', url: '/informatico' }, { title: 'Energie', url: '/energie' }, { title: 'Elettrico', url: '/elettrico' }, { title: 'Meccanico', url: '/meccanico' }, { title: 'Motoristico', url: '/motoristico' }, { title: 'Carrozzeria', url: '/carrozzeria' }, { title: 'Trasparenza', url: '/trasparenza' }, ] <LandingHero siteName="CFP DON BOSCO" title="Your Story Starts With Us." description="Every landing page needs a small description......." imageUrl="https://url.dell.immagine" opacity={ 0.7 } buttonText="WATCH VIDEO" buttonUrl="https://....." menu={ menu } height={ 80 } />
I parametri buttonText, buttonUrl e menu sono opzionali
let slides = [ { titolo: 'Fatti un bel giro', descrizione: 'Scopri tutti i segreti del nostro Centro con il tour virtuale!', immagine: 'https://source.unsplash.com/random', colore: "#ED4C67", opacity: 0.5, blur: "0.5rem", buttonText: 'Scopri di più!', buttonUrl: 'https:...', }, { titolo: 'Concorso nazionale settore elettrico', descrizione: "A maggio il nostro Centro avrà l'onore di ospitare il Concorso Nazionale del Settore Elettrico: tutti i Centri di Formazione Professionale salesiani d'Italia invieranno i loro campioni per una settimana di sfida e condivisione professionale...", colore: '#22aa22', colore2: 'transparent', // opzionale, per realizzare gradienti, può essere un rgba e viene comunque usata anche opacity }, ]
buttonText e buttonUrl sono facoltative;
se buttonUrl non è presente il bottone non viene visualizzato.
<Carousel slides={slides} maxWidth={false} height="90" >
Componente sviluppato da Alessio Solighetto e Daniel Solighetto, 2F 2022-23
let features = [ { imageUrl: "https....", title: "Free Chat", description: "Divide details about..." }, ... ] <Features title="Why our product is the best" description="This is the paragraph......." features={ features } cardWidth={ 4 } />
Componente sviluppato da Filippo Urban e Zaccaria Cesaro, 2F 2022-23
let members = [ { name: "Alec Thompson", role: "CEO / CO-FOUNDER", description: "And I love you like...", imageUrl: "https..." linkedinUrl: "https...", facebookUrl: "https...", instagramUrl: "https...", maxWidth: "lg" }, ... ] <Team title="Our Awesome Team" description="This is the paragraph......." members={ members } cardWidth={ 3 } />
Componente sviluppato da Lorenzo Alberti e Elia Barbaric, 2F 2022-23
let products = [ { title: "NextJS Material Kit Free", category: "FREE UI KIT", description: "It is a Fre Material-UI Kit with.....", immagineUrl: "https:...", url: "https..." }, ... ] <Products title="Some of Our Awesome Products" description="This is the paragraph......." products={ products } cardWidth={ 4 } borderRadius="10px" aspectRatio="3 / 2" />
Componente sviluppato da Alessio Solighetto e Daniel Solighetto, 2F 2022-23
let testimonials = [ { name: "Alec Thompson", channel: "@Google", text: "Your produtcs, all the kits.......", imageUrl: "https..." }, ... ] <Testimonials title="Our Clients Love Us" description="You need more informations?....." imageUrl="https....." opacity={0.7} testimonials={ testimonials } cardWidth={ 4 } />
Componente sviluppato da Bilal Amara, Thiago Alves Rodrigues e Dionise Rotaru, 2F 2022-23
let socials = [ { title: 'Facebook', imageUrl: 'https...', url: '...' }, { title: 'Instagram', imageUrl: 'https...', url: '...' }, { title: 'Youtube', imageUrl: 'https...', url: '...' }, { title: 'Linkedin', imageUrl: 'https...', url: '...' }, ] let images = [ { title: 'Informatico', imageUrl: 'https...', url: '...' }, { title: 'Informatico', imageUrl: 'https...', url: '...' }, { title: 'Informatico', imageUrl: 'https...', url: '...' }, ] let menu = [ { title: 'BLOG', url: '/informatico' }, { title: 'PRESENTATION', url: '/energie' }, { title: 'DISCOVER', url: '/elettrico' }, { title: 'PAYMENT', url: '/meccanico' }, { title: 'CONTACT US', url: '/motoristico' }, ] <Footer imageUrl="https://immagine di sfondo" color="#777" opacity={1} title1="About Us" description1="Creative Tim is a startup..." title2="Social Feed" socials={socials} title3="I Settori" images={images} menu={menu} copyright="Copyright (C) 2023 9dreams Agency." />
<Paragraph title="Risotto con gli asparagi" subtitle="Una specialità tutta nostrana" topImageUrl="https..." avatarImageUrl="https..." leftImageUrl="https..." rightImageUrl="https..." backgroundImageUrl="https..." backgroundColor="#225533" opacity={0.8} blur="0.2rem" color="white" columnCount={1} maxWidth="lg" sx={{...}} > Qui va tutto il testo del paragrafo... </Paragraph>
Gli attributi sono tutti opzionali.
Componente sviluppato da Filippo Bagnoli e Valentina Segato, 2F 2022-23
<Maps maxWidth='100%' maxHeight='550px' url="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d5580.05343317009!2d12.5710658!3d45.6301996!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x477956fe076b4157%3A0x29fb231d47465883!2sCnos%20Fap%20Don%20Bosco!5e0!3m2!1sit!2sit!4v1680507660807!5m2!1sit!2sit" />
<Table title="Titolo della tabella" subtitle="Sottotitolo della tabella" backgroundImageUrl="https..." backgroundColor="#EE5A24" opacity={0.8} blur="0.2rem" color="white" elevation="1" rows={[ ["Cognome", "Nome", "Età"], ["Paoletti", "Vigilio", 75], ["Scaroletti", "Emma", 45], ["Anselmi", "Ada", 32], ]} />
<Calendar title="Prima settimana" cardWidth={3} events={settimana1} /> let settimana1 = [ { date: "Lunedì 19 Giugno", morning: "Attività regolare", afternoon: "Giochi al parco e tornei", evening: "ore 20.45 Film TRANSFORMERS - IL RISVEGLIO", immagineUrl: "/images/calendario/transformers.png", }, ];
aspectRatio="3 / 2" // proporzioni di ritaglio delle immagini
<News title={null} data={data} />
limit={6} // numero massimo di post presentati aspectRatio="3 / 2" // proporzioni di ritaglio delle immagini
È possibile usare SwiperNews al posto di News, con le stesse props: viene visualizzato come slider.
Entrambi fanno usp di un componente NewsCard apposito.
<Featured data={data} />
limit: 6 // numero massimo di post presentati maxWidth: false // larghezza del container height: 90 // altezza del container
let sponsor = [ 'https://agsol.com/wp-content/uploads/2018/09/new-microsoft-logo-SIZED-SQUARE.jpg', 'https://assets.ubuntu.com/v1/57a889f6-ubuntu-logo112.png', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Cisco_logo_blue_2016.svg/1200px-Cisco_logo_blue_2016.svg.png', 'https://dev.socialidnow.com/images/9/94/Mikrotik-logo.png', 'https://www.raspberrypi.org/app/uploads/2018/03/RPi-Logo-Reg-SCREEN.png', 'https://www.arduino.cc/en/uploads/Trademark/ArduinoCommunityLogo.png', 'https://images-eu.ssl-images-amazon.com/images/I/413W%2BhcdyEL.png', 'https://www.comitec.it/img/logo.png?v=1.1', 'https://archive.donboscosandona.it/img/ck/1e0a315dbf7a64beb118a36bbc2148c8d20f55a3.png', ] <Sponsor title='I nostri sponsor' logos={sponsor} />
npm start