@happyvertical/smrt-template-site-static-json 0.30.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/AGENTS.md +30 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +115 -0
- package/index.js +8 -0
- package/package.json +43 -0
- package/template/.env.example +8 -0
- package/template/AGENTS.md +21 -0
- package/template/CLAUDE.md +1 -0
- package/template/README.md +59 -0
- package/template/data/.gitkeep +2 -0
- package/template/package.json +21 -0
- package/template/scripts/init-data.ts +56 -0
- package/template/smrt.config.js +138 -0
- package/template/src/app.css +156 -0
- package/template/src/app.d.ts +13 -0
- package/template/src/app.html +12 -0
- package/template/src/lib/components/WeatherHeader.svelte +59 -0
- package/template/src/lib/utils/markdown.ts +35 -0
- package/template/src/routes/+layout.server.ts +193 -0
- package/template/src/routes/+layout.svelte +73 -0
- package/template/src/routes/+page.server.ts +60 -0
- package/template/src/routes/+page.svelte +118 -0
- package/template/src/routes/about/+page.server.ts +8 -0
- package/template/src/routes/about/+page.svelte +92 -0
- package/template/src/routes/contact/+page.server.ts +8 -0
- package/template/src/routes/contact/+page.svelte +95 -0
- package/template/src/site.config.ts +35 -0
- package/template/svelte.config.js +19 -0
- package/template/tsconfig.json +14 -0
- package/template/vite.config.ts +6 -0
- package/template.config.js +86 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# template-site-static-json
|
|
2
|
+
|
|
3
|
+
Scaffold template for static community news sites with JSON data. Used by `smrt gnode create`.
|
|
4
|
+
|
|
5
|
+
## Exports
|
|
6
|
+
|
|
7
|
+
- Template config with placeholder mappings (site name, location, timezone, coordinates)
|
|
8
|
+
- Template directory path and file path utilities
|
|
9
|
+
|
|
10
|
+
## Template Contents
|
|
11
|
+
|
|
12
|
+
- `template.config.js` — placeholder definitions and post-generation hooks
|
|
13
|
+
- `template/scripts/init-data.ts` — data initialization script
|
|
14
|
+
- `template/src/site.config.ts` — typed access to `smrt.config.js` site section (`initSiteConfig()`/`getSite()`)
|
|
15
|
+
- `template/src/lib/components/WeatherHeader.svelte` — local weather-bar shim (was previously imported from `@happyvertical/smrt-svelte`, but that package dropped the component before the 0.24.x baseline). The shim renders the caelus-shaped `forecast` payload; consumers should customize for their data layer if they pull a different upstream.
|
|
16
|
+
|
|
17
|
+
## Key Patterns
|
|
18
|
+
|
|
19
|
+
- **Placeholder system**: variables (site name, location, timezone) replaced during `smrt gnode create`
|
|
20
|
+
- **Post-generation hooks**: run after template files are copied (e.g., init-data.ts)
|
|
21
|
+
- **Dependency injection**: `template/package.json` ships with empty `dependencies`/`devDependencies`; the scaffolder injects entries from `template.config.js` at generation time, so version bumps live in `template.config.js` only.
|
|
22
|
+
- **Workflow scripts**: `workflow:caelus` and `workflow:praeco` are currently stubs that print a clear "upstream package needs a CLI bin" message and exit with status 1. Two independent reasons today's scaffold can't run them:
|
|
23
|
+
1. The upstream `@happyvertical/caelus` and `@happyvertical/praeco` packages are library-only — they do not declare a `bin` field, so `npx @happyvertical/caelus` / `npx @happyvertical/praeco` exits with "could not determine executable to run."
|
|
24
|
+
2. The template does not ship a local workflow shim (e.g. `template/src/workflows/caelus.ts`) that would import the upstream package and invoke the workflow from code. A `tsx`-based script would work fine if such a shim existed; the previous baseline pointed at `tsx src/workflows/caelus.ts` and failed only because the shim file was missing, not because tsx requires upstream to ship a bin.
|
|
25
|
+
|
|
26
|
+
Once upstream ships bins, replace the stubs with `npx @happyvertical/caelus --config smrt.config.js` / `npx @happyvertical/praeco --config smrt.config.js` (the scoped names — the unscoped `caelus` is a 404 on the public registry). Alternatively, add a `template/src/workflows/<name>.ts` shim that imports the upstream package's main export and invokes the workflow, then point the script at `tsx src/workflows/<name>.ts`. Until either is in place, callers who need these workflows should write the shim themselves in their generated project.
|
|
27
|
+
|
|
28
|
+
## Runtime Dependencies
|
|
29
|
+
|
|
30
|
+
Template projects use: `smrt-content`, `smrt-events`, `smrt-places`, `smrt-profiles`, `smrt-ui`.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright <2025> <Happy Vertical Corporation>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @happyvertical/smrt-template-site-static-json
|
|
2
|
+
|
|
3
|
+
Template for static community news sites with JSON-based data storage. Generates a SvelteKit static site with weather integration (Caelus) and council meeting scraping (Praeco).
|
|
4
|
+
|
|
5
|
+
## What This Template Provides
|
|
6
|
+
|
|
7
|
+
- SvelteKit with `adapter-static` for static site generation
|
|
8
|
+
- JSON file-based data storage in `data/`
|
|
9
|
+
- Config-driven site identity, navigation, categories, and theming via `smrt.config.js`
|
|
10
|
+
- Weather forecasts via Caelus (Environment Canada)
|
|
11
|
+
- Council meeting scraping and article generation via Praeco
|
|
12
|
+
- Typed site config helper (`initSiteConfig()`/`getSite()`)
|
|
13
|
+
- Pre-built routes: home, about, contact
|
|
14
|
+
- Markdown utility for content rendering
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
- Node.js 18+
|
|
19
|
+
- pnpm (recommended)
|
|
20
|
+
- Gemini API key (for Praeco article generation)
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
smrt gnode create my-town-site --template site-static-json \
|
|
26
|
+
--location "My Town, AB" \
|
|
27
|
+
--lat 53.5 --lon -113.5
|
|
28
|
+
|
|
29
|
+
cd my-town-site
|
|
30
|
+
pnpm install
|
|
31
|
+
cp .env.example .env # Add your GEMINI_API_KEY
|
|
32
|
+
pnpm run init-data # Initialize data directory
|
|
33
|
+
pnpm dev # Start dev server
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Environment Variables
|
|
37
|
+
|
|
38
|
+
Defined in `.env.example`:
|
|
39
|
+
|
|
40
|
+
| Variable | Required | Description |
|
|
41
|
+
|----------|----------|-------------|
|
|
42
|
+
| `GEMINI_API_KEY` | Yes | Google Gemini API key for Praeco article generation |
|
|
43
|
+
| `PUBLIC_GTM_ID` | No | Google Tag Manager container ID |
|
|
44
|
+
| `CUSTOM_DOMAIN` | No | Custom domain for deployment |
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
Edit `smrt.config.js` to customize. Key sections:
|
|
49
|
+
|
|
50
|
+
- **`site`** -- name, description, location, navigation links, theme colors
|
|
51
|
+
- **`categories`** -- content categories for routing (e.g., `politics/local`)
|
|
52
|
+
- **`modules.praeco`** -- council meeting sources and report configurations
|
|
53
|
+
- **`modules.caelus`** -- weather location (set automatically from `--lat`/`--lon` flags)
|
|
54
|
+
|
|
55
|
+
## Available Scripts
|
|
56
|
+
|
|
57
|
+
| Script | Description |
|
|
58
|
+
|--------|-------------|
|
|
59
|
+
| `pnpm dev` | Start development server |
|
|
60
|
+
| `pnpm build` | Build static site to `./build` |
|
|
61
|
+
| `pnpm preview` | Preview the built site |
|
|
62
|
+
| `pnpm run init-data` | Initialize JSON data files |
|
|
63
|
+
| `pnpm run workflow:caelus` | Fetch weather data |
|
|
64
|
+
| `pnpm run workflow:praeco` | Scrape council meetings |
|
|
65
|
+
| `pnpm run validate:json` | Validate JSON data files |
|
|
66
|
+
| `pnpm run validate:slugs` | Validate content slugs |
|
|
67
|
+
|
|
68
|
+
## Template Structure
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
template/
|
|
72
|
+
├── .env.example # Environment variables
|
|
73
|
+
├── .gitignore
|
|
74
|
+
├── package.json # Scripts and dependency placeholders
|
|
75
|
+
├── smrt.config.js # Site identity, modules, theme
|
|
76
|
+
├── svelte.config.js # SvelteKit with adapter-static
|
|
77
|
+
├── tsconfig.json
|
|
78
|
+
├── vite.config.ts
|
|
79
|
+
├── data/ # JSON data storage directory
|
|
80
|
+
├── scripts/
|
|
81
|
+
│ └── init-data.ts # Data initialization script
|
|
82
|
+
└── src/
|
|
83
|
+
├── app.css # Global styles
|
|
84
|
+
├── app.d.ts # SvelteKit type declarations
|
|
85
|
+
├── app.html # HTML shell
|
|
86
|
+
├── site.config.ts # Typed config helper (initSiteConfig/getSite)
|
|
87
|
+
├── lib/
|
|
88
|
+
│ └── utils/
|
|
89
|
+
│ └── markdown.ts # Markdown rendering utility
|
|
90
|
+
└── routes/
|
|
91
|
+
├── +layout.server.ts # Loads site config for all routes
|
|
92
|
+
├── +layout.svelte # Root layout
|
|
93
|
+
├── +page.server.ts # Home page data
|
|
94
|
+
├── +page.svelte # Home page
|
|
95
|
+
├── about/ # About page
|
|
96
|
+
└── contact/ # Contact page
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Placeholder Substitution
|
|
100
|
+
|
|
101
|
+
During `smrt gnode create`, placeholders like `{{SITE_NAME}}`, `{{LOCATION_NAME}}`, `{{LATITUDE}}`, `{{LONGITUDE}}`, and `{{TIMEZONE}}` are replaced from CLI flags. See `template.config.js` for the full mapping.
|
|
102
|
+
|
|
103
|
+
## Deployment
|
|
104
|
+
|
|
105
|
+
This template uses SvelteKit's static adapter. Build and deploy to any static host:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pnpm build
|
|
109
|
+
# Deploy ./build to S3, Netlify, Vercel, Cloudflare Pages, etc.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Related
|
|
113
|
+
|
|
114
|
+
- [SMRT Framework](https://github.com/happyvertical/smrt)
|
|
115
|
+
- [SvelteKit](https://kit.svelte.dev/)
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@happyvertical/smrt-template-site-static-json",
|
|
3
|
+
"version": "0.30.0",
|
|
4
|
+
"description": "Static community site template with JSON data storage and SMRT framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js",
|
|
9
|
+
"./template/*": "./template/*"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"CLAUDE.md",
|
|
13
|
+
"README.md",
|
|
14
|
+
"index.js",
|
|
15
|
+
"template",
|
|
16
|
+
"template.config.js",
|
|
17
|
+
"AGENTS.md"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"smrt",
|
|
21
|
+
"sveltekit",
|
|
22
|
+
"template",
|
|
23
|
+
"scaffold",
|
|
24
|
+
"community-site",
|
|
25
|
+
"static-site",
|
|
26
|
+
"json"
|
|
27
|
+
],
|
|
28
|
+
"author": "HappyVertical",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/happyvertical/smrt.git",
|
|
33
|
+
"directory": "packages/template-site-static-json"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@happyvertical/smrt-core": "0.30.0",
|
|
37
|
+
"@happyvertical/smrt-config": "0.30.0"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"registry": "https://registry.npmjs.org",
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# SMRT Static JSON Site
|
|
2
|
+
|
|
3
|
+
This project uses SMRT configuration and generated local data for a static site.
|
|
4
|
+
If SMRT objects are added, enable the SMRT Vite plugin so local knowledge
|
|
5
|
+
artifacts are generated in `.smrt/smrt-knowledge.json`.
|
|
6
|
+
|
|
7
|
+
## Agent Workflow
|
|
8
|
+
|
|
9
|
+
- Treat `AGENTS.md` as the canonical project guidance file.
|
|
10
|
+
- Keep `CLAUDE.md` as the one-line `@AGENTS.md` shim.
|
|
11
|
+
- Use `smrt knowledge:architecture-context --format markdown` or the
|
|
12
|
+
`build-domain-architecture-context` MCP tool when adding SMRT packages.
|
|
13
|
+
- Use `knowledge: { tags, summary, risks }` on domain objects that need
|
|
14
|
+
package-specific review guidance.
|
|
15
|
+
|
|
16
|
+
## Safety
|
|
17
|
+
|
|
18
|
+
- Do not expose `/__smrt/knowledge` HTTP routes in production without explicit
|
|
19
|
+
admin auth.
|
|
20
|
+
- Keep generated data and `.smrt` artifacts out of source control unless the
|
|
21
|
+
project intentionally publishes a package artifact.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# {{SITE_NAME}}
|
|
2
|
+
|
|
3
|
+
Local news and community information for {{LOCATION_NAME}}.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies
|
|
9
|
+
pnpm install
|
|
10
|
+
|
|
11
|
+
# Initialize data files
|
|
12
|
+
pnpm run init-data
|
|
13
|
+
|
|
14
|
+
# Start development server
|
|
15
|
+
pnpm dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Configuration
|
|
19
|
+
|
|
20
|
+
Edit `smrt.config.js` to configure:
|
|
21
|
+
|
|
22
|
+
- **Site identity**: Name, location, navigation
|
|
23
|
+
- **Data sources**: Council meeting URLs for Praeco
|
|
24
|
+
- **Weather**: Location coordinates for Caelus
|
|
25
|
+
|
|
26
|
+
## Workflows
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Fetch weather data
|
|
30
|
+
pnpm workflow:caelus
|
|
31
|
+
|
|
32
|
+
# Generate articles from council meetings
|
|
33
|
+
pnpm workflow:praeco
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Deployment
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Build static site
|
|
40
|
+
pnpm build
|
|
41
|
+
|
|
42
|
+
# Preview production build
|
|
43
|
+
pnpm preview
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Deploy the `build/` directory to any static host (S3, Netlify, Vercel, etc.).
|
|
47
|
+
|
|
48
|
+
## Project Structure
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
├── smrt.config.js # Site configuration
|
|
52
|
+
├── data/ # JSON data storage
|
|
53
|
+
├── scripts/ # Utility scripts
|
|
54
|
+
└── src/
|
|
55
|
+
├── site.config.ts # Config helper
|
|
56
|
+
├── app.css # Global styles
|
|
57
|
+
├── routes/ # SvelteKit pages
|
|
58
|
+
└── lib/ # Shared utilities
|
|
59
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PACKAGE_NAME}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite dev",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview",
|
|
10
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
11
|
+
"typecheck": "svelte-kit sync && tsc --noEmit && svelte-check --tsconfig ./tsconfig.json",
|
|
12
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
13
|
+
"init-data": "tsx scripts/init-data.ts",
|
|
14
|
+
"workflow:caelus": "node -e \"console.error('workflow:caelus requires @happyvertical/caelus to ship a CLI bin (tracked upstream). For now invoke the workflow from a script that imports the package directly.'); process.exit(1)\"",
|
|
15
|
+
"workflow:praeco": "node -e \"console.error('workflow:praeco requires @happyvertical/praeco to ship a CLI bin (tracked upstream). For now invoke the workflow from a script that imports the package directly.'); process.exit(1)\"",
|
|
16
|
+
"validate:json": "tsx scripts/validate-json.ts",
|
|
17
|
+
"validate:slugs": "tsx scripts/validate-slugs.ts"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {},
|
|
20
|
+
"dependencies": {}
|
|
21
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize Data Directory
|
|
3
|
+
*
|
|
4
|
+
* Creates empty JSON files for the site's data storage.
|
|
5
|
+
* Run this after creating a new site: pnpm run init-data
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { mkdir, writeFile, access } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
const DATA_DIR = join(process.cwd(), 'data');
|
|
12
|
+
|
|
13
|
+
const INITIAL_FILES: Record<string, any[]> = {
|
|
14
|
+
'contents.json': [],
|
|
15
|
+
'events.json': [],
|
|
16
|
+
'places.json': [],
|
|
17
|
+
'profiles.json': [],
|
|
18
|
+
'assets.json': [],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
async function initData() {
|
|
22
|
+
console.log('Initializing data directory...\n');
|
|
23
|
+
|
|
24
|
+
// Ensure data directory exists
|
|
25
|
+
try {
|
|
26
|
+
await access(DATA_DIR);
|
|
27
|
+
console.log(' ✓ data/ directory exists');
|
|
28
|
+
} catch {
|
|
29
|
+
await mkdir(DATA_DIR, { recursive: true });
|
|
30
|
+
console.log(' ✓ Created data/ directory');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create each data file if it doesn't exist
|
|
34
|
+
for (const [filename, initialData] of Object.entries(INITIAL_FILES)) {
|
|
35
|
+
const filepath = join(DATA_DIR, filename);
|
|
36
|
+
try {
|
|
37
|
+
await access(filepath);
|
|
38
|
+
console.log(` • ${filename} exists, skipping`);
|
|
39
|
+
} catch {
|
|
40
|
+
await writeFile(filepath, JSON.stringify(initialData, null, 2));
|
|
41
|
+
console.log(` ✓ Created ${filename}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log('\n✅ Data initialization complete!');
|
|
46
|
+
console.log('\nNext steps:');
|
|
47
|
+
console.log(' 1. Configure smrt.config.js with your council sources');
|
|
48
|
+
console.log(' 2. Run pnpm workflow:caelus to fetch weather data');
|
|
49
|
+
console.log(' 3. Run pnpm workflow:praeco to generate articles');
|
|
50
|
+
console.log(' 4. Run pnpm dev to start the development server');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
initData().catch((error) => {
|
|
54
|
+
console.error('Failed to initialize data:', error);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMRT Configuration for {{SITE_NAME}}
|
|
3
|
+
*
|
|
4
|
+
* This file configures site identity, navigation, data sources, and workflows.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
// Site identity (used by components for titles, navigation, SEO)
|
|
9
|
+
site: {
|
|
10
|
+
name: '{{SITE_NAME}}',
|
|
11
|
+
shortName: '{{SITE_SHORT_NAME}}',
|
|
12
|
+
description: 'Local news and community information for {{LOCATION_NAME}}',
|
|
13
|
+
url: 'https://{{PACKAGE_NAME}}.com',
|
|
14
|
+
location: {
|
|
15
|
+
name: '{{LOCATION_NAME}}',
|
|
16
|
+
latitude: {{LATITUDE}},
|
|
17
|
+
longitude: {{LONGITUDE}},
|
|
18
|
+
timezone: '{{TIMEZONE}}',
|
|
19
|
+
},
|
|
20
|
+
navigation: {
|
|
21
|
+
primary: [
|
|
22
|
+
{ label: 'Politics', href: '/politics' },
|
|
23
|
+
{ label: 'Weather', href: '/weather' },
|
|
24
|
+
],
|
|
25
|
+
footer: [
|
|
26
|
+
{ label: 'About', href: '/about' },
|
|
27
|
+
{ label: 'Contact', href: '/contact' },
|
|
28
|
+
{ label: 'RSS', href: '/rss.xml' },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
theme: {
|
|
32
|
+
primaryColor: '#1976d2',
|
|
33
|
+
primaryLight: '#e3f2fd',
|
|
34
|
+
primaryDark: '#0d47a1',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// Site-wide category definitions (for routing/navigation)
|
|
39
|
+
categories: {
|
|
40
|
+
politics: {
|
|
41
|
+
name: 'Politics',
|
|
42
|
+
children: {
|
|
43
|
+
local: { name: 'Local Government' },
|
|
44
|
+
county: { name: 'County Government' },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
community: {
|
|
48
|
+
name: 'Community',
|
|
49
|
+
children: {
|
|
50
|
+
events: { name: 'Events' },
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// Agent/developer knowledge defaults
|
|
56
|
+
knowledge: {
|
|
57
|
+
enabled: true,
|
|
58
|
+
api: {
|
|
59
|
+
enabled: false,
|
|
60
|
+
basePath: '/__smrt/knowledge',
|
|
61
|
+
requireAdmin: true,
|
|
62
|
+
includeDocs: false,
|
|
63
|
+
includePrompts: false,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// Global package settings
|
|
68
|
+
packages: {
|
|
69
|
+
cli: {
|
|
70
|
+
verbose: true,
|
|
71
|
+
database: {
|
|
72
|
+
type: 'json',
|
|
73
|
+
url: './data',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
ai: {
|
|
77
|
+
defaultProvider: 'claude-cli',
|
|
78
|
+
defaultModel: 'sonnet',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
// Module-specific configurations
|
|
83
|
+
modules: {
|
|
84
|
+
// Praeco module configuration (meeting scraper)
|
|
85
|
+
praeco: {
|
|
86
|
+
db: {
|
|
87
|
+
type: 'json',
|
|
88
|
+
url: './data',
|
|
89
|
+
writeStrategy: 'immediate',
|
|
90
|
+
},
|
|
91
|
+
ai: {
|
|
92
|
+
type: 'gemini',
|
|
93
|
+
model: 'gemini-2.0-flash-exp',
|
|
94
|
+
apiKey: process.env.GEMINI_API_KEY,
|
|
95
|
+
},
|
|
96
|
+
analyzeOptions: {
|
|
97
|
+
detailLevel: 'comprehensive',
|
|
98
|
+
},
|
|
99
|
+
// Add your council sources here
|
|
100
|
+
sources: [
|
|
101
|
+
// Example:
|
|
102
|
+
// {
|
|
103
|
+
// type: 'documents',
|
|
104
|
+
// council: 'my-council',
|
|
105
|
+
// url: 'https://example.com/meetings/',
|
|
106
|
+
// },
|
|
107
|
+
],
|
|
108
|
+
// Add your report configurations here
|
|
109
|
+
reports: [
|
|
110
|
+
// Example:
|
|
111
|
+
// {
|
|
112
|
+
// type: 'meeting-recap',
|
|
113
|
+
// council: 'my-council',
|
|
114
|
+
// category: 'politics/local',
|
|
115
|
+
// author: '{{SITE_SHORT_NAME}} Reporter',
|
|
116
|
+
// role: 'You are a professional journalist writing for {{LOCATION_NAME}} residents.',
|
|
117
|
+
// },
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
// Caelus module configuration (weather)
|
|
122
|
+
caelus: {
|
|
123
|
+
db: {
|
|
124
|
+
type: 'json',
|
|
125
|
+
url: './data',
|
|
126
|
+
writeStrategy: 'immediate',
|
|
127
|
+
clearCache: true,
|
|
128
|
+
},
|
|
129
|
+
provider: 'environment-canada',
|
|
130
|
+
location: {
|
|
131
|
+
name: '{{LOCATION_NAME}}',
|
|
132
|
+
latitude: {{LATITUDE}},
|
|
133
|
+
longitude: {{LONGITUDE}},
|
|
134
|
+
},
|
|
135
|
+
logLevel: 'info',
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global CSS for {{SITE_NAME}}
|
|
3
|
+
* Design tokens as CSS custom properties
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
:root {
|
|
7
|
+
/* Colors - Primary (customize these in smrt.config.js site.theme) */
|
|
8
|
+
--color-primary: #1976d2;
|
|
9
|
+
--color-primary-main: #1976d2;
|
|
10
|
+
--color-primary-light: #e3f2fd;
|
|
11
|
+
--color-primary-dark: #0d47a1;
|
|
12
|
+
|
|
13
|
+
/* Colors - Neutral */
|
|
14
|
+
--color-neutral-white: #ffffff;
|
|
15
|
+
--color-neutral-gray100: #f5f5f5;
|
|
16
|
+
--color-neutral-gray200: #eeeeee;
|
|
17
|
+
--color-neutral-gray300: #e0e0e0;
|
|
18
|
+
--color-neutral-gray400: #bdbdbd;
|
|
19
|
+
--color-neutral-gray500: #9e9e9e;
|
|
20
|
+
--color-neutral-gray600: #757575;
|
|
21
|
+
--color-neutral-gray700: #616161;
|
|
22
|
+
--color-neutral-gray800: #424242;
|
|
23
|
+
--color-neutral-gray900: #212121;
|
|
24
|
+
|
|
25
|
+
/* Colors - Semantic */
|
|
26
|
+
--color-semantic-success: #4caf50;
|
|
27
|
+
--color-semantic-warning: #ff9800;
|
|
28
|
+
--color-semantic-error: #f44336;
|
|
29
|
+
--color-semantic-info: #2196f3;
|
|
30
|
+
|
|
31
|
+
/* Colors - Text */
|
|
32
|
+
--color-text-primary: #333333;
|
|
33
|
+
--color-text-secondary: #666666;
|
|
34
|
+
--color-text-disabled: #9e9e9e;
|
|
35
|
+
--color-text-inverse: #ffffff;
|
|
36
|
+
|
|
37
|
+
/* Spacing */
|
|
38
|
+
--spacing-xs: 0.25rem;
|
|
39
|
+
--spacing-sm: 0.5rem;
|
|
40
|
+
--spacing-md: 1rem;
|
|
41
|
+
--spacing-lg: 1.5rem;
|
|
42
|
+
--spacing-xl: 2rem;
|
|
43
|
+
--spacing-2xl: 3rem;
|
|
44
|
+
--spacing-3xl: 4rem;
|
|
45
|
+
|
|
46
|
+
/* Typography */
|
|
47
|
+
--font-family-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
48
|
+
--font-family-serif: Georgia, 'Times New Roman', serif;
|
|
49
|
+
--font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
50
|
+
|
|
51
|
+
--font-size-xs: 0.75rem;
|
|
52
|
+
--font-size-sm: 0.875rem;
|
|
53
|
+
--font-size-base: 1rem;
|
|
54
|
+
--font-size-lg: 1.125rem;
|
|
55
|
+
--font-size-xl: 1.25rem;
|
|
56
|
+
--font-size-2xl: 1.5rem;
|
|
57
|
+
--font-size-3xl: 1.875rem;
|
|
58
|
+
--font-size-4xl: 2.25rem;
|
|
59
|
+
|
|
60
|
+
--font-weight-normal: 400;
|
|
61
|
+
--font-weight-medium: 500;
|
|
62
|
+
--font-weight-semibold: 600;
|
|
63
|
+
--font-weight-bold: 700;
|
|
64
|
+
|
|
65
|
+
--line-height-tight: 1.2;
|
|
66
|
+
--line-height-normal: 1.6;
|
|
67
|
+
--line-height-relaxed: 1.8;
|
|
68
|
+
|
|
69
|
+
/* Shadows */
|
|
70
|
+
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
71
|
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
72
|
+
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
73
|
+
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
|
74
|
+
|
|
75
|
+
/* Border Radius */
|
|
76
|
+
--radius-sm: 4px;
|
|
77
|
+
--radius-md: 8px;
|
|
78
|
+
--radius-lg: 12px;
|
|
79
|
+
--radius-full: 9999px;
|
|
80
|
+
|
|
81
|
+
/* Transitions */
|
|
82
|
+
--transition-fast: 150ms ease;
|
|
83
|
+
--transition-base: 200ms ease;
|
|
84
|
+
--transition-slow: 300ms ease;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Reset and base styles */
|
|
88
|
+
*,
|
|
89
|
+
*::before,
|
|
90
|
+
*::after {
|
|
91
|
+
box-sizing: border-box;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
body {
|
|
95
|
+
margin: 0;
|
|
96
|
+
font-family: var(--font-family-sans);
|
|
97
|
+
font-size: var(--font-size-base);
|
|
98
|
+
line-height: var(--line-height-normal);
|
|
99
|
+
color: var(--color-text-primary);
|
|
100
|
+
background: var(--color-neutral-white);
|
|
101
|
+
-webkit-font-smoothing: antialiased;
|
|
102
|
+
-moz-osx-font-smoothing: grayscale;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Typography defaults */
|
|
106
|
+
h1, h2, h3, h4, h5, h6 {
|
|
107
|
+
margin: 0;
|
|
108
|
+
font-weight: var(--font-weight-semibold);
|
|
109
|
+
line-height: var(--line-height-tight);
|
|
110
|
+
color: var(--color-text-primary);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
p {
|
|
114
|
+
margin: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
a {
|
|
118
|
+
color: var(--color-primary-main);
|
|
119
|
+
text-decoration: none;
|
|
120
|
+
transition: color var(--transition-fast);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
a:hover {
|
|
124
|
+
color: var(--color-primary-dark);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Focus styles for accessibility */
|
|
128
|
+
:focus-visible {
|
|
129
|
+
outline: 2px solid var(--color-primary-main);
|
|
130
|
+
outline-offset: 2px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Remove default button styles */
|
|
134
|
+
button {
|
|
135
|
+
font-family: inherit;
|
|
136
|
+
font-size: inherit;
|
|
137
|
+
line-height: inherit;
|
|
138
|
+
margin: 0;
|
|
139
|
+
padding: 0;
|
|
140
|
+
border: none;
|
|
141
|
+
background: none;
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Utility classes */
|
|
146
|
+
.sr-only {
|
|
147
|
+
position: absolute;
|
|
148
|
+
width: 1px;
|
|
149
|
+
height: 1px;
|
|
150
|
+
padding: 0;
|
|
151
|
+
margin: -1px;
|
|
152
|
+
overflow: hidden;
|
|
153
|
+
clip: rect(0, 0, 0, 0);
|
|
154
|
+
white-space: nowrap;
|
|
155
|
+
border-width: 0;
|
|
156
|
+
}
|