@zitadel/config 0.1.0-alpha.17 → 0.1.0-alpha.18
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/defaults/README-branding.md +62 -0
- package/defaults/branding/centered/login.liquid +164 -0
- package/defaults/branding/hero/login.liquid +222 -0
- package/defaults/branding/minimal/login.liquid +154 -0
- package/defaults/branding/split/login.liquid +178 -0
- package/defaults/branding/split-right/login.liquid +178 -0
- package/defaults/default-human-user.json +0 -15
- package/defaults/default-login.json +1 -4
- package/defaults/presets/passkey-first/human-user.json +0 -15
- package/defaults/presets/passkey-first/login.json +1 -4
- package/dist/defaults-Bh4_xVbh.d.mts +84 -0
- package/dist/defaults-Bh4_xVbh.d.mts.map +1 -0
- package/dist/{defaults-BQej3KIY.mjs → defaults-CXTnFMHj.mjs} +193 -65
- package/dist/defaults-CXTnFMHj.mjs.map +1 -0
- package/dist/defaults.d.mts +2 -2
- package/dist/defaults.mjs +2 -2
- package/dist/index.d.mts +5 -4
- package/dist/index.mjs +5 -4
- package/dist/{meta-schemas-8nlyVL7g.mjs → meta-schemas-B4YiHAX_.mjs} +71 -3
- package/dist/meta-schemas-B4YiHAX_.mjs.map +1 -0
- package/dist/meta-schemas.d.mts +6 -1
- package/dist/meta-schemas.d.mts.map +1 -1
- package/dist/meta-schemas.mjs +2 -2
- package/dist/schemas.d.mts +14 -1
- package/dist/schemas.d.mts.map +1 -1
- package/dist/schemas.mjs +60 -2
- package/dist/schemas.mjs.map +1 -1
- package/dist/template.d.mts +76 -0
- package/dist/template.d.mts.map +1 -0
- package/dist/template.mjs +145 -0
- package/dist/template.mjs.map +1 -0
- package/meta-schemas/branding.json +52 -0
- package/meta-schemas/property-name.json +7 -0
- package/meta-schemas/user-property.json +6 -1
- package/meta-schemas/user-schema.json +4 -1
- package/package.json +12 -4
- package/dist/defaults-BQej3KIY.mjs.map +0 -1
- package/dist/defaults-CSjBjBkQ.d.mts +0 -41
- package/dist/defaults-CSjBjBkQ.d.mts.map +0 -1
- package/dist/meta-schemas-8nlyVL7g.mjs.map +0 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Branding
|
|
2
|
+
|
|
3
|
+
This directory owns how your login UI looks: `branding.json` (layout preset
|
|
4
|
+
and asset URLs) plus `login.liquid`, the LiquidJS template the
|
|
5
|
+
`<zitadel-login>` component renders for every step.
|
|
6
|
+
|
|
7
|
+
## Workflow
|
|
8
|
+
|
|
9
|
+
1. Edit `login.liquid` (and `branding.json` for logo/font/hero URLs).
|
|
10
|
+
2. `zitadel plan` — validates the template (LiquidJS parse, banned patterns,
|
|
11
|
+
the required `{% mandatory_gates %}` tag) and shows the pending revision.
|
|
12
|
+
3. `zitadel apply` — publishes an immutable branding revision. The login UI
|
|
13
|
+
picks up the newest revision on the next step response.
|
|
14
|
+
|
|
15
|
+
Every edit publishes a new revision; there is no in-place update. Roll back
|
|
16
|
+
by re-applying an earlier template.
|
|
17
|
+
|
|
18
|
+
## Rules of the template
|
|
19
|
+
|
|
20
|
+
- Compose `<zl-*>` atoms and plain structural HTML. No `<script>`, no
|
|
21
|
+
`<style>`, no inline event handlers — theming happens through design
|
|
22
|
+
tokens, not template CSS.
|
|
23
|
+
- User-facing copy goes through translation keys: `{{ "key" | t }}`.
|
|
24
|
+
- Keep the trailing `{% mandatory_gates %}` tag: it appends any required
|
|
25
|
+
field, gate, or submit action your template forgot, so a broken template
|
|
26
|
+
still yields a submittable step.
|
|
27
|
+
|
|
28
|
+
## Make it yours
|
|
29
|
+
|
|
30
|
+
- In the split-family designs (`split`, `split-right`, `hero`) the
|
|
31
|
+
`.zl-split__brand` pane is yours: structural HTML plus inline `style=""`
|
|
32
|
+
attributes are allowed; `button`, `input`, and `form` tags are stripped —
|
|
33
|
+
use `<a>` for landing CTAs. The `hero` design ships a full landing-page
|
|
34
|
+
starting point on token-styled `zl-hero__*` classes.
|
|
35
|
+
- On narrow viewports the brand pane collapses and the `.zl-split__compact`
|
|
36
|
+
node inside the form pane takes over (logo or brand line) — keep one so
|
|
37
|
+
your identity survives on phones.
|
|
38
|
+
- The split chrome is tunable from your template root's `style` attribute
|
|
39
|
+
(`--zl-split-columns`, `--zl-split-align`, `--zl-split-brand-mobile`), and
|
|
40
|
+
`zl-split--right` on the wrapper mirrors the panes. Knob reference:
|
|
41
|
+
`docs/design/branding/templates.md` in the Zitadel repo.
|
|
42
|
+
- The "Secured with Zitadel" attribution is licence-gated and on by default.
|
|
43
|
+
- Back-navigation: the engine injects a `kind: "back"` action on steps
|
|
44
|
+
that can return to their predecessor, and the browser's back gesture
|
|
45
|
+
submits it automatically — the shipped designs deliberately render **no
|
|
46
|
+
visible back control**. Your template may render one if you want it;
|
|
47
|
+
select the action by kind (never by name) and submit it like any other
|
|
48
|
+
action:
|
|
49
|
+
|
|
50
|
+
```liquid
|
|
51
|
+
{% assign back = actions | where: "kind", "back" | first %}
|
|
52
|
+
{% if back %}
|
|
53
|
+
<a href="#" class="zl-card-nav__link" data-action="{{ back.name }}">{{ back.text_key | t }}</a>
|
|
54
|
+
{% endif %}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
If you list actions generically, exclude `a.kind == 'back'` from button
|
|
58
|
+
loops so the injected action doesn't render as a stray secondary button.
|
|
59
|
+
|
|
60
|
+
Start over anytime with `zitadel branding eject --design <name>` (designs:
|
|
61
|
+
`centered`, `split`, `split-right`, `hero`, `minimal`; add `--force` to
|
|
62
|
+
overwrite).
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<zl-page-shell data-zl-template-root>
|
|
2
|
+
{% if branding.logo_url %}
|
|
3
|
+
<img slot="header" class="zl-card-logo" src="{{ branding.logo_url }}" alt="" />
|
|
4
|
+
{% endif %}
|
|
5
|
+
<zl-card>
|
|
6
|
+
<h1 slot="header" class="zl-card-title">{{ step.texts.title_key | t: identity.display_name }}</h1>
|
|
7
|
+
{% if step.texts.description_key %}
|
|
8
|
+
{% assign card_subtitle = step.texts.description_key | t: identity.display_name %}
|
|
9
|
+
{% if card_subtitle != "" %}
|
|
10
|
+
<p slot="header" class="zl-card-subtitle">{{ card_subtitle }}</p>
|
|
11
|
+
{% endif %}
|
|
12
|
+
{% endif %}
|
|
13
|
+
|
|
14
|
+
{% if errors and errors.size > 0 %}
|
|
15
|
+
{% for err in errors %}
|
|
16
|
+
{% if err | formLevelError %}
|
|
17
|
+
{% assign alert_heading = err.text_key | alertHeading %}
|
|
18
|
+
{% assign alert_body = err.text_key | alertBody %}
|
|
19
|
+
<zl-alert severity="error" dismissible data-zl-step-error{% if alert_heading != "" %} heading="{{ alert_heading | t }}"{% endif %}>
|
|
20
|
+
{% if alert_body != "" %}{{ alert_body | t }}{% elsif err.text_key %}{{ err.text_key | t }}{% else %}{{ err.message }}{% endif %}
|
|
21
|
+
</zl-alert>
|
|
22
|
+
{% endif %}
|
|
23
|
+
{% endfor %}
|
|
24
|
+
{% endif %}
|
|
25
|
+
|
|
26
|
+
{% for f in fields %}
|
|
27
|
+
{% assign field_placeholder = f.text_key | fieldPlaceholder %}
|
|
28
|
+
{% assign field_help = f.text_key | fieldHelp %}
|
|
29
|
+
{% assign field_err = f.name | fieldError: errors %}
|
|
30
|
+
{% case f.type %}
|
|
31
|
+
{% when 'checkbox' %}
|
|
32
|
+
<zl-checkbox
|
|
33
|
+
name="{{ f.name }}"
|
|
34
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
35
|
+
label="{{ f.text_key | t }}"
|
|
36
|
+
value="true"
|
|
37
|
+
{% if f.value %}checked{% endif %}
|
|
38
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
39
|
+
></zl-checkbox>
|
|
40
|
+
{% when 'select' %}
|
|
41
|
+
<zl-select
|
|
42
|
+
name="{{ f.name }}"
|
|
43
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
44
|
+
label="{{ f.text_key | t }}"
|
|
45
|
+
value="{{ f.value }}"
|
|
46
|
+
options='{{ f.validation.enum | selectOptions | json }}'
|
|
47
|
+
{% if f.required %}required{% endif %}
|
|
48
|
+
{% if field_placeholder != "" %}placeholder="{{ field_placeholder }}"{% endif %}
|
|
49
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
50
|
+
></zl-select>
|
|
51
|
+
{% else %}
|
|
52
|
+
{% assign autocomplete_val = '' %}
|
|
53
|
+
{% if f.name == 'email' %}
|
|
54
|
+
{% assign autocomplete_val = 'email' %}
|
|
55
|
+
{% elsif f.type == 'password' and step.name contains 'register' %}
|
|
56
|
+
{% assign autocomplete_val = 'new-password' %}
|
|
57
|
+
{% elsif f.type == 'password' %}
|
|
58
|
+
{% assign autocomplete_val = 'current-password' %}
|
|
59
|
+
{% endif %}
|
|
60
|
+
<zl-field
|
|
61
|
+
name="{{ f.name }}"
|
|
62
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
63
|
+
label="{{ f.text_key | t }}"
|
|
64
|
+
type="{{ f.type }}"
|
|
65
|
+
value="{{ f.value }}"
|
|
66
|
+
{% if autocomplete_val != '' %}autocomplete="{{ autocomplete_val }}"{% endif %}
|
|
67
|
+
{% if f.required %}required{% endif %}
|
|
68
|
+
{% if field_placeholder != "" %}placeholder="{{ field_placeholder }}"{% endif %}
|
|
69
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
70
|
+
>
|
|
71
|
+
{% if field_help != "" %}
|
|
72
|
+
<span slot="help">{{ field_help }}</span>
|
|
73
|
+
{% endif %}
|
|
74
|
+
</zl-field>
|
|
75
|
+
{% endcase %}
|
|
76
|
+
{% endfor %}
|
|
77
|
+
|
|
78
|
+
{% assign recover = actions | where: "name", "recover" | first %}
|
|
79
|
+
{% if recover %}
|
|
80
|
+
<p class="zl-card-forgot">
|
|
81
|
+
<a href="#" class="zl-card-forgot__link" data-action="recover">{{ recover.text_key | t }}</a>
|
|
82
|
+
</p>
|
|
83
|
+
{% endif %}
|
|
84
|
+
|
|
85
|
+
{% for a in actions %}
|
|
86
|
+
{% if a.primary %}
|
|
87
|
+
<zl-button
|
|
88
|
+
hierarchy="primary"
|
|
89
|
+
size="medium"
|
|
90
|
+
type="submit"
|
|
91
|
+
block
|
|
92
|
+
action="{{ a.name }}"
|
|
93
|
+
data-testid="zitadel-action-{{ a.name }}"
|
|
94
|
+
label="{{ a.text_key | t }}"
|
|
95
|
+
{% if loading %}loading{% endif %}
|
|
96
|
+
></zl-button>
|
|
97
|
+
{% endif %}
|
|
98
|
+
{% endfor %}
|
|
99
|
+
|
|
100
|
+
{% for a in actions %}
|
|
101
|
+
{% unless a.primary or a.kind == 'back' or a.name == 'passkey' or a.name == 'register' or a.name == 'sign_in' or a.name == 'recover' %}
|
|
102
|
+
<zl-button
|
|
103
|
+
hierarchy="secondary"
|
|
104
|
+
size="medium"
|
|
105
|
+
type="button"
|
|
106
|
+
block
|
|
107
|
+
action="{{ a.name }}"
|
|
108
|
+
data-testid="zitadel-action-{{ a.name }}"
|
|
109
|
+
label="{{ a.text_key | t }}"
|
|
110
|
+
></zl-button>
|
|
111
|
+
{% endunless %}
|
|
112
|
+
{% endfor %}
|
|
113
|
+
|
|
114
|
+
{% assign passkey = actions | where: "name", "passkey" | first %}
|
|
115
|
+
{% if passkey %}
|
|
116
|
+
{% unless passkey.primary %}
|
|
117
|
+
<zl-button
|
|
118
|
+
hierarchy="secondary"
|
|
119
|
+
size="medium"
|
|
120
|
+
block
|
|
121
|
+
action="passkey"
|
|
122
|
+
data-testid="zitadel-action-passkey"
|
|
123
|
+
label="{{ passkey.text_key | t }}"
|
|
124
|
+
></zl-button>
|
|
125
|
+
{% endunless %}
|
|
126
|
+
{% endif %}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
{% assign register = actions | where: "name", "register" | first %}
|
|
130
|
+
{% if register %}
|
|
131
|
+
<p class="zl-card-nav">
|
|
132
|
+
{{ 'identifier.action.register.lead' | t }}<a href="#" class="zl-card-nav__link" data-action="register" data-testid="zitadel-action-register-link">{{ 'identifier.action.register.link' | t }}</a>
|
|
133
|
+
</p>
|
|
134
|
+
{% endif %}
|
|
135
|
+
|
|
136
|
+
{% assign sign_in = actions | where: "name", "sign_in" | first %}
|
|
137
|
+
{% if sign_in %}
|
|
138
|
+
<p class="zl-card-nav">
|
|
139
|
+
{{ 'register.action.sign_in.lead' | t }}<a href="#" class="zl-card-nav__link" data-action="sign_in" data-testid="zitadel-action-sign_in-link">{{ 'register.action.sign_in.link' | t }}</a>
|
|
140
|
+
</p>
|
|
141
|
+
{% endif %}
|
|
142
|
+
|
|
143
|
+
{% if challenge %}
|
|
144
|
+
{% if challenge.method == "passkey" or challenge.method == "passkey_register" %}
|
|
145
|
+
{% assign ceremony = "authenticate" %}
|
|
146
|
+
{% assign submit_method = challenge.method %}
|
|
147
|
+
{% if challenge.method == "passkey_register" or challenge.options.user %}
|
|
148
|
+
{% assign ceremony = "register" %}
|
|
149
|
+
{% assign submit_method = "passkey_register" %}
|
|
150
|
+
{% endif %}
|
|
151
|
+
<zl-passkey
|
|
152
|
+
ceremony="{{ ceremony }}"
|
|
153
|
+
method="{{ submit_method }}"
|
|
154
|
+
challenge-id="{{ challenge.challenge_id }}"
|
|
155
|
+
options='{{ challenge.options | json }}'
|
|
156
|
+
pending-label="{{ 'passkey.pending.status' | t }}"
|
|
157
|
+
cancel-label="{{ 'action.cancel' | t }}"
|
|
158
|
+
></zl-passkey>
|
|
159
|
+
{% endif %}
|
|
160
|
+
{% endif %}
|
|
161
|
+
|
|
162
|
+
{% mandatory_gates %}
|
|
163
|
+
</zl-card>
|
|
164
|
+
</zl-page-shell>
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
<zl-page-shell data-zl-template-root>
|
|
2
|
+
<div class="zl-split">
|
|
3
|
+
<aside class="zl-split__brand">
|
|
4
|
+
{% comment %} ──────────────────────────────────────────────────────────
|
|
5
|
+
YOUR LANDING CONTENT — everything inside this aside is yours.
|
|
6
|
+
Edit the copy and structure freely: structural HTML (div, section,
|
|
7
|
+
nav, h1–h6, ul, li, a, img, …) plus inline style="" attributes are
|
|
8
|
+
allowed; button, input, form, script, and style tags are stripped —
|
|
9
|
+
use plain anchors for landing CTAs. The zl-hero__* classes keep
|
|
10
|
+
this pane on design tokens so palettes and theme mode apply.
|
|
11
|
+
|
|
12
|
+
The login card in the section below is fully wired to the flow
|
|
13
|
+
engine; leave its zl-* atoms intact. Layout knobs (set on the root
|
|
14
|
+
element's style attribute): --zl-split-columns, --zl-split-align,
|
|
15
|
+
--zl-split-brand-mobile. Add zl-split--right to the wrapper div to
|
|
16
|
+
mirror the panes. More in .zitadel/branding/README.md.
|
|
17
|
+
────────────────────────────────────────────────────────────── {% endcomment %}
|
|
18
|
+
<div class="zl-hero">
|
|
19
|
+
<nav class="zl-hero__nav">
|
|
20
|
+
<span class="zl-hero__brand">
|
|
21
|
+
{% if branding.logo_url %}
|
|
22
|
+
<img class="zl-hero__brand-logo" src="{{ branding.logo_url }}" alt="" />
|
|
23
|
+
{% else %}
|
|
24
|
+
<span class="zl-hero__brand-mark" aria-hidden="true"></span>
|
|
25
|
+
{% endif %}
|
|
26
|
+
Your brand
|
|
27
|
+
</span>
|
|
28
|
+
<span class="zl-hero__nav-links">
|
|
29
|
+
<a href="#">Product</a>
|
|
30
|
+
<a href="#">Pricing</a>
|
|
31
|
+
<a href="#">Docs</a>
|
|
32
|
+
</span>
|
|
33
|
+
</nav>
|
|
34
|
+
|
|
35
|
+
<p class="zl-hero__eyebrow">Your product category</p>
|
|
36
|
+
<h2 class="zl-hero__headline">A headline about what you ship.</h2>
|
|
37
|
+
<p class="zl-hero__sub">
|
|
38
|
+
Use this pane to tell visitors why they sign up: what your product
|
|
39
|
+
does, who it is for, and what happens after they sign in. Replace
|
|
40
|
+
every line here before you publish.
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<ul class="zl-hero__bullets">
|
|
44
|
+
<li>Your first selling point</li>
|
|
45
|
+
<li>Your second selling point</li>
|
|
46
|
+
<li>Your third selling point</li>
|
|
47
|
+
</ul>
|
|
48
|
+
|
|
49
|
+
<p class="zl-hero__footnote">
|
|
50
|
+
Replace this line with real social proof, such as customer logos or
|
|
51
|
+
a certification you actually hold.
|
|
52
|
+
</p>
|
|
53
|
+
</div>
|
|
54
|
+
</aside>
|
|
55
|
+
<section class="zl-split__form">
|
|
56
|
+
{% if branding.logo_url %}
|
|
57
|
+
<img class="zl-split__compact" src="{{ branding.logo_url }}" alt="" />
|
|
58
|
+
{% else %}
|
|
59
|
+
<p class="zl-split__compact zl-hero__compact-brand">Your brand</p>
|
|
60
|
+
{% endif %}
|
|
61
|
+
<zl-card>
|
|
62
|
+
<h1 slot="header" class="zl-card-title">{{ step.texts.title_key | t: identity.display_name }}</h1>
|
|
63
|
+
{% if step.texts.description_key %}
|
|
64
|
+
{% assign card_subtitle = step.texts.description_key | t: identity.display_name %}
|
|
65
|
+
{% if card_subtitle != "" %}
|
|
66
|
+
<p slot="header" class="zl-card-subtitle">{{ card_subtitle }}</p>
|
|
67
|
+
{% endif %}
|
|
68
|
+
{% endif %}
|
|
69
|
+
|
|
70
|
+
{% if errors and errors.size > 0 %}
|
|
71
|
+
{% for err in errors %}
|
|
72
|
+
{% if err | formLevelError %}
|
|
73
|
+
{% assign alert_heading = err.text_key | alertHeading %}
|
|
74
|
+
{% assign alert_body = err.text_key | alertBody %}
|
|
75
|
+
<zl-alert severity="error" dismissible data-zl-step-error{% if alert_heading != "" %} heading="{{ alert_heading | t }}"{% endif %}>
|
|
76
|
+
{% if alert_body != "" %}{{ alert_body | t }}{% elsif err.text_key %}{{ err.text_key | t }}{% else %}{{ err.message }}{% endif %}
|
|
77
|
+
</zl-alert>
|
|
78
|
+
{% endif %}
|
|
79
|
+
{% endfor %}
|
|
80
|
+
{% endif %}
|
|
81
|
+
|
|
82
|
+
{% for f in fields %}
|
|
83
|
+
{% assign field_placeholder = f.text_key | fieldPlaceholder %}
|
|
84
|
+
{% assign field_help = f.text_key | fieldHelp %}
|
|
85
|
+
{% assign field_err = f.name | fieldError: errors %}
|
|
86
|
+
{% case f.type %}
|
|
87
|
+
{% when 'checkbox' %}
|
|
88
|
+
<zl-checkbox
|
|
89
|
+
name="{{ f.name }}"
|
|
90
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
91
|
+
label="{{ f.text_key | t }}"
|
|
92
|
+
value="true"
|
|
93
|
+
{% if f.value %}checked{% endif %}
|
|
94
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
95
|
+
></zl-checkbox>
|
|
96
|
+
{% when 'select' %}
|
|
97
|
+
<zl-select
|
|
98
|
+
name="{{ f.name }}"
|
|
99
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
100
|
+
label="{{ f.text_key | t }}"
|
|
101
|
+
value="{{ f.value }}"
|
|
102
|
+
options='{{ f.validation.enum | selectOptions | json }}'
|
|
103
|
+
{% if f.required %}required{% endif %}
|
|
104
|
+
{% if field_placeholder != "" %}placeholder="{{ field_placeholder }}"{% endif %}
|
|
105
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
106
|
+
></zl-select>
|
|
107
|
+
{% else %}
|
|
108
|
+
{% assign autocomplete_val = '' %}
|
|
109
|
+
{% if f.name == 'email' %}
|
|
110
|
+
{% assign autocomplete_val = 'email' %}
|
|
111
|
+
{% elsif f.type == 'password' and step.name contains 'register' %}
|
|
112
|
+
{% assign autocomplete_val = 'new-password' %}
|
|
113
|
+
{% elsif f.type == 'password' %}
|
|
114
|
+
{% assign autocomplete_val = 'current-password' %}
|
|
115
|
+
{% endif %}
|
|
116
|
+
<zl-field
|
|
117
|
+
name="{{ f.name }}"
|
|
118
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
119
|
+
label="{{ f.text_key | t }}"
|
|
120
|
+
type="{{ f.type }}"
|
|
121
|
+
value="{{ f.value }}"
|
|
122
|
+
{% if autocomplete_val != '' %}autocomplete="{{ autocomplete_val }}"{% endif %}
|
|
123
|
+
{% if f.required %}required{% endif %}
|
|
124
|
+
{% if field_placeholder != "" %}placeholder="{{ field_placeholder }}"{% endif %}
|
|
125
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
126
|
+
>
|
|
127
|
+
{% if field_help != "" %}
|
|
128
|
+
<span slot="help">{{ field_help }}</span>
|
|
129
|
+
{% endif %}
|
|
130
|
+
</zl-field>
|
|
131
|
+
{% endcase %}
|
|
132
|
+
{% endfor %}
|
|
133
|
+
|
|
134
|
+
{% assign recover = actions | where: "name", "recover" | first %}
|
|
135
|
+
{% if recover %}
|
|
136
|
+
<p class="zl-card-forgot">
|
|
137
|
+
<a href="#" class="zl-card-forgot__link" data-action="recover">{{ recover.text_key | t }}</a>
|
|
138
|
+
</p>
|
|
139
|
+
{% endif %}
|
|
140
|
+
|
|
141
|
+
{% for a in actions %}
|
|
142
|
+
{% if a.primary %}
|
|
143
|
+
<zl-button
|
|
144
|
+
hierarchy="primary"
|
|
145
|
+
size="medium"
|
|
146
|
+
type="submit"
|
|
147
|
+
block
|
|
148
|
+
action="{{ a.name }}"
|
|
149
|
+
data-testid="zitadel-action-{{ a.name }}"
|
|
150
|
+
label="{{ a.text_key | t }}"
|
|
151
|
+
{% if loading %}loading{% endif %}
|
|
152
|
+
></zl-button>
|
|
153
|
+
{% endif %}
|
|
154
|
+
{% endfor %}
|
|
155
|
+
|
|
156
|
+
{% for a in actions %}
|
|
157
|
+
{% unless a.primary or a.kind == 'back' or a.name == 'passkey' or a.name == 'register' or a.name == 'sign_in' or a.name == 'recover' %}
|
|
158
|
+
<zl-button
|
|
159
|
+
hierarchy="secondary"
|
|
160
|
+
size="medium"
|
|
161
|
+
type="button"
|
|
162
|
+
block
|
|
163
|
+
action="{{ a.name }}"
|
|
164
|
+
data-testid="zitadel-action-{{ a.name }}"
|
|
165
|
+
label="{{ a.text_key | t }}"
|
|
166
|
+
></zl-button>
|
|
167
|
+
{% endunless %}
|
|
168
|
+
{% endfor %}
|
|
169
|
+
|
|
170
|
+
{% assign passkey = actions | where: "name", "passkey" | first %}
|
|
171
|
+
{% if passkey %}
|
|
172
|
+
{% unless passkey.primary %}
|
|
173
|
+
<zl-button
|
|
174
|
+
hierarchy="secondary"
|
|
175
|
+
size="medium"
|
|
176
|
+
block
|
|
177
|
+
action="passkey"
|
|
178
|
+
data-testid="zitadel-action-passkey"
|
|
179
|
+
label="{{ passkey.text_key | t }}"
|
|
180
|
+
></zl-button>
|
|
181
|
+
{% endunless %}
|
|
182
|
+
{% endif %}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
{% assign register = actions | where: "name", "register" | first %}
|
|
186
|
+
{% if register %}
|
|
187
|
+
<p class="zl-card-nav">
|
|
188
|
+
{{ 'identifier.action.register.lead' | t }}<a href="#" class="zl-card-nav__link" data-action="register" data-testid="zitadel-action-register-link">{{ 'identifier.action.register.link' | t }}</a>
|
|
189
|
+
</p>
|
|
190
|
+
{% endif %}
|
|
191
|
+
|
|
192
|
+
{% assign sign_in = actions | where: "name", "sign_in" | first %}
|
|
193
|
+
{% if sign_in %}
|
|
194
|
+
<p class="zl-card-nav">
|
|
195
|
+
{{ 'register.action.sign_in.lead' | t }}<a href="#" class="zl-card-nav__link" data-action="sign_in" data-testid="zitadel-action-sign_in-link">{{ 'register.action.sign_in.link' | t }}</a>
|
|
196
|
+
</p>
|
|
197
|
+
{% endif %}
|
|
198
|
+
|
|
199
|
+
{% if challenge %}
|
|
200
|
+
{% if challenge.method == "passkey" or challenge.method == "passkey_register" %}
|
|
201
|
+
{% assign ceremony = "authenticate" %}
|
|
202
|
+
{% assign submit_method = challenge.method %}
|
|
203
|
+
{% if challenge.method == "passkey_register" or challenge.options.user %}
|
|
204
|
+
{% assign ceremony = "register" %}
|
|
205
|
+
{% assign submit_method = "passkey_register" %}
|
|
206
|
+
{% endif %}
|
|
207
|
+
<zl-passkey
|
|
208
|
+
ceremony="{{ ceremony }}"
|
|
209
|
+
method="{{ submit_method }}"
|
|
210
|
+
challenge-id="{{ challenge.challenge_id }}"
|
|
211
|
+
options='{{ challenge.options | json }}'
|
|
212
|
+
pending-label="{{ 'passkey.pending.status' | t }}"
|
|
213
|
+
cancel-label="{{ 'action.cancel' | t }}"
|
|
214
|
+
></zl-passkey>
|
|
215
|
+
{% endif %}
|
|
216
|
+
{% endif %}
|
|
217
|
+
|
|
218
|
+
{% mandatory_gates %}
|
|
219
|
+
</zl-card>
|
|
220
|
+
</section>
|
|
221
|
+
</div>
|
|
222
|
+
</zl-page-shell>
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<zl-page-shell data-zl-template-root>
|
|
2
|
+
<section class="zl-minimal">
|
|
3
|
+
<h1 class="zl-card-title">{{ step.texts.title_key | t: identity.display_name }}</h1>
|
|
4
|
+
|
|
5
|
+
{% if errors and errors.size > 0 %}
|
|
6
|
+
{% for err in errors %}
|
|
7
|
+
{% if err | formLevelError %}
|
|
8
|
+
{% assign alert_heading = err.text_key | alertHeading %}
|
|
9
|
+
{% assign alert_body = err.text_key | alertBody %}
|
|
10
|
+
<zl-alert severity="error" dismissible data-zl-step-error{% if alert_heading != "" %} heading="{{ alert_heading | t }}"{% endif %}>
|
|
11
|
+
{% if alert_body != "" %}{{ alert_body | t }}{% elsif err.text_key %}{{ err.text_key | t }}{% else %}{{ err.message }}{% endif %}
|
|
12
|
+
</zl-alert>
|
|
13
|
+
{% endif %}
|
|
14
|
+
{% endfor %}
|
|
15
|
+
{% endif %}
|
|
16
|
+
|
|
17
|
+
{% for f in fields %}
|
|
18
|
+
{% assign field_placeholder = f.text_key | fieldPlaceholder %}
|
|
19
|
+
{% assign field_help = f.text_key | fieldHelp %}
|
|
20
|
+
{% assign field_err = f.name | fieldError: errors %}
|
|
21
|
+
{% case f.type %}
|
|
22
|
+
{% when 'checkbox' %}
|
|
23
|
+
<zl-checkbox
|
|
24
|
+
name="{{ f.name }}"
|
|
25
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
26
|
+
label="{{ f.text_key | t }}"
|
|
27
|
+
value="true"
|
|
28
|
+
{% if f.value %}checked{% endif %}
|
|
29
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
30
|
+
></zl-checkbox>
|
|
31
|
+
{% when 'select' %}
|
|
32
|
+
<zl-select
|
|
33
|
+
name="{{ f.name }}"
|
|
34
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
35
|
+
label="{{ f.text_key | t }}"
|
|
36
|
+
value="{{ f.value }}"
|
|
37
|
+
options='{{ f.validation.enum | selectOptions | json }}'
|
|
38
|
+
{% if f.required %}required{% endif %}
|
|
39
|
+
{% if field_placeholder != "" %}placeholder="{{ field_placeholder }}"{% endif %}
|
|
40
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
41
|
+
></zl-select>
|
|
42
|
+
{% else %}
|
|
43
|
+
{% assign autocomplete_val = '' %}
|
|
44
|
+
{% if f.name == 'email' %}
|
|
45
|
+
{% assign autocomplete_val = 'email' %}
|
|
46
|
+
{% elsif f.type == 'password' and step.name contains 'register' %}
|
|
47
|
+
{% assign autocomplete_val = 'new-password' %}
|
|
48
|
+
{% elsif f.type == 'password' %}
|
|
49
|
+
{% assign autocomplete_val = 'current-password' %}
|
|
50
|
+
{% endif %}
|
|
51
|
+
<zl-field
|
|
52
|
+
name="{{ f.name }}"
|
|
53
|
+
data-testid="zitadel-field-{{ f.name | testid }}"
|
|
54
|
+
label="{{ f.text_key | t }}"
|
|
55
|
+
type="{{ f.type }}"
|
|
56
|
+
value="{{ f.value }}"
|
|
57
|
+
{% if autocomplete_val != '' %}autocomplete="{{ autocomplete_val }}"{% endif %}
|
|
58
|
+
{% if f.required %}required{% endif %}
|
|
59
|
+
{% if field_placeholder != "" %}placeholder="{{ field_placeholder }}"{% endif %}
|
|
60
|
+
{% if field_err != "" %}invalid error="{{ field_err }}"{% endif %}
|
|
61
|
+
>
|
|
62
|
+
{% if field_help != "" %}
|
|
63
|
+
<span slot="help">{{ field_help }}</span>
|
|
64
|
+
{% endif %}
|
|
65
|
+
</zl-field>
|
|
66
|
+
{% endcase %}
|
|
67
|
+
{% endfor %}
|
|
68
|
+
|
|
69
|
+
{% assign recover = actions | where: "name", "recover" | first %}
|
|
70
|
+
{% if recover %}
|
|
71
|
+
<p class="zl-card-forgot">
|
|
72
|
+
<a href="#" class="zl-card-forgot__link" data-action="recover">{{ recover.text_key | t }}</a>
|
|
73
|
+
</p>
|
|
74
|
+
{% endif %}
|
|
75
|
+
|
|
76
|
+
{% for a in actions %}
|
|
77
|
+
{% if a.primary %}
|
|
78
|
+
<zl-button
|
|
79
|
+
hierarchy="primary"
|
|
80
|
+
size="medium"
|
|
81
|
+
type="submit"
|
|
82
|
+
block
|
|
83
|
+
action="{{ a.name }}"
|
|
84
|
+
data-testid="zitadel-action-{{ a.name }}"
|
|
85
|
+
label="{{ a.text_key | t }}"
|
|
86
|
+
{% if loading %}loading{% endif %}
|
|
87
|
+
></zl-button>
|
|
88
|
+
{% endif %}
|
|
89
|
+
{% endfor %}
|
|
90
|
+
|
|
91
|
+
{% for a in actions %}
|
|
92
|
+
{% unless a.primary or a.kind == 'back' or a.name == 'passkey' or a.name == 'register' or a.name == 'sign_in' or a.name == 'recover' %}
|
|
93
|
+
<zl-button
|
|
94
|
+
hierarchy="secondary"
|
|
95
|
+
size="medium"
|
|
96
|
+
type="button"
|
|
97
|
+
block
|
|
98
|
+
action="{{ a.name }}"
|
|
99
|
+
data-testid="zitadel-action-{{ a.name }}"
|
|
100
|
+
label="{{ a.text_key | t }}"
|
|
101
|
+
></zl-button>
|
|
102
|
+
{% endunless %}
|
|
103
|
+
{% endfor %}
|
|
104
|
+
|
|
105
|
+
{% assign passkey = actions | where: "name", "passkey" | first %}
|
|
106
|
+
{% if passkey %}
|
|
107
|
+
{% unless passkey.primary %}
|
|
108
|
+
<zl-button
|
|
109
|
+
hierarchy="secondary"
|
|
110
|
+
size="medium"
|
|
111
|
+
block
|
|
112
|
+
action="passkey"
|
|
113
|
+
data-testid="zitadel-action-passkey"
|
|
114
|
+
label="{{ passkey.text_key | t }}"
|
|
115
|
+
></zl-button>
|
|
116
|
+
{% endunless %}
|
|
117
|
+
{% endif %}
|
|
118
|
+
|
|
119
|
+
{% assign register = actions | where: "name", "register" | first %}
|
|
120
|
+
{% if register %}
|
|
121
|
+
<p class="zl-card-nav">
|
|
122
|
+
{{ 'identifier.action.register.lead' | t }}<a href="#" class="zl-card-nav__link" data-action="register" data-testid="zitadel-action-register-link">{{ 'identifier.action.register.link' | t }}</a>
|
|
123
|
+
</p>
|
|
124
|
+
{% endif %}
|
|
125
|
+
|
|
126
|
+
{% assign sign_in = actions | where: "name", "sign_in" | first %}
|
|
127
|
+
{% if sign_in %}
|
|
128
|
+
<p class="zl-card-nav">
|
|
129
|
+
{{ 'register.action.sign_in.lead' | t }}<a href="#" class="zl-card-nav__link" data-action="sign_in" data-testid="zitadel-action-sign_in-link">{{ 'register.action.sign_in.link' | t }}</a>
|
|
130
|
+
</p>
|
|
131
|
+
{% endif %}
|
|
132
|
+
|
|
133
|
+
{% if challenge %}
|
|
134
|
+
{% if challenge.method == "passkey" or challenge.method == "passkey_register" %}
|
|
135
|
+
{% assign ceremony = "authenticate" %}
|
|
136
|
+
{% assign submit_method = challenge.method %}
|
|
137
|
+
{% if challenge.method == "passkey_register" or challenge.options.user %}
|
|
138
|
+
{% assign ceremony = "register" %}
|
|
139
|
+
{% assign submit_method = "passkey_register" %}
|
|
140
|
+
{% endif %}
|
|
141
|
+
<zl-passkey
|
|
142
|
+
ceremony="{{ ceremony }}"
|
|
143
|
+
method="{{ submit_method }}"
|
|
144
|
+
challenge-id="{{ challenge.challenge_id }}"
|
|
145
|
+
options='{{ challenge.options | json }}'
|
|
146
|
+
pending-label="{{ 'passkey.pending.status' | t }}"
|
|
147
|
+
cancel-label="{{ 'action.cancel' | t }}"
|
|
148
|
+
></zl-passkey>
|
|
149
|
+
{% endif %}
|
|
150
|
+
{% endif %}
|
|
151
|
+
|
|
152
|
+
{% mandatory_gates %}
|
|
153
|
+
</section>
|
|
154
|
+
</zl-page-shell>
|