create-materialize 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cristiano Casazza
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,19 @@
1
- # Temporary Holding Version
1
+ # create-materialize
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Crea un nuovo sito Materialize con un comando: npm create materialize@latest
4
+
5
+ ```bash
6
+ npm create materialize@latest
7
+ ```
8
+
9
+ Chiede la cartella, copia il sito di partenza e installa le dipendenze. Poi `npm run dev` e il pannello su http://localhost:4321/admin.
10
+
11
+ ## Materialize
12
+
13
+ CMS open source con editor visuale: le pagine si disegnano sulla tela, il sito è fatto di file statici veloci. Per un nuovo sito (serve Node 24):
14
+
15
+ ```bash
16
+ npm create materialize@latest
17
+ ```
18
+
19
+ Documentazione e codice: https://github.com/materializecms/materialize · Licenza MIT.
package/package.json CHANGED
@@ -1,6 +1,27 @@
1
1
  {
2
2
  "name": "create-materialize",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Crea un nuovo sito Materialize con un comando: npm create materialize@latest",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/materializecms/materialize.git",
10
+ "directory": "packages/create-materialize"
11
+ },
12
+ "homepage": "https://github.com/materializecms/materialize#readme",
13
+ "bugs": "https://github.com/materializecms/materialize/issues",
14
+ "bin": {
15
+ "create-materialize": "src/index.js"
16
+ },
17
+ "files": [
18
+ "src",
19
+ "template"
20
+ ],
21
+ "engines": {
22
+ "node": ">=24"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ }
27
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function createProject(target: string, siteName?: string): Promise<string>;
package/src/index.js ADDED
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'node:child_process';
3
+ import { existsSync, realpathSync } from 'node:fs';
4
+ import { cp, readdir, readFile, rename, writeFile } from 'node:fs/promises';
5
+ import { createRequire } from 'node:module';
6
+ import { basename, dirname, join, relative, resolve } from 'node:path';
7
+ import { createInterface } from 'node:readline/promises';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { parseArgs, styleText } from 'node:util';
10
+ const TEMPLATE = join(dirname(fileURLToPath(import.meta.url)), '..', 'template');
11
+ /** Materialize packages move together: a new site uses the version of this starter. */
12
+ const VERSION = createRequire(import.meta.url)('../package.json').version;
13
+ // npm drops dotfiles named .gitignore when publishing, so the template ships them without the dot.
14
+ const RENAMES = { gitignore: '.gitignore' };
15
+ const TEXT_FILES = ['package.json', 'materialize.config.ts', 'README.md', 'src/layouts/Site.astro'];
16
+ export async function createProject(target, siteName) {
17
+ const dir = resolve(target);
18
+ if (existsSync(dir) && (await readdir(dir)).length > 0) {
19
+ throw new Error(`La cartella ${dir} esiste e non è vuota`);
20
+ }
21
+ await cp(TEMPLATE, dir, { recursive: true });
22
+ for (const [from, to] of Object.entries(RENAMES)) {
23
+ if (existsSync(join(dir, from)))
24
+ await rename(join(dir, from), join(dir, to));
25
+ }
26
+ const slug = basename(dir)
27
+ .toLowerCase()
28
+ .replace(/[^a-z0-9-]+/g, '-')
29
+ .replace(/^-+|-+$/g, '') || 'materialize-site';
30
+ const name = siteName ??
31
+ basename(dir)
32
+ .replace(/[-_]+/g, ' ')
33
+ .replace(/^\w/, (c) => c.toUpperCase());
34
+ for (const file of TEXT_FILES) {
35
+ const path = join(dir, file);
36
+ if (!existsSync(path))
37
+ continue;
38
+ const text = await readFile(path, 'utf8');
39
+ await writeFile(path, text
40
+ .replaceAll('__PACKAGE_NAME__', slug)
41
+ // Inside TypeScript and Astro strings.
42
+ .replaceAll('__SITE_NAME__', file === 'README.md' ? name : name.replaceAll("'", "\\'"))
43
+ .replaceAll('__VERSION__', VERSION));
44
+ }
45
+ return dir;
46
+ }
47
+ /** The package manager that ran us (npm create, pnpm create, …), so the site installs with the same one. */
48
+ function packageManager() {
49
+ const agent = process.env.npm_config_user_agent ?? '';
50
+ return ['pnpm', 'yarn', 'bun'].find((pm) => agent.startsWith(`${pm}/`)) ?? 'npm';
51
+ }
52
+ function install(dir, pm) {
53
+ return new Promise((done) => {
54
+ const child = spawn(pm, ['install'], { cwd: dir, stdio: 'inherit', shell: process.platform === 'win32' });
55
+ child.on('close', (code) => done(code === 0));
56
+ child.on('error', () => done(false));
57
+ });
58
+ }
59
+ async function ask(question, fallback) {
60
+ if (!process.stdin.isTTY)
61
+ return fallback;
62
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
63
+ try {
64
+ return (await rl.question(` ${question} ${styleText('dim', `(${fallback})`)} `)).trim() || fallback;
65
+ }
66
+ finally {
67
+ rl.close();
68
+ }
69
+ }
70
+ async function main() {
71
+ const { values, positionals } = parseArgs({
72
+ allowPositionals: true,
73
+ options: { 'no-install': { type: 'boolean' }, help: { type: 'boolean', short: 'h' } },
74
+ });
75
+ if (values.help) {
76
+ console.log('\n npm create materialize@latest [cartella] [--no-install]\n');
77
+ return;
78
+ }
79
+ console.log();
80
+ console.log(` ${styleText(['bold', 'blue'], 'Materialize')} ${styleText('dim', VERSION)}`);
81
+ console.log();
82
+ const target = positionals[0] ?? (await ask('Dove creo il sito?', 'il-mio-sito'));
83
+ const dir = await createProject(target);
84
+ const rel = relative(process.cwd(), dir) || '.';
85
+ console.log(` ${styleText('green', '✓')} Progetto creato in ${rel}`);
86
+ const pm = packageManager();
87
+ let installed = false;
88
+ if (!values['no-install']) {
89
+ console.log(` ${styleText('dim', `Installo le dipendenze con ${pm}…`)}`);
90
+ console.log();
91
+ installed = await install(dir, pm);
92
+ console.log();
93
+ if (!installed)
94
+ console.log(` ${styleText('yellow', '!')} Installazione non riuscita: riprova a mano.`);
95
+ }
96
+ const run = pm === 'npm' ? 'npm run' : pm;
97
+ console.log(' Per iniziare:');
98
+ console.log();
99
+ if (rel !== '.')
100
+ console.log(` cd ${rel}`);
101
+ if (!installed)
102
+ console.log(` ${pm} install`);
103
+ console.log(` ${run} dev`);
104
+ console.log();
105
+ console.log(` Poi apri ${styleText('blue', 'http://localhost:4321/admin')} e crea il tuo account.`);
106
+ console.log();
107
+ }
108
+ // Run as a command (through the bin symlink npm creates), not when imported by tests.
109
+ if (process.argv[1] && realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) {
110
+ try {
111
+ await main();
112
+ }
113
+ catch (error) {
114
+ console.error(` ${styleText('red', error instanceof Error ? error.message : String(error))}`);
115
+ process.exit(1);
116
+ }
117
+ }
@@ -0,0 +1,30 @@
1
+ # __SITE_NAME__
2
+
3
+ Sito creato con [Materialize](https://www.npmjs.com/package/create-materialize): contenuti nel pannello, pagine statiche e veloci.
4
+
5
+ ## Avvio
6
+
7
+ ```bash
8
+ npm run dev
9
+ ```
10
+
11
+ Apri http://localhost:4321/admin, crea l’account di amministratore e poi una pagina con indirizzo `home`: parti da una pagina pronta o componila con le sezioni della libreria.
12
+
13
+ ## Dove mettere le mani
14
+
15
+ | Cosa | Dove |
16
+ | --- | --- |
17
+ | Pagine, sezioni, animazioni | Il pannello, sulla tela |
18
+ | Colori, caratteri e forme del sito | Il pannello, scheda **Stili** dell’editor |
19
+ | Modello dei contenuti (raccolte e campi) | `materialize.config.ts` |
20
+ | Struttura HTML comune (meta, caratteri) | `src/layouts/Site.astro` |
21
+
22
+ ## Comandi
23
+
24
+ | Comando | Cosa fa |
25
+ | --- | --- |
26
+ | `npm run dev` | Pannello e sito con anteprima dal vivo |
27
+ | `npm run build` | Sito statico in `dist/`, da pubblicare su qualsiasi hosting |
28
+ | `npm run start` | Pannello e sito in produzione: ogni pubblicazione ricostruisce il sito |
29
+
30
+ Contenuti e immagini restano in `.materialize/`: fanne un backup.
@@ -0,0 +1,10 @@
1
+ import node from '@astrojs/node'
2
+ import materialize from '@materializecms/astro'
3
+ import { defineConfig } from 'astro/config'
4
+
5
+ export default defineConfig({
6
+ // Pages are static files; only the editor's live preview renders on demand.
7
+ output: 'static',
8
+ adapter: node({ mode: 'middleware' }),
9
+ integrations: [materialize()],
10
+ })
@@ -0,0 +1,7 @@
1
+ node_modules/
2
+ dist/
3
+ .astro/
4
+ .materialize/
5
+ .env
6
+ .env.*
7
+ .DS_Store
@@ -0,0 +1,31 @@
1
+ import { defineCollection, defineConfig, f } from '@materializecms/core'
2
+
3
+ // Il modello dei contenuti del sito. Le pagine si compongono sulla tela del pannello,
4
+ // con le sezioni della libreria; qui si aggiungono raccolte e campi quando servono.
5
+
6
+ const pages = defineCollection({
7
+ name: 'pages',
8
+ label: 'Pagine',
9
+ url: (page) => (page.slug === 'home' ? '/' : `/${page.slug}`),
10
+ fields: {
11
+ title: f.text({ label: 'Titolo', required: true, max: 80 }),
12
+ slug: f.slug({ label: 'Indirizzo', from: 'title' }),
13
+ page: f.page({ label: 'Pagina' }),
14
+ seo: f.seo({ label: 'Motori di ricerca' }),
15
+ },
16
+ })
17
+
18
+ const settings = defineCollection({
19
+ name: 'settings',
20
+ label: 'Impostazioni del sito',
21
+ singleton: true,
22
+ fields: {
23
+ siteName: f.text({ label: 'Nome del sito', required: true }),
24
+ email: f.text({ label: 'Email' }),
25
+ },
26
+ })
27
+
28
+ export default defineConfig({
29
+ site: { name: '__SITE_NAME__' },
30
+ collections: [pages, settings],
31
+ })
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "__PACKAGE_NAME__",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "materialize dev",
7
+ "build": "materialize build",
8
+ "start": "materialize start"
9
+ },
10
+ "dependencies": {
11
+ "@astrojs/node": "^11.1.9",
12
+ "@fontsource-variable/fraunces": "^5.3.0",
13
+ "@fontsource-variable/geist": "^5.3.0",
14
+ "@fontsource-variable/geist-mono": "^5.3.0",
15
+ "@fontsource-variable/inter": "^5.3.0",
16
+ "@fontsource/instrument-serif": "^5.3.0",
17
+ "@materializecms/astro": "__VERSION__",
18
+ "@materializecms/cli": "__VERSION__",
19
+ "@materializecms/core": "__VERSION__",
20
+ "astro": "^7.4.4"
21
+ },
22
+ "engines": {
23
+ "node": ">=24"
24
+ }
25
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="7" fill="#111113"/><rect x="9" y="9" width="14" height="14" rx="3" fill="#fff"/></svg>
@@ -0,0 +1,53 @@
1
+ ---
2
+ // Every font a theme can choose: browsers download only the ones a page uses.
3
+ import '@fontsource-variable/geist'
4
+ import '@fontsource-variable/geist-mono'
5
+ import '@fontsource/instrument-serif'
6
+ import '@fontsource-variable/fraunces'
7
+ import '@fontsource-variable/inter'
8
+ import Tracking from '@materializecms/astro/components/Tracking.astro'
9
+ import { type Entry, getSingleton, getTheme } from '@materializecms/astro/content'
10
+ import { pageRootStyle } from '@materializecms/core/page'
11
+
12
+ interface Props {
13
+ title: string
14
+ description?: string
15
+ entry?: Entry
16
+ /** Rendered inside the editor canvas. */
17
+ preview?: boolean
18
+ }
19
+
20
+ const { title, description, entry } = Astro.props
21
+ const settings = await getSingleton('settings')
22
+ const siteName: string = settings?.data.siteName ?? '__SITE_NAME__'
23
+ const seo = entry?.data.seo ?? {}
24
+ const pageTitle = seo.title || (entry?.url === '/' ? siteName : `${title} · ${siteName}`)
25
+ const metaDescription = seo.description || description
26
+ const root = pageRootStyle(await getTheme())
27
+ ---
28
+
29
+ <!doctype html>
30
+ <html lang={entry?.locale ?? 'it'}>
31
+ <head>
32
+ <meta charset="utf-8" />
33
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
34
+ <title>{pageTitle}</title>
35
+ {metaDescription && <meta name="description" content={metaDescription} />}
36
+ {seo.noindex && <meta name="robots" content="noindex" />}
37
+ {seo.image?.src && <meta property="og:image" content={seo.image.src} />}
38
+ <meta property="og:title" content={pageTitle} />
39
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
40
+ <Tracking lang={entry?.locale} />
41
+ {Astro.site && entry?.url && <link rel="canonical" href={new URL(entry.url, Astro.site)} />}
42
+ </head>
43
+ <body style={root}>
44
+ <slot />
45
+ </body>
46
+ </html>
47
+
48
+ <style is:global>
49
+ body {
50
+ margin: 0;
51
+ -webkit-font-smoothing: antialiased;
52
+ }
53
+ </style>
@@ -0,0 +1,27 @@
1
+ ---
2
+ import Site from '../layouts/Site.astro'
3
+ ---
4
+
5
+ <Site title="Pagina non trovata">
6
+ <main>
7
+ <h1>Questa pagina non c’è.</h1>
8
+ <p>Forse è stata spostata. <a href="/">Torna alla home</a>.</p>
9
+ </main>
10
+ </Site>
11
+
12
+ <style>
13
+ main {
14
+ max-width: 720px;
15
+ margin: 0 auto;
16
+ padding: 160px 24px;
17
+ font-family: 'Geist Variable', system-ui, sans-serif;
18
+ }
19
+ h1 {
20
+ margin: 0;
21
+ font: 400 clamp(44px, 7vw, 88px) / 1 'Instrument Serif', Georgia, serif;
22
+ }
23
+ p {
24
+ margin-top: 24px;
25
+ font-size: 18px;
26
+ }
27
+ </style>
@@ -0,0 +1,74 @@
1
+ ---
2
+ import Page from '@materializecms/astro/components/Page.astro'
3
+ import { type Entry, getRoutes } from '@materializecms/astro/content'
4
+ import Site from '../layouts/Site.astro'
5
+
6
+ // One static page for every published document that has an address.
7
+ // Until a home page is published, the home shows how to start.
8
+ export async function getStaticPaths() {
9
+ const routes: { params: { path: string | undefined }; props: { entry: Entry | null } }[] = await getRoutes()
10
+ if (!routes.some((r) => r.params.path === undefined)) routes.push({ params: { path: undefined }, props: { entry: null } })
11
+ return routes
12
+ }
13
+
14
+ const { entry } = Astro.props as { entry: Entry | null }
15
+ ---
16
+
17
+ {
18
+ entry ? (
19
+ <Site title={entry.title} entry={entry}>
20
+ <Page sections={entry.data.page} document={entry} />
21
+ </Site>
22
+ ) : (
23
+ <Site title="Benvenuto">
24
+ <main class="welcome">
25
+ <p class="eyebrow">Materialize</p>
26
+ <h1>Il sito è pronto.</h1>
27
+ <p>Apri il pannello, crea una pagina con indirizzo <code>home</code> e pubblicala: comparirà qui.</p>
28
+ <a href="/admin">Apri il pannello →</a>
29
+ </main>
30
+ </Site>
31
+ )
32
+ }
33
+
34
+ <style>
35
+ .welcome {
36
+ max-width: 720px;
37
+ margin: 0 auto;
38
+ padding: clamp(96px, 16vw, 200px) 24px;
39
+ font-family: 'Geist Variable', system-ui, sans-serif;
40
+ }
41
+ .eyebrow {
42
+ font: 500 12px/1 'Geist Mono Variable', ui-monospace, monospace;
43
+ letter-spacing: 0.08em;
44
+ text-transform: uppercase;
45
+ opacity: 0.6;
46
+ }
47
+ h1 {
48
+ margin: 20px 0 0;
49
+ font: 400 clamp(48px, 8vw, 92px) / 1 'Instrument Serif', Georgia, serif;
50
+ letter-spacing: -0.025em;
51
+ }
52
+ p {
53
+ margin: 24px 0 0;
54
+ font-size: 18px;
55
+ line-height: 1.6;
56
+ opacity: 0.75;
57
+ }
58
+ code {
59
+ font-size: 0.9em;
60
+ padding: 2px 6px;
61
+ border-radius: 6px;
62
+ background: rgb(127 127 127 / 0.14);
63
+ }
64
+ a {
65
+ display: inline-flex;
66
+ margin-top: 36px;
67
+ padding: 14px 24px;
68
+ border-radius: 999px;
69
+ background: #a8502a;
70
+ color: #fff;
71
+ font-weight: 500;
72
+ text-decoration: none;
73
+ }
74
+ </style>
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "astro/tsconfigs/strict",
3
+ "include": [".astro/types.d.ts", "**/*", "node_modules/@materializecms/astro/src/virtual.d.ts"],
4
+ "exclude": ["dist"]
5
+ }