PageSourceSearch

https://www.blue70.cz/pages/products.js

js blue70.cz collected 2026-10-04 10:23:31 UTC 4,988 bytes, 173 lines download raw bytes

1// upload/pages/products.js — generated by scripts/migrate-pages.mjs.
2// Do not hand-edit; re-run migrate-pages.mjs and edit the original
3// HTML / inline script there.
4
5import "../_globals.js";
6import { applySeoMeta } from "nodality";
7
8// SEO metadata — description, canonical, Open Graph + Twitter cards. Lands in the
9// static HTML at prerender time so crawlers and social scrapers see it.
10applySeoMeta({
11  path: "/products.html",
12  title: "BLUE70 — produkty blueseventy",
13  description: "Kompletní nabídka produktů blueseventy — neoprenové obleky, plavecké brýle a doplňky pro triatlonisty a plavce.",
14  image: "/img/blue70.jpg",
15  ogType: "website",
16  siteName: "BLUE70",
17});
18
19import {renderNav} from "../components/nav.js"; renderNav();
20import {renderDarkMode} from "../components/dark-mode.js"; renderDarkMode();
21import "../components/footer.js";
22
23// --- inline block ---
24
25    const urlParams = new URLSearchParams(window.location.search);
26const cat = urlParams.get("cat"); 
27document.title = `BLUE70 ${cat}`;
28// http://localhost:2000/categoryDetail?cat=neopreny
29
30// http://localhost:2000/products
31
32
33// http://localhost:2000/products?cat=neopreny
34// http://localhost:2000/products?cat=wetsuits
35
36import {Blue70Button} from "../components/blue-70-button.js";
37
38 class ProductCard extends Base {
39      constructor(obj){
40        super();
41        this.obj = obj;
42
43        if (obj.images === undefined){
44          alert(obj.name);
45          
46        } else {
47          if (obj.images[0] === undefined){
48              alert(obj.name);
49          }
50        }
51      }
52
53      render(){
54        return new Wrapper(/*isLink: true, child: `detail.html?id=a`*/)
55          .add([
56            new Image().set({
57              type: "img",
58              width: "300px",
59              isFull: true,
60              url: this.obj.images[0],
61              alt: this.obj.name,
62              vtn: this.obj.name
63            }),
64            new Wrapper().set({
65              pad: [{a: 14}]
66            }).add([
67
68            new Wrapper().set({
69             
70             
71             resprop:  [
72              {
73              breakpoint: "md",
74              height: "120px",
75            // background: "green"
76          
77        },
78        {
79            breakpoint: "1800px",
80            height: "170px",
81            // background: "orange"
82          
83        }
84      ]
85            }).add([
86 new Text(this.obj.name).set({
87                color: "black",
88                weight: "bold",
89                exact: "1.7rem",
90                font: "Helvetica"
91              }),
92
93              
94              new Text(this.obj.price).set({
95                weight: "bold",
96                color: "black",
97                exact: "1.1rem", 
98                pad: [{b: "0.7rem"}],
99                hide: this.obj.price === "n/a"
100              }),
101            ]),
102
103              new Blue70Button({
104                // Link straight to the per-product static page generated
105                // by `nodality prerender`. Keeps the old
106                // detail.html?id=… runtime path working as a fallback
107                // for bookmarks / inbound external links.
108                url: `https://www.blue70.cz/detail-${this.obj.id}.html`
109              }).render()
110             
111            ])
112          ]);
113      } // 205954 WORKS
114      // locally have to type manually http://localhost:2000/detail?id=helix 
115    }
116
117    // ✅ Title
118
119
120
121 import { FooterEl } from "../components/footer.js";
122import { loadJson } from "nodality";
123
124// Top-level await so prerender serialises the full grid + footer into
125// the static HTML. Previously this was a `fetch(...).then(...)` chain
126// that resolved after prerender had already snapshot the DOM, leaving
127// crawlers with an empty mount. `loadJson` reads from disk at SSG time
128// (./upload/products.json) and falls through to fetch in the browser.
129try {
130  const data = await loadJson("products.json");
131  const cata = data.categories.filter(cato => cato.id.toLowerCase() === cat)[0]
132    ?? { products: [] };
133
134  new FlexGrid()
135    .set({
136      colat: "700px",
137      wrap: true,
138      align: "center",
139      gap: "1rem",
140      pad: [{ a: "1rem" }]
141    })
142    .items(
143      cata.products.map(el =>
144        new Card()
145          .set({
146            width: "300px",
147            radius: "1rem",
148            border: "3px solid #ECF0F1",
149            background: "#ECF0F1",
150            inpad: "1rem",
151            mar: { sides: ["all"], value: "0.8rem" }
152          })
153          .items([ new ProductCard(el).render() ])
154      )
155    )
156    .render("#mount");
157
158  // Render footer under grid — now lives inside the awaited block so
159  // it lands in the static HTML alongside the products it sits under.
160  new FooterEl().render().render("#mount");
161} catch (err) {
162  console.error("Failed to load products.json", err);
163}
164   
165  
166// We can host on github and redirect for free
167
168// UPDATE: npm i nodality@latest
169// BYPASS package.json
170
171// run with npx serve -l 2000
172// http://localhost:2000/publish
173

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.