From 6796e102e0b031249989c477e13881efd1624bb6 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 7 Jun 2026 13:06:16 +0200 Subject: [PATCH 1/2] add template + document framework in root README template/README.md: stripped to a one-liner bootstrap command. README.md: full project docs (structure, add page, add component, build.sh). Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: GnomeZworc --- README.md | 60 +++- template/.gitignore | 5 + template/README.md | 6 + template/build.sh | 333 ++++++++++++++++++++++ template/components.yml | 39 +++ template/sources/config.json | 3 + template/sources/core/config.js | 4 + template/sources/core/menu.js | 10 + template/sources/core/registry.js | 8 + template/sources/core/router.js | 41 +++ template/sources/favicon.svg | 5 + template/sources/index.html | 106 +++++++ template/sources/pages/home/home.css | 24 ++ template/sources/pages/home/home.js | 14 + template/sources/pages/home/index.html | 1 + template/sources/pages/home/manifest.json | 5 + 16 files changed, 663 insertions(+), 1 deletion(-) create mode 100644 template/.gitignore create mode 100644 template/README.md create mode 100755 template/build.sh create mode 100644 template/components.yml create mode 100644 template/sources/config.json create mode 100644 template/sources/core/config.js create mode 100644 template/sources/core/menu.js create mode 100644 template/sources/core/registry.js create mode 100644 template/sources/core/router.js create mode 100644 template/sources/favicon.svg create mode 100644 template/sources/index.html create mode 100644 template/sources/pages/home/home.css create mode 100644 template/sources/pages/home/home.js create mode 100644 template/sources/pages/home/index.html create mode 100644 template/sources/pages/home/manifest.json diff --git a/README.md b/README.md index 77350a1..a38eff7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,61 @@ # Syn -Ce projet est un framwork web base sur un javascript tres simple. +Framework web minimaliste basé sur JavaScript vanilla et les Web Components. +Routage hash-based, composants déclarés dans `components.yml`, build via `build.sh`. + +## Structure d'un projet + +``` +├── sources/ # Code servi — déployer ce dossier +│ ├── index.html +│ ├── favicon.svg +│ ├── config.json # Config runtime (api_url, tokens…) +│ ├── core/ # Framework core +│ ├── components/ # Téléchargés par build.sh (gitignored) +│ ├── vendor/ # Libs tierces (gitignored) +│ └── pages/ +│ └── / # Une page = un dossier +├── components.yml # Source de vérité +└── build.sh # Télécharge les remotes + génère les JSON +``` + +## Démarrer un projet + +```bash +cp -r template/ mon-projet/ +cd mon-projet/ +./build.sh +python3 -m http.server 8000 --directory sources/ +``` + +## Ajouter une page + +1. Créer `sources/pages//` avec : + - `manifest.json` — `{ "route", "label", "icon" }` + - `index.html` — fragment HTML (ex. ``) + - `.js` — `customElements.define` + `export function init(main) {}` + - `.css` — styles scopés à la page (optionnel) +2. Déclarer sous `local_pages:` dans `components.yml` +3. Ajouter la route à `menu:` si visible dans la nav +4. `./build.sh` + +## Ajouter un composant + +1. Déclarer sous `components:` dans `components.yml` : + ```yaml + components: + - name: mon-composant + repo: https://git.example.com/org/mon-composant + ref: main + ``` +2. `./build.sh` — télécharge dans `sources/components/mon-composant/` + +## build.sh + +``` +./build.sh # build complet +./build.sh --check # valide le manifest sans télécharger +``` + +Dépendances : `yq` (mikefarah v4), `jq`, `curl`. +Variable optionnelle : `GIT_TOKEN` pour les repos privés. diff --git a/template/.gitignore b/template/.gitignore new file mode 100644 index 0000000..b62440f --- /dev/null +++ b/template/.gitignore @@ -0,0 +1,5 @@ +sources/components.json +sources/navigation.json +sources/pages.json +sources/vendor/ +sources/components/ diff --git a/template/README.md b/template/README.md new file mode 100644 index 0000000..a254b32 --- /dev/null +++ b/template/README.md @@ -0,0 +1,6 @@ +# Syn — Project Template + +```bash +./build.sh +python3 -m http.server 8000 --directory sources/ +``` diff --git a/template/build.sh b/template/build.sh new file mode 100755 index 0000000..aa754dc --- /dev/null +++ b/template/build.sh @@ -0,0 +1,333 @@ +#!/usr/bin/env bash +# Build the web UI component set from components.yml. +# +# ./build.sh build (download remote components + generate components.json) +# ./build.sh --check validate manifest and entry files without downloading +# +# Reads components.yml, downloads each remote component into components// +# at the requested ref, then generates components.json (runtime load list) and +# components.lock.json (resolved commit pins). +# +# Dependencies: yq (mikefarah/yq v4), jq, curl +# Optional env: +# GIT_TOKEN forge token for private repos (sent as "Authorization: token …") + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +WEB_DIR="${SCRIPT_DIR}/sources" +MANIFEST="${SCRIPT_DIR}/components.yml" +COMPONENTS_DIR="${WEB_DIR}/components" +OUTPUT="${WEB_DIR}/components.json" +LOCKFILE="${WEB_DIR}/components.lock.json" +GIT_TOKEN="${GIT_TOKEN:-}" + +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' +log() { echo -e "${GREEN}[+]${NC} $*"; } +warn() { echo -e "${YELLOW}[!]${NC} $*"; } +info() { echo -e "${BLUE}[i]${NC} $*"; } +die() { echo -e "${RED}[-]${NC} $*" >&2; exit 1; } + +CHECK_ONLY=false +[[ "${1:-}" == "--check" ]] && CHECK_ONLY=true + +# ── Dependency + manifest guards ──────────────────────────────────────────────── + +command -v yq &>/dev/null || die "yq is required (mikefarah/yq v4)" +command -v jq &>/dev/null || die "jq is required" +command -v curl &>/dev/null || die "curl is required" +[[ -f "$MANIFEST" ]] || die "manifest not found: $MANIFEST" + +# ── Forge API helpers ─────────────────────────────────────────────────────────── + +api_get() { + local url="$1" + local args=(-sf -H "Accept: application/json") + [[ -n "$GIT_TOKEN" ]] && args+=(-H "Authorization: token ${GIT_TOKEN}") + curl "${args[@]}" "$url" || die "API request failed: $url" +} + +raw_dl() { + local url="$1" out="$2" + local args=(-sfL) + [[ -n "$GIT_TOKEN" ]] && args+=(-H "Authorization: token ${GIT_TOKEN}") + curl "${args[@]}" "$url" -o "$out" || die "download failed: $url" +} + +# Split a repo URL into "server owner repo". +# https://git.g3e.fr/team-reseau/vpc-panel → https://git.g3e.fr team-reseau vpc-panel +parse_repo_url() { + local url="$1" + url="${url%.git}"; url="${url%/}" + local proto="${url%%://*}" + local rest="${url#*://}" + local host="${rest%%/*}" + local path="${rest#*/}" + [[ "$path" == "$rest" || -z "$path" ]] && die "invalid repo URL (need owner/repo): $1" + local owner="${path%/*}" repo="${path##*/}" + [[ -z "$owner" || -z "$repo" ]] && die "invalid repo URL (need owner/repo): $1" + echo "${proto}://${host}" "$owner" "$repo" +} + +# Build the commits API URL — handles GitHub (api.github.com) vs Gitea (/api/v1). +forge_commits_url() { + local server="$1" owner="$2" repo="$3" ref="$4" + if [[ "$server" == "https://github.com" ]]; then + echo "https://api.github.com/repos/${owner}/${repo}/commits?sha=${ref}&per_page=1" + else + echo "${server}/api/v1/repos/${owner}/${repo}/commits?sha=${ref}&limit=1" + fi +} + +# Build the contents API URL for a given path (empty = repo root). +forge_contents_url() { + local server="$1" owner="$2" repo="$3" ref="$4" path="$5" + if [[ "$server" == "https://github.com" ]]; then + if [[ -z "$path" ]]; then + echo "https://api.github.com/repos/${owner}/${repo}/contents?ref=${ref}" + else + echo "https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${ref}" + fi + else + if [[ -z "$path" ]]; then + echo "${server}/api/v1/repos/${owner}/${repo}/contents?ref=${ref}" + else + echo "${server}/api/v1/repos/${owner}/${repo}/contents/${path}?ref=${ref}" + fi + fi +} + +resolve_commit() { + local server="$1" owner="$2" repo="$3" ref="$4" + api_get "$(forge_commits_url "$server" "$owner" "$repo" "$ref")" \ + | jq -r '.[0].sha // empty' +} + +# Recursively download a repo path (relative to repo root) into dest dir. +download_path() { + local server="$1" owner="$2" repo="$3" ref="$4" rpath="$5" dest="$6" + + local api + api="$(forge_contents_url "$server" "$owner" "$repo" "$ref" "$rpath")" + + local listing + listing="$(api_get "$api")" + + mkdir -p "$dest" + while IFS= read -r entry; do + local type name dl path + type="$(jq -r '.type' <<<"$entry")" + name="$(jq -r '.name' <<<"$entry")" + dl="$( jq -r '.download_url // ""' <<<"$entry")" + path="$(jq -r '.path' <<<"$entry")" + + if [[ "$type" == "dir" ]]; then + download_path "$server" "$owner" "$repo" "$ref" "$path" "${dest}/${name}" + else + [[ -z "$dl" ]] && die "no download_url for ${path} in ${owner}/${repo}@${ref}" + raw_dl "$dl" "${dest}/${name}" + fi + done < <(echo "$listing" | jq -c 'if type=="array" then .[] else . end') +} + +# ── Read manifest ──────────────────────────────────────────────────────────────── + +PAGES_DIR="${WEB_DIR}/pages" + +mapfile -t LOCALS < <(yq '(.local_components // [])[]' "$MANIFEST") +mapfile -t REMOTES < <(yq '(.components // [])[] | [.name, .repo, (.ref // "main")] | join("|")' "$MANIFEST") +mapfile -t LOCAL_PAGES < <(yq '(.local_pages // [])[]' "$MANIFEST") +mapfile -t REMOTE_PAGES < <(yq '(.remote_pages // [])[] | [.name, .repo, (.ref // "main")] | join("|")' "$MANIFEST") +mapfile -t VENDORS < <(yq '(.vendors // [])[] | [.name, .repo, (.ref // "main"), (.path // ""), (.dest // "")] | join("|")' "$MANIFEST") + +# ── Download vendors ──────────────────────────────────────────────────────────── +# Vendors are third-party libraries downloaded into web/vendor/ at build time. +# They are gitignored and never loaded by components.json — components import +# them directly via relative paths (e.g. ../../vendor/novnc/core/rfb.js). + +for spec in "${VENDORS[@]}"; do + [[ -z "$spec" ]] && continue + IFS='|' read -r name repo ref vpath dest <<<"$spec" + [[ -z "$name" || -z "$repo" ]] && die "vendor entry missing name or repo: '$spec'" + + read -r server owner gitrepo <<<"$(parse_repo_url "$repo")" + [[ -z "$dest" ]] && dest="vendor/${name}" + local_dest="${WEB_DIR}/${dest}" + + if [[ "$CHECK_ONLY" == true ]]; then + info "would fetch vendor ${name} from ${repo}@${ref} path=${vpath:-/}" + continue + fi + + log "fetching vendor ${name} ← ${owner}/${gitrepo}@${ref}${vpath:+ path=}${vpath}" + commit="$(resolve_commit "$server" "$owner" "$gitrepo" "$ref")" + [[ -z "$commit" ]] && die "cannot resolve ref '${ref}' in ${owner}/${gitrepo}" + + rm -rf "$local_dest" + download_path "$server" "$owner" "$gitrepo" "$ref" "$vpath" "$local_dest" + info " vendor '${name}' → ${dest} (${commit:0:12})" +done + +# Ordered list of load paths for components.json +declare -a LOAD_PATHS=() + +# ── Validate locals ────────────────────────────────────────────────────────────── + +for name in "${LOCALS[@]}"; do + [[ -z "$name" ]] && continue + entry="${COMPONENTS_DIR}/${name}/${name}.js" + if [[ ! -f "$entry" ]]; then + die "local component '${name}' missing entry file: components/${name}/${name}.js" + fi + LOAD_PATHS+=("components/${name}/${name}.js") +done + +# ── Download remotes ───────────────────────────────────────────────────────────── + +LOCK_ENTRIES="[]" + +for spec in "${REMOTES[@]}"; do + [[ -z "$spec" ]] && continue + IFS='|' read -r name repo ref <<<"$spec" + [[ -z "$name" || -z "$repo" ]] && die "manifest entry missing name or repo: '$spec'" + + read -r server owner gitrepo <<<"$(parse_repo_url "$repo")" + dest="${COMPONENTS_DIR}/${name}" + + if [[ "$CHECK_ONLY" == true ]]; then + info "would fetch ${name} from ${repo}@${ref}" + commit="$(resolve_commit "$server" "$owner" "$gitrepo" "$ref" || true)" + [[ -z "$commit" ]] && warn " could not resolve ref '${ref}' in ${owner}/${gitrepo}" + LOAD_PATHS+=("components/${name}/${name}.js") + continue + fi + + log "fetching ${name} ← ${owner}/${gitrepo}@${ref}" + commit="$(resolve_commit "$server" "$owner" "$gitrepo" "$ref")" + [[ -z "$commit" ]] && die "cannot resolve ref '${ref}' in ${owner}/${gitrepo}" + + rm -rf "$dest" + download_path "$server" "$owner" "$gitrepo" "$ref" "" "$dest" + + entry="${dest}/${name}.js" + [[ -f "$entry" ]] || die "component '${name}' has no ${name}.js at repo root" + + LOAD_PATHS+=("components/${name}/${name}.js") + LOCK_ENTRIES="$(jq \ + --arg name "$name" --arg repo "$repo" --arg ref "$ref" --arg commit "$commit" \ + '. + [{name:$name, repo:$repo, ref:$ref, commit:$commit}]' <<<"$LOCK_ENTRIES")" + info " pinned ${commit:0:12}" +done + +# ── Generate components.json ───────────────────────────────────────────────────── + +if [[ "$CHECK_ONLY" == true ]]; then + log "check passed: ${#LOAD_PATHS[@]} components, manifest valid" + exit 0 +fi + +printf '%s\n' "${LOAD_PATHS[@]}" | jq -R . | jq -s . > "$OUTPUT" +echo "$LOCK_ENTRIES" | jq '.' > "$LOCKFILE" + +log "wrote ${OUTPUT} (${#LOAD_PATHS[@]} components)" +log "wrote ${LOCKFILE} ($(jq 'length' <<<"$LOCK_ENTRIES") remote pins)" + +# ── Process pages ──────────────────────────────────────────────────────────────── + +PAGE_ENTRIES="[]" + +# Collect page metadata from a directory into PAGE_ENTRIES. +# Detects css/js presence automatically — both are optional. +add_page_entry() { + local name="$1" dir="$2" + local manifest="${dir}/manifest.json" + local html="${dir}/index.html" + + [[ -f "$manifest" ]] || die "page '${name}' missing manifest.json in ${dir}" + [[ -f "$html" ]] || die "page '${name}' missing index.html in ${dir}" + + local route label icon css_arg js_arg + route=$(jq -r '.route' "$manifest") + label=$(jq -r '.label' "$manifest") + icon=$(jq -r '.icon' "$manifest") + css_arg="null"; js_arg="null" + [[ -f "${dir}/${name}.css" ]] && css_arg="\"pages/${name}/${name}.css\"" + [[ -f "${dir}/${name}.js" ]] && js_arg="\"pages/${name}/${name}.js\"" + + PAGE_ENTRIES="$(jq \ + --arg route "$route" --arg label "$label" --arg icon "$icon" \ + --arg html "pages/${name}/index.html" \ + --argjson css "$css_arg" --argjson js "$js_arg" \ + '. + [{route:$route, label:$label, icon:$icon, html:$html, css:$css, js:$js}]' \ + <<<"$PAGE_ENTRIES")" + info " page '${name}' → /#/${route}$([ "$css_arg" != "null" ] && echo " +css")$([ "$js_arg" != "null" ] && echo " +js")" +} + +# Local pages +for name in "${LOCAL_PAGES[@]}"; do + [[ -z "$name" ]] && continue + add_page_entry "$name" "${PAGES_DIR}/${name}" +done + +# Remote pages — download then register +for spec in "${REMOTE_PAGES[@]}"; do + [[ -z "$spec" ]] && continue + IFS='|' read -r name repo ref <<<"$spec" + [[ -z "$name" || -z "$repo" ]] && die "remote_pages entry missing name or repo" + + read -r server owner gitrepo <<<"$(parse_repo_url "$repo")" + dest="${PAGES_DIR}/${name}" + + if [[ "$CHECK_ONLY" == true ]]; then + info "would fetch page ${name} from ${repo}@${ref}" + continue + fi + + log "fetching page ${name} ← ${owner}/${gitrepo}@${ref}" + commit="$(resolve_commit "$server" "$owner" "$gitrepo" "$ref")" + [[ -z "$commit" ]] && die "cannot resolve ref '${ref}' in ${owner}/${gitrepo}" + + rm -rf "$dest" + download_path "$server" "$owner" "$gitrepo" "$ref" "" "$dest" + add_page_entry "$name" "$dest" + info " pinned ${commit:0:12}" +done + +if [[ "$CHECK_ONLY" == false ]]; then + # Build navigation.json from menu: section. + # Convert full manifest to JSON once (single yq call) then jq handles all logic. + # Menu items: string → page lookup, object → pass-through (separator/section). + manifest_json=$(yq -o json '.' "$MANIFEST") + menu_json=$(echo "$manifest_json" | jq -c '.menu // []') + menu_len=$(echo "$menu_json" | jq 'length') + + if [[ "$menu_len" -gt 0 ]]; then + NAV_ENTRIES=$(jq -n \ + --argjson menu "$menu_json" \ + --argjson pages "$PAGE_ENTRIES" \ + 'def resolve($pages): + . as $r | $pages[] | select(.route == $r) | { label, href: ("#/" + .route), icon }; + [ $menu[] | + if type == "string" + then resolve($pages) + elif .type == "group" + then { type: "group", label: .label, icon: (.icon // ""), + children: [ .children[]? | + if type == "string" then resolve($pages) else . end ] } + else . + end + ]') + else + # No menu defined — use all pages in discovery order + NAV_ENTRIES=$(echo "$PAGE_ENTRIES" | \ + jq '[.[] | { label, href: ("#/" + .route), icon }]') + fi + + # pages.json — full list (all pages, original discovery order) + echo "$PAGE_ENTRIES" | jq '.' > "${WEB_DIR}/pages.json" + + # navigation.json — write NAV_ENTRIES as-is (already correctly shaped) + echo "$NAV_ENTRIES" | jq '.' > "${WEB_DIR}/navigation.json" + + log "wrote pages.json ($(echo "$PAGE_ENTRIES" | jq 'length') pages) + navigation.json ($(echo "$NAV_ENTRIES" | jq 'length') in menu)" +fi diff --git a/template/components.yml b/template/components.yml new file mode 100644 index 0000000..e02fe27 --- /dev/null +++ b/template/components.yml @@ -0,0 +1,39 @@ +# Component manifest — source of truth for the web UI. +# +# Edit this file, then run ./build.sh to: +# - download every remote component into sources/components// +# - generate sources/components.json (the runtime load list) in declared order +# +# Load order matters: service components (login-gate, api-client) must come +# before the components that consume them. + +# Local components shipped inside this repo. Not downloaded — listed here only +# so build.sh can place them in the generated load order. +local_components: [] + +# Remote components fetched from git at build time. +# Each is its own repo; its root must contain .js and manifest.json. +# +# - name: side-nav +# repo: https://git.g3e.fr/syonad/syn-side-nav +# ref: main +components: [] + +# Vendor libraries — downloaded into sources/vendor/ at build time (gitignored). +# Components import them via relative paths, never via components.json. +vendors: [] + +# Pages — each page is a self-contained directory (JS + CSS + index.html + manifest.json). +# Page manifest.json must contain: route, label, icon. +# Page JS must export an optional init(main) function. + +local_pages: + - home + +remote_pages: [] + +# Menu — order and visibility in the navigation. +# List routes in desired display order. +# A page not listed here is accessible via /#/route but hidden from the nav. +menu: + - home diff --git a/template/sources/config.json b/template/sources/config.json new file mode 100644 index 0000000..d67ec5d --- /dev/null +++ b/template/sources/config.json @@ -0,0 +1,3 @@ +{ + "api_url": "http://localhost:8080" +} diff --git a/template/sources/core/config.js b/template/sources/core/config.js new file mode 100644 index 0000000..51f9b56 --- /dev/null +++ b/template/sources/core/config.js @@ -0,0 +1,4 @@ +const response = await fetch('./config.json') +if (!response.ok) throw new Error('Failed to load config.json') + +export const config = await response.json() diff --git a/template/sources/core/menu.js b/template/sources/core/menu.js new file mode 100644 index 0000000..931ff0f --- /dev/null +++ b/template/sources/core/menu.js @@ -0,0 +1,10 @@ +// Dynamic menu loader. +// Fetches data for groups declared with empty children in navigation.json +// and injects them into side-nav after it is ready. +// +// Imported non-blocking from index.html — does not delay routing. +// +// Example usage: +// const nav = document.querySelector('side-nav') +// await nav.ready +// nav.setGroupChildren('My Group', [{ label: 'Item', href: '#/route', icon: 'icon' }]) diff --git a/template/sources/core/registry.js b/template/sources/core/registry.js new file mode 100644 index 0000000..071e398 --- /dev/null +++ b/template/sources/core/registry.js @@ -0,0 +1,8 @@ +const response = await fetch('./components.json') +if (!response.ok) throw new Error('Failed to load components.json') + +const components = await response.json() + +for (const path of components) { + await import(`../${path}`) +} diff --git a/template/sources/core/router.js b/template/sources/core/router.js new file mode 100644 index 0000000..00d73cb --- /dev/null +++ b/template/sources/core/router.js @@ -0,0 +1,41 @@ +const response = await fetch('./pages.json') +if (!response.ok) throw new Error('router: failed to load pages.json — run build.sh') +const PAGES = await response.json() + +const MODULE_CACHE = new Map() +let activeCSS = null + +function currentRoute() { + const hash = window.location.hash.replace(/^#\//, '') || PAGES[0]?.route || '' + return hash.split('?')[0] +} + +async function render(routeName) { + const page = PAGES.find(p => p.route === routeName) ?? PAGES[0] + const main = document.querySelector('main') + if (!main || !page) return + + const htmlRes = await fetch(page.html) + if (!htmlRes.ok) throw new Error(`router: failed to load ${page.html}`) + main.innerHTML = await htmlRes.text() + + activeCSS?.remove() + activeCSS = null + if (page.css) { + const link = document.createElement('link') + link.rel = 'stylesheet' + link.href = page.css + document.head.appendChild(link) + activeCSS = link + } + + if (page.js) { + if (!MODULE_CACHE.has(page.js)) { + MODULE_CACHE.set(page.js, await import(`../${page.js}`)) + } + MODULE_CACHE.get(page.js)?.init?.(main) + } +} + +await render(currentRoute()) +window.addEventListener('hashchange', () => render(currentRoute())) diff --git a/template/sources/favicon.svg b/template/sources/favicon.svg new file mode 100644 index 0000000..d90c23c --- /dev/null +++ b/template/sources/favicon.svg @@ -0,0 +1,5 @@ + + + S + diff --git a/template/sources/index.html b/template/sources/index.html new file mode 100644 index 0000000..d70a704 --- /dev/null +++ b/template/sources/index.html @@ -0,0 +1,106 @@ + + + + + + Mon Projet + + + + +
+

Mon Projet

+ powered by Syn +
+
+ +
+ +
+
+ +
+ + + + diff --git a/template/sources/pages/home/home.css b/template/sources/pages/home/home.css new file mode 100644 index 0000000..fc04649 --- /dev/null +++ b/template/sources/pages/home/home.css @@ -0,0 +1,24 @@ +.home { + padding: 8px; +} + +.home h2 { + font-size: 20px; + font-weight: 600; + color: #cdd6f4; + margin-bottom: 8px; +} + +.home p { + color: #6c7086; + font-size: 14px; +} + +.home code { + background: #313244; + padding: 2px 6px; + border-radius: 4px; + font-family: monospace; + font-size: 13px; + color: #89b4fa; +} diff --git a/template/sources/pages/home/home.js b/template/sources/pages/home/home.js new file mode 100644 index 0000000..474ff05 --- /dev/null +++ b/template/sources/pages/home/home.js @@ -0,0 +1,14 @@ +class HomePage extends HTMLElement { + connectedCallback() { + this.innerHTML = ` +
+

Bienvenue

+

Modifiez cette page dans sources/pages/home/.

+
+ ` + } +} + +customElements.define('home-page', HomePage) + +export function init(_main) {} diff --git a/template/sources/pages/home/index.html b/template/sources/pages/home/index.html new file mode 100644 index 0000000..4ffebd0 --- /dev/null +++ b/template/sources/pages/home/index.html @@ -0,0 +1 @@ + diff --git a/template/sources/pages/home/manifest.json b/template/sources/pages/home/manifest.json new file mode 100644 index 0000000..9ad2661 --- /dev/null +++ b/template/sources/pages/home/manifest.json @@ -0,0 +1,5 @@ +{ + "route": "home", + "label": "Home", + "icon": "home" +} From f49eae6c3141d55e67c5459ee0658d4331a2cfe0 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 7 Jun 2026 13:08:50 +0200 Subject: [PATCH 2/2] =?UTF-8?q?rename=20components.yml=20=E2=86=92=20confi?= =?UTF-8?q?g.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The manifest covers components, pages, vendors and menu — config.yml is a more accurate name. Updated build.sh (both project and template), router.js comment, and README. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: GnomeZworc --- README.md | 8 ++++---- build.sh | 6 +++--- components.yml => config.yml | 0 sources/core/router.js | 2 +- template/build.sh | 6 +++--- template/{components.yml => config.yml} | 0 6 files changed, 11 insertions(+), 11 deletions(-) rename components.yml => config.yml (100%) rename template/{components.yml => config.yml} (100%) diff --git a/README.md b/README.md index a38eff7..1fb1113 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Syn Framework web minimaliste basé sur JavaScript vanilla et les Web Components. -Routage hash-based, composants déclarés dans `components.yml`, build via `build.sh`. +Routage hash-based, composants déclarés dans `config.yml`, build via `build.sh`. ## Structure d'un projet @@ -15,7 +15,7 @@ Routage hash-based, composants déclarés dans `components.yml`, build via `buil │ ├── vendor/ # Libs tierces (gitignored) │ └── pages/ │ └── / # Une page = un dossier -├── components.yml # Source de vérité +├── config.yml # Source de vérité └── build.sh # Télécharge les remotes + génère les JSON ``` @@ -35,13 +35,13 @@ python3 -m http.server 8000 --directory sources/ - `index.html` — fragment HTML (ex. ``) - `.js` — `customElements.define` + `export function init(main) {}` - `.css` — styles scopés à la page (optionnel) -2. Déclarer sous `local_pages:` dans `components.yml` +2. Déclarer sous `local_pages:` dans `config.yml` 3. Ajouter la route à `menu:` si visible dans la nav 4. `./build.sh` ## Ajouter un composant -1. Déclarer sous `components:` dans `components.yml` : +1. Déclarer sous `components:` dans `config.yml` : ```yaml components: - name: mon-composant diff --git a/build.sh b/build.sh index aa754dc..a25ce23 100755 --- a/build.sh +++ b/build.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash -# Build the web UI component set from components.yml. +# Build the web UI component set from config.yml. # # ./build.sh build (download remote components + generate components.json) # ./build.sh --check validate manifest and entry files without downloading # -# Reads components.yml, downloads each remote component into components// +# Reads config.yml, downloads each remote component into components// # at the requested ref, then generates components.json (runtime load list) and # components.lock.json (resolved commit pins). # @@ -16,7 +16,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" WEB_DIR="${SCRIPT_DIR}/sources" -MANIFEST="${SCRIPT_DIR}/components.yml" +MANIFEST="${SCRIPT_DIR}/config.yml" COMPONENTS_DIR="${WEB_DIR}/components" OUTPUT="${WEB_DIR}/components.json" LOCKFILE="${WEB_DIR}/components.lock.json" diff --git a/components.yml b/config.yml similarity index 100% rename from components.yml rename to config.yml diff --git a/sources/core/router.js b/sources/core/router.js index d23777c..7f9920f 100644 --- a/sources/core/router.js +++ b/sources/core/router.js @@ -1,5 +1,5 @@ // Hash-based SPA router. -// Reads pages.json (generated by build.sh from components.yml). +// Reads pages.json (generated by build.sh from config.yml). // Each page is an HTML fragment (index.html) + optional CSS + optional JS module. // // Load order enforced by index.html: diff --git a/template/build.sh b/template/build.sh index aa754dc..a25ce23 100755 --- a/template/build.sh +++ b/template/build.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash -# Build the web UI component set from components.yml. +# Build the web UI component set from config.yml. # # ./build.sh build (download remote components + generate components.json) # ./build.sh --check validate manifest and entry files without downloading # -# Reads components.yml, downloads each remote component into components// +# Reads config.yml, downloads each remote component into components// # at the requested ref, then generates components.json (runtime load list) and # components.lock.json (resolved commit pins). # @@ -16,7 +16,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" WEB_DIR="${SCRIPT_DIR}/sources" -MANIFEST="${SCRIPT_DIR}/components.yml" +MANIFEST="${SCRIPT_DIR}/config.yml" COMPONENTS_DIR="${WEB_DIR}/components" OUTPUT="${WEB_DIR}/components.json" LOCKFILE="${WEB_DIR}/components.lock.json" diff --git a/template/components.yml b/template/config.yml similarity index 100% rename from template/components.yml rename to template/config.yml