@ofidj/generator-fidj 3.7.5 → 3.8.1

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.
@@ -578,11 +578,12 @@ body.has-module {
578
578
  line-height: 1.55;
579
579
  color: var(--fidj-on-ink-faint);
580
580
  }
581
+ /* No rule of its own: the disclosure above already draws one across the panel,
582
+ * and two lines a few pixels apart read as a mistake rather than as structure. */
581
583
  .signin-trust {
582
584
  display: flex;
583
585
  flex-direction: column;
584
586
  gap: 12px;
585
- border-top: 1px solid var(--fidj-line-soft);
586
587
  padding-top: 20px;
587
588
  }
588
589
  .signin-trust-head {
@@ -646,7 +647,10 @@ body.has-module {
646
647
  .signin-form input {
647
648
  min-height: 48px;
648
649
  }
649
- .signin-form form > button {
650
+ /* The app's own buttons sit one level deeper now that the credential form is
651
+ * inside a disclosure, so the rule follows them in rather than losing them. */
652
+ .signin-form form > button,
653
+ .signin-form form #email-entry > button {
650
654
  min-height: 48px;
651
655
  width: 100%;
652
656
  margin-top: 12px;
@@ -780,13 +784,63 @@ body.has-module {
780
784
  .content-account input:not([type="checkbox"]) {
781
785
  width: 100%;
782
786
  }
783
- .content-nav {
787
+ /* The app's navigation lives in the app's own bar, past its mark and its name
788
+ * and past a rule — the shape Fidj's console uses for the same job. It used to
789
+ * sit in the page under a bar that carried only a name, which read as two
790
+ * headers for one app and put the way out a scroll away from the way in. */
791
+ .topbar .content-nav {
792
+ border: 0;
793
+ border-left: 1px solid var(--fidj-ink-line-soft);
794
+ border-radius: 0;
795
+ margin: 0 auto 0 0;
796
+ padding-left: clamp(12px, 2vw, 20px);
797
+ gap: 2px;
798
+ flex-wrap: nowrap;
799
+ }
800
+ .topbar .content-nav button {
801
+ padding: 8px 12px;
802
+ font-size: 13.5px;
803
+ color: var(--fidj-on-ink-faint);
804
+ border-bottom: 0;
805
+ white-space: nowrap;
806
+ }
807
+ .topbar .content-nav button:hover:not(:disabled) {
808
+ color: var(--fidj-on-ink);
809
+ }
810
+ .topbar .content-nav button.selected {
811
+ color: var(--fidj-on-ink);
812
+ font-weight: 600;
813
+ }
814
+ .topbar .content-nav button:last-child {
815
+ margin-left: 0;
816
+ }
817
+ /* Who you are, said where it can be checked against what follows. */
818
+ .account-identity {
819
+ font-size: 15px;
820
+ }
821
+ /* The two ways out of this screen, last and together. */
822
+ .account-actions {
784
823
  display: flex;
824
+ flex-wrap: wrap;
785
825
  align-items: center;
786
826
  gap: 10px;
827
+ margin-top: 28px;
828
+ padding-top: 22px;
829
+ border-top: 1px solid var(--fidj-line-soft);
787
830
  }
788
- .content-nav #exit {
789
- margin-left: auto;
831
+ .account-actions .primary {
832
+ width: auto;
833
+ flex: 1;
834
+ min-width: 200px;
835
+ margin: 0;
836
+ }
837
+
838
+ /* The account tab carries the address it is about, and that address is long.
839
+ * It gives way before the app's own name does. */
840
+ .topbar .content-nav #account-tab {
841
+ overflow: hidden;
842
+ text-overflow: ellipsis;
843
+ min-width: 0;
790
844
  }
791
845
  .signin-logo {
792
846
  width: 22px;
@@ -957,3 +1011,147 @@ button.quiet {
957
1011
  cursor: pointer;
958
1012
  width: auto;
959
1013
  }
1014
+
1015
+ /* The Fidj door.
1016
+ *
1017
+ * The accent is the Fidj mark, and this is the one control on an app's entry
1018
+ * that belongs to Fidj rather than to the app. It is also the door the app
1019
+ * would rather people took — the one where the password is never typed here —
1020
+ * and those two reasons happen to want the same paint. Nothing else on the
1021
+ * screen wears it, which is what makes it read as the way in rather than as one
1022
+ * option among several. */
1023
+ .primary.fidj-entry {
1024
+ background: var(--fidj-accent);
1025
+ border-color: var(--fidj-accent);
1026
+ color: var(--fidj-on-accent);
1027
+ margin-top: 0;
1028
+ }
1029
+ .primary.fidj-entry:hover:not(:disabled) {
1030
+ background: var(--fidj-accent-strong);
1031
+ border-color: var(--fidj-accent-strong);
1032
+ }
1033
+ /* While the Fidj window is open, the door is no longer the way in — it is the
1034
+ * way back to the window doing the work. So it reads as a state rather than an
1035
+ * invitation, and keeps the pointer, because it is the one thing on the screen
1036
+ * somebody who has lost that window behind this page needs to be able to press. */
1037
+ .primary.fidj-entry.is-waiting,
1038
+ .primary.fidj-entry.is-waiting:hover:not(:disabled) {
1039
+ background: var(--fidj-surface-sunk);
1040
+ border-color: var(--fidj-line);
1041
+ color: var(--fidj-text-faint);
1042
+ cursor: pointer;
1043
+ }
1044
+ .primary.fidj-entry.is-waiting:hover:not(:disabled) {
1045
+ border-color: var(--fidj-line-hover);
1046
+ color: var(--fidj-text-muted);
1047
+ }
1048
+
1049
+ /* The app's own form, second. A disclosure rather than a second button of equal
1050
+ * weight: it costs the person who wants it one click, and costs everybody else
1051
+ * nothing — where two buttons side by side charged every arrival a decision.
1052
+ *
1053
+ * It sits with the button it is an alternative to, not a rule and a gap away:
1054
+ * separated, the two read as unrelated parts of the screen rather than as the
1055
+ * two ways in. */
1056
+ .signin-alternate {
1057
+ margin-top: 2px;
1058
+ }
1059
+ /* A seam across the panel rather than a link hanging off its left edge: the
1060
+ * label in the middle with a rule running out to each side, which is what says
1061
+ * "below this, a different way in" instead of "here is one more control". */
1062
+ .signin-toggle {
1063
+ display: flex;
1064
+ align-items: center;
1065
+ gap: 12px;
1066
+ width: 100%;
1067
+ margin: 0;
1068
+ padding: 8px 0;
1069
+ min-height: 0;
1070
+ background: none;
1071
+ border: none;
1072
+ font: inherit;
1073
+ font-size: 13.5px;
1074
+ color: var(--fidj-text-muted);
1075
+ cursor: pointer;
1076
+ }
1077
+ .signin-toggle::before,
1078
+ .signin-toggle::after {
1079
+ content: "";
1080
+ height: 1px;
1081
+ flex: 1;
1082
+ background: var(--fidj-line);
1083
+ }
1084
+ .signin-toggle-label {
1085
+ display: inline-flex;
1086
+ align-items: center;
1087
+ gap: 7px;
1088
+ }
1089
+ .signin-toggle:hover:not(:disabled) {
1090
+ color: var(--fidj-text);
1091
+ }
1092
+ .signin-toggle:hover:not(:disabled)::before,
1093
+ .signin-toggle:hover:not(:disabled)::after {
1094
+ background: var(--fidj-line-hover);
1095
+ }
1096
+ /* The caret points at what pressing it does: down at a form that is not here
1097
+ * yet, and — turned over — up at the one it would put away again. */
1098
+ .signin-toggle .caret {
1099
+ width: 0;
1100
+ height: 0;
1101
+ border-left: 4px solid transparent;
1102
+ border-right: 4px solid transparent;
1103
+ border-top: 5px solid currentColor;
1104
+ transition: transform 220ms ease;
1105
+ }
1106
+ .signin-toggle[aria-expanded="true"] .caret {
1107
+ transform: rotate(180deg);
1108
+ }
1109
+ .signin-alternate #email-entry {
1110
+ margin-top: 6px;
1111
+ }
1112
+
1113
+ /* Opening the form folds the Fidj door away, because the two are alternatives
1114
+ * and only one of them is being used. Folding rather than vanishing is the part
1115
+ * that says so: the form visibly takes the room the door was holding. */
1116
+ .primary.fidj-entry {
1117
+ overflow: hidden;
1118
+ max-height: 64px;
1119
+ transition:
1120
+ max-height 220ms ease,
1121
+ min-height 220ms ease,
1122
+ opacity 140ms ease,
1123
+ margin 220ms ease,
1124
+ padding 220ms ease,
1125
+ border-width 220ms ease;
1126
+ }
1127
+ .primary.fidj-entry.is-folded {
1128
+ /* `min-height` wins over `max-height`, so the entry's own 48px floor has to
1129
+ * come down too or nothing moves. */
1130
+ min-height: 0;
1131
+ max-height: 0;
1132
+ opacity: 0;
1133
+ margin-top: 0;
1134
+ margin-bottom: 0;
1135
+ padding-top: 0;
1136
+ padding-bottom: 0;
1137
+ border-width: 0;
1138
+ pointer-events: none;
1139
+ }
1140
+ @media (prefers-reduced-motion: reduce) {
1141
+ .primary.fidj-entry,
1142
+ .signin-toggle .caret {
1143
+ transition: none;
1144
+ }
1145
+ }
1146
+
1147
+ /* A window that opened itself over the page somebody was on owes them the way
1148
+ * back before it asks for a password. */
1149
+ .signin-return {
1150
+ margin: 0 0 18px;
1151
+ padding: 10px 12px;
1152
+ background: var(--fidj-surface-sunk);
1153
+ border-left: 2px solid var(--fidj-accent);
1154
+ color: var(--fidj-text-muted);
1155
+ font-size: 13.5px;
1156
+ line-height: 1.5;
1157
+ }
@@ -34,6 +34,11 @@
34
34
  /* Accents. The red is the Fidj mark; it identifies the account and privacy
35
35
  * provider, so it stays sparing — a dot, a rule, a hover. */
36
36
  --fidj-accent: #d6342c;
37
+ /* The one place the accent is a surface rather than a mark: the Fidj door on
38
+ * a sign-in entry. It is the control that belongs to Fidj and not to the app
39
+ * around it, so it is the one thing allowed to carry the mark's weight. */
40
+ --fidj-accent-strong: #b52a23;
41
+ --fidj-on-accent: #fbfaf8;
37
42
  --fidj-danger: #b8352c;
38
43
  --fidj-danger-strong: #8c2a22;
39
44
  --fidj-danger-tint: #fdf7f6;
package/lib/scaffold.cjs CHANGED
@@ -25,15 +25,27 @@ function scaffold(destination, options) {
25
25
  const anonymous = options.anonymous ?? true;
26
26
  if (![true, false, "true", "false"].includes(anonymous))
27
27
  throw new Error("--anonymous must be true or false.");
28
- // An app that delegates to the provider collects no password: that is the
29
- // promise its entry makes, and it holds only while the app never sees one.
30
- // An owner can decide otherwise for their own app — some people would rather
31
- // type an address than be sent somewhere — and then it is the app, not only
32
- // Fidj, that must be trusted with the credential. Off by default, so the
33
- // promise stays the default.
28
+ // How this app asks, in the owner's words.
29
+ //
30
+ // `button` delegates every sign-in to Fidj, which is the promise the entry
31
+ // makes — this app never sees a password — so it is what an owner gets
32
+ // without asking. `inline` keeps the app's own form and nothing else, for an
33
+ // owner who has decided that their page, not only Fidj, is to be trusted with
34
+ // the credential. `both` leads with the button and folds the form under it.
35
+ //
36
+ // One input with three values rather than a boolean, because "no button" and
37
+ // "no form" are different apps and a flag named after one cannot say the
38
+ // other. `--credentials true|false` said the same thing about a product that
39
+ // had only two shapes; it still means what it meant, and `--signin` wins when
40
+ // both are given.
34
41
  const credentials = options.credentials ?? false;
35
42
  if (![true, false, "true", "false"].includes(credentials))
36
43
  throw new Error("--credentials must be true or false.");
44
+ const signin =
45
+ options.signin ??
46
+ (credentials === true || credentials === "true" ? "both" : "button");
47
+ if (!["button", "inline", "both"].includes(signin))
48
+ throw new Error("--signin must be button, inline or both.");
37
49
  const name = options.name || path.basename(path.resolve(destination));
38
50
  if (!/^[a-z0-9][a-z0-9-]{0,63}$/.test(name))
39
51
  throw new Error(
@@ -157,7 +169,7 @@ function scaffold(destination, options) {
157
169
  // The app's own server serves this to its page: the entry cannot redirect to
158
170
  // a provider it was never told about.
159
171
  const issuerSetting = options.oidcIssuer ? `FIDJ_OIDC_ISSUER=${options.oidcIssuer}\n` : "";
160
- const settings = `FIDJ_APP_ID=${options.appId}\nFIDJ_API_ENDPOINT=${api.href.replace(/\/$/, "")}\n${issuerSetting}FIDJ_DASHBOARD_URL=https://fidj.ovh\nAPP_TITLE=${title}\nAPP_VERSION=${releaseVersion}\nPORT=8200\nHOST=127.0.0.1\nLOCAL_DEMO=false\nFIDJ_DATA_DIR=../.fidj-data/${name}\nFIDJ_PRIVACY_ADAPTER_KEY=\n`;
172
+ const settings = `FIDJ_APP_ID=${options.appId}\nFIDJ_API_ENDPOINT=${api.href.replace(/\/$/, "")}\n${issuerSetting}FIDJ_DASHBOARD_URL=https://fidj.ovh\nAPP_TITLE=${title}\nAPP_VERSION=${releaseVersion}\nFIDJ_SIGNIN=${signin}\nPORT=8200\nHOST=127.0.0.1\nLOCAL_DEMO=false\nFIDJ_DATA_DIR=../.fidj-data/${name}\nFIDJ_PRIVACY_ADAPTER_KEY=\n`;
161
173
  const localApi = options.local
162
174
  ? "http://localhost:3201/v3"
163
175
  : api.href.replace(/\/$/, "");
@@ -175,7 +187,7 @@ function scaffold(destination, options) {
175
187
  releaseVersion,
176
188
  localDemo: Boolean(options.local),
177
189
  allowAnonymous: anonymous === true || anonymous === "true",
178
- ownCredentials: credentials === true || credentials === "true",
190
+ signin,
179
191
  welcome: options.welcome || title,
180
192
  description:
181
193
  options.description ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ofidj/generator-fidj",
3
- "version": "3.7.5",
3
+ "version": "3.8.1",
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": {
@@ -22,7 +22,9 @@
22
22
  "dependencies": {
23
23
  "yeoman-generator": "^4.12.0"
24
24
  },
25
- "devDependencies": {},
25
+ "devDependencies": {
26
+ "knip": "^6.35.1"
27
+ },
26
28
  "eslintConfig": {
27
29
  "extends": "xo-space",
28
30
  "env": {
@@ -31,7 +33,8 @@
31
33
  },
32
34
  "repository": "https://github.com/ofidj/generator-fidj.git",
33
35
  "scripts": {
34
- "test": "node --test test/*.test.cjs"
36
+ "test": "node --test test/*.test.cjs",
37
+ "bp:dead-code": "knip"
35
38
  },
36
39
  "license": "MIT",
37
40
  "bin": {