@ofidj/generator-fidj 1.0.1 → 1.0.4

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.
Files changed (27) hide show
  1. package/README.md +58 -14
  2. package/bin/create-fidj.cjs +9 -1
  3. package/generators/app/index.js +57 -15
  4. package/generators/app/templates/typescript/README.md +12 -2
  5. package/generators/app/templates/typescript/app.config.json +5 -1
  6. package/generators/app/templates/typescript/package.json +1 -1
  7. package/generators/app/templates/typescript/public/fidj-logo.png +0 -0
  8. package/generators/app/templates/typescript/public/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  9. package/generators/app/templates/typescript/public/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  10. package/generators/app/templates/typescript/public/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  11. package/generators/app/templates/typescript/public/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  12. package/generators/app/templates/typescript/public/fonts/IBMPlexSans-400_600-latin-ext.woff2 +0 -0
  13. package/generators/app/templates/typescript/public/fonts/IBMPlexSans-400_600-latin.woff2 +0 -0
  14. package/generators/app/templates/typescript/public/fonts/InstrumentSerif-400-latin-ext.woff2 +0 -0
  15. package/generators/app/templates/typescript/public/fonts/InstrumentSerif-400-latin.woff2 +0 -0
  16. package/generators/app/templates/typescript/scripts/build.mjs +3 -0
  17. package/generators/app/templates/typescript/scripts/render-content.mjs +2 -2
  18. package/generators/app/templates/typescript/server/index.ts +10 -1
  19. package/generators/app/templates/typescript/src/content.ts +128 -37
  20. package/generators/app/templates/typescript/src/fonts.css +92 -0
  21. package/generators/app/templates/typescript/src/main.ts +31 -9
  22. package/generators/app/templates/typescript/src/service-agreement.ts +51 -0
  23. package/generators/app/templates/typescript/src/style.css +640 -363
  24. package/generators/app/templates/typescript/src/tokens.css +56 -0
  25. package/lib/app-module.cjs +6 -1
  26. package/lib/scaffold.cjs +72 -3
  27. package/package.json +2 -6
@@ -0,0 +1,56 @@
1
+ /* The Fidj design system, v2 — every value the product paints with.
2
+ *
3
+ * This file is shared verbatim with fidj-app (src/theme/fidj-tokens.css), so a
4
+ * style change made here reaches Fidj, mleweb and every generated app at once.
5
+ * Keep it free of anything path-dependent: @font-face lives in fonts.css, and
6
+ * each consumer supplies its own. Nothing else in a stylesheet may introduce a
7
+ * literal colour, family or radius.
8
+ */
9
+
10
+ :root {
11
+ /* Ink — the dark half of the split: brand panel, header, primary button. */
12
+ --fidj-ink: #14110f;
13
+ --fidj-ink-raised: #2a2521;
14
+ --fidj-ink-line: #38322c;
15
+ --fidj-ink-line-soft: #4a423b;
16
+ --fidj-on-ink: #f2eee9;
17
+ --fidj-on-ink-muted: #b6ada5;
18
+ --fidj-on-ink-faint: #8c847c;
19
+
20
+ /* Paper — the light half. */
21
+ --fidj-paper: #fbfaf8;
22
+ --fidj-surface: #ffffff;
23
+ --fidj-surface-sunk: #f5f1ec;
24
+ --fidj-surface-tint: #f2eee9;
25
+ --fidj-line: #e4ded7;
26
+ --fidj-line-soft: #ece7e1;
27
+ --fidj-line-strong: #dfd9d2;
28
+ --fidj-line-hover: #c9c1b8;
29
+ --fidj-text: #14110f;
30
+ --fidj-text-muted: #4a4540;
31
+ --fidj-text-faint: #6b655f;
32
+ --fidj-placeholder: #a8a099;
33
+
34
+ /* Accents. The red is the Fidj mark; it identifies the account and privacy
35
+ * provider, so it stays sparing — a dot, a rule, a hover. */
36
+ --fidj-accent: #d6342c;
37
+ --fidj-danger: #b8352c;
38
+ --fidj-danger-strong: #8c2a22;
39
+ --fidj-danger-tint: #fdf7f6;
40
+ --fidj-danger-line: #e8d9d6;
41
+ --fidj-ok: #3f7a4f;
42
+ --fidj-warn: #c07a1e;
43
+ --fidj-warn-tint: #fbf7f1;
44
+
45
+ --fidj-focus-ring: 0 0 0 3px rgb(20 17 15 / 0.07);
46
+ --fidj-overlay-shadow: 0 12px 32px rgb(20 17 15 / 0.18);
47
+
48
+ --fidj-font-sans: "IBM Plex Sans", system-ui, -apple-system, sans-serif;
49
+ --fidj-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace;
50
+ --fidj-font-display: "Instrument Serif", Georgia, "Times New Roman", serif;
51
+
52
+ /* Squared corners are the loudest signal of this style: 2px everywhere, and
53
+ * a full round only for avatars and status dots. */
54
+ --fidj-radius: 2px;
55
+ --fidj-shell-max: 1180px;
56
+ }
@@ -54,6 +54,11 @@ function inspectModule(source, entry = "index.html", destination) {
54
54
  }
55
55
  };
56
56
  visit(root);
57
- return { root, file, entry: "./module/" + file + url.hash };
57
+ // Address a directory rather than its index file: the generated server and
58
+ // any static host resolve it, and no index.html shows up in the address bar.
59
+ const address = file.endsWith("index.html")
60
+ ? file.slice(0, -"index.html".length)
61
+ : file;
62
+ return { root, file, entry: "./module/" + address + url.hash };
58
63
  }
59
64
  module.exports = { inspectModule };
package/lib/scaffold.cjs CHANGED
@@ -40,11 +40,55 @@ function scaffold(destination, options) {
40
40
  }
41
41
  const title = options.title || name;
42
42
  if (/[\r\n]/.test(title)) throw new Error("Title must be one line.");
43
+ // Sign-in highlights are the app's own selling points, so they are supplied
44
+ // per app rather than baked in: an app that passes none simply shows none.
45
+ const highlights = (options.highlights || []).map((entry) => {
46
+ const [heading, ...rest] = String(entry).split("|");
47
+ const body = rest.join("|").trim();
48
+ if (!heading.trim() || !body)
49
+ throw new Error('Each --highlight must read "<heading>|<body>".');
50
+ if (/[\r\n]/.test(entry)) throw new Error("A highlight must be one line.");
51
+ return { heading: heading.trim(), body };
52
+ });
53
+ if (highlights.length > 6)
54
+ throw new Error("Six highlights is the most the sign-in panel can hold.");
55
+ // Trust badges are claims about a specific app — where it is hosted, what it
56
+ // audits. None are supplied by default, because an app cannot inherit them.
57
+ const badges = (options.badges || []).map((entry) => {
58
+ const text = String(entry).trim();
59
+ if (!text || /[\r\n]/.test(text))
60
+ throw new Error("Each --badge must be one line of text.");
61
+ if (text.length > 40)
62
+ throw new Error("A badge must be at most 40 characters.");
63
+ return text;
64
+ });
65
+ if (badges.length > 4)
66
+ throw new Error("Four badges is the most the sign-in footer can hold.");
43
67
  if (
44
68
  options.domain &&
45
69
  !/^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/i.test(options.domain)
46
70
  )
47
71
  throw new Error("Domain must be a hostname, without a scheme or path.");
72
+ const brandImage = (value, flag) => {
73
+ if (!value) return null;
74
+ const source = path.resolve(value);
75
+ if (!fs.existsSync(source) || !fs.statSync(source).isFile())
76
+ throw new Error(`${flag} must point at an image file.`);
77
+ const extension = path.extname(source).toLowerCase();
78
+ if (
79
+ ![".png", ".svg", ".gif", ".jpg", ".jpeg", ".webp", ".ico"].includes(
80
+ extension,
81
+ )
82
+ )
83
+ throw new Error(
84
+ `${flag} must be a .png, .svg, .gif, .jpg, .webp or .ico file.`,
85
+ );
86
+ if (fs.statSync(source).size > 512 * 1024)
87
+ throw new Error(`${flag} must be under 512KB; it is served on every visit.`);
88
+ return { source, extension };
89
+ };
90
+ const logo = brandImage(options.logo, "--logo");
91
+ const favicon = brandImage(options.favicon, "--favicon");
48
92
  const dir = path.resolve(destination);
49
93
  const appModule = options.module
50
94
  ? inspectModule(options.module, options.moduleEntry, dir)
@@ -99,19 +143,44 @@ function scaffold(destination, options) {
99
143
  options.description ||
100
144
  "A space to explore, with an account that puts you in control.",
101
145
  content: appModule ? "" : options.content,
146
+ highlights,
147
+ badges,
148
+ // An app that supplies no mark of its own borrows Fidj's, so the sign-in
149
+ // and the browser tab are never blank.
150
+ logo: logo ? "./brand/logo" + logo.extension : "./fidj-logo.png",
151
+ favicon: favicon ? "./brand/favicon" + favicon.extension : "./fidj-logo.png",
102
152
  moduleEntry: appModule?.entry || "",
103
153
  domain: options.domain,
104
154
  };
155
+ if (logo || favicon) fs.mkdirSync(path.join(dir, "public/brand"), { recursive: true });
156
+ if (logo)
157
+ fs.copyFileSync(logo.source, path.join(dir, "public/brand/logo" + logo.extension));
158
+ if (favicon)
159
+ fs.copyFileSync(favicon.source, path.join(dir, "public/brand/favicon" + favicon.extension));
160
+ if (favicon) {
161
+ // The workspace starter serves a static index.html rather than rendering
162
+ // one, so its icon is rewritten here.
163
+ const page = path.join(dir, "public/index.html");
164
+ fs.writeFileSync(
165
+ page,
166
+ fs
167
+ .readFileSync(page, "utf8")
168
+ .replace('href="/fidj-logo.png"', `href="/brand/favicon${favicon.extension}"`),
169
+ );
170
+ }
105
171
  if (appModule) {
106
172
  fs.cpSync(appModule.root, path.join(dir, "public/module"), {
107
173
  recursive: true,
108
174
  });
109
175
  const entryFile = path.join(dir, "public/module", appModule.file);
110
- const relativeSignin =
176
+ // Point back at the shell's directory, not at its index file, for the same
177
+ // reason the module entry does: no index.html in the address bar.
178
+ const toRoot =
111
179
  path.posix.relative(
112
180
  path.posix.dirname("module/" + appModule.file),
113
- "index.html",
114
- ) + "#/signin";
181
+ ".",
182
+ ) || ".";
183
+ const relativeSignin = toRoot + "/#/signin";
115
184
  const html = fs.readFileSync(entryFile, "utf8");
116
185
  if (!html.includes("</head>"))
117
186
  throw new Error("Module entry must have an HTML head.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ofidj/generator-fidj",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "description": "Generate a TypeScript app with Fidj sign-in, live server-side roles and per-app privacy.",
5
5
  "homepage": "https://fidj.ovh",
6
6
  "bugs": {
@@ -12,15 +12,11 @@
12
12
  "files": [
13
13
  "bin",
14
14
  "lib",
15
- "generators",
16
- "!generators/app/templates/app2018",
17
- "!generators/app/templates/app2021"
15
+ "generators"
18
16
  ],
19
17
  "main": "./lib/scaffold.cjs",
20
18
  "keywords": [
21
19
  "fidj",
22
- "angular",
23
- "ionic",
24
20
  "yeoman-generator"
25
21
  ],
26
22
  "dependencies": {