@atproto/oauth-provider-ui 0.0.2 → 0.1.0

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 (182) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/{src/authorization-page.html → authorization-page.html} +36 -33
  3. package/{src/error-page.html → error-page.html} +17 -24
  4. package/package.json +28 -37
  5. package/src/authorization-page.tsx +21 -27
  6. package/src/components/forms/button.tsx +8 -8
  7. package/src/components/forms/fieldset.tsx +1 -1
  8. package/src/components/forms/form-card-async.tsx +1 -1
  9. package/src/components/forms/form-card.tsx +1 -1
  10. package/src/components/forms/input-checkbox.tsx +3 -3
  11. package/src/components/forms/input-container.tsx +12 -12
  12. package/src/components/forms/input-text.tsx +2 -2
  13. package/src/components/forms/wizard-card.tsx +2 -2
  14. package/src/components/layouts/layout-title-page.tsx +9 -8
  15. package/src/components/layouts/layout-welcome.tsx +21 -16
  16. package/src/components/utils/account-image.tsx +2 -2
  17. package/src/components/utils/admonition.tsx +5 -5
  18. package/src/components/utils/client-name.tsx +30 -4
  19. package/src/components/utils/error-card.tsx +1 -1
  20. package/src/components/utils/help-card.tsx +3 -3
  21. package/src/components/utils/multi-lang-string.tsx +14 -8
  22. package/src/components/utils/password-strength-meter.tsx +3 -3
  23. package/src/components/utils/url-viewer.tsx +1 -1
  24. package/src/error-page.tsx +8 -14
  25. package/src/hooks/use-api.ts +65 -45
  26. package/src/hydration-data.d.ts +42 -0
  27. package/src/lib/api.ts +12 -21
  28. package/src/{cookies.ts → lib/cookies.ts} +8 -2
  29. package/src/lib/json-client.ts +62 -18
  30. package/src/lib/util.ts +2 -1
  31. package/src/locales/an/messages.po +35 -28
  32. package/src/locales/ast/messages.po +35 -28
  33. package/src/locales/ca/messages.po +35 -28
  34. package/src/locales/da/messages.po +35 -28
  35. package/src/locales/de/messages.po +35 -28
  36. package/src/locales/el/messages.po +35 -28
  37. package/src/locales/en/messages.po +35 -28
  38. package/src/locales/en-GB/messages.po +35 -28
  39. package/src/locales/es/messages.po +35 -28
  40. package/src/locales/eu/messages.po +35 -28
  41. package/src/locales/fi/messages.po +35 -28
  42. package/src/locales/fr/messages.po +35 -28
  43. package/src/locales/ga/messages.po +35 -28
  44. package/src/locales/gl/messages.po +35 -28
  45. package/src/locales/hi/messages.po +35 -28
  46. package/src/locales/hu/messages.po +35 -28
  47. package/src/locales/ia/messages.po +35 -28
  48. package/src/locales/id/messages.po +35 -28
  49. package/src/locales/it/messages.po +35 -28
  50. package/src/locales/ja/messages.po +35 -28
  51. package/src/locales/km/messages.po +35 -28
  52. package/src/locales/ko/messages.po +35 -28
  53. package/src/locales/locale-provider.tsx +55 -59
  54. package/src/locales/locale-selector.tsx +13 -14
  55. package/src/locales/locales.ts +161 -146
  56. package/src/locales/ne/messages.po +35 -28
  57. package/src/locales/nl/messages.po +35 -28
  58. package/src/locales/pl/messages.po +35 -28
  59. package/src/locales/pt-BR/messages.po +35 -28
  60. package/src/locales/ro/messages.po +35 -28
  61. package/src/locales/ru/messages.po +35 -28
  62. package/src/locales/sv/messages.po +35 -28
  63. package/src/locales/th/messages.po +35 -28
  64. package/src/locales/tr/messages.po +35 -28
  65. package/src/locales/uk/messages.po +35 -28
  66. package/src/locales/vi/messages.po +35 -28
  67. package/src/locales/zh-CN/messages.po +35 -28
  68. package/src/locales/zh-HK/messages.po +35 -28
  69. package/src/locales/zh-TW/messages.po +35 -28
  70. package/src/style.css +219 -0
  71. package/src/views/authorize/accept/accept-form.tsx +11 -6
  72. package/src/views/authorize/authorize-view.tsx +13 -10
  73. package/src/views/authorize/reset-password/reset-password-view.tsx +2 -2
  74. package/src/views/authorize/sign-in/sign-in-form.tsx +39 -41
  75. package/src/views/authorize/sign-in/sign-in-picker.tsx +3 -3
  76. package/src/views/authorize/sign-up/sign-up-disclaimer.tsx +3 -3
  77. package/src/views/authorize/sign-up/sign-up-handle-form.tsx +6 -6
  78. package/src/views/authorize/sign-up/sign-up-view.tsx +3 -3
  79. package/src/views/authorize/welcome/welcome-view.tsx +5 -5
  80. package/tsconfig.json +1 -2
  81. package/{tsconfig.frontend.json → tsconfig.src.json} +4 -1
  82. package/tsconfig.src.tsbuildinfo +1 -0
  83. package/tsconfig.tools.json +1 -1
  84. package/tsconfig.tools.tsbuildinfo +1 -1
  85. package/vite.config.mjs +38 -7
  86. package/dist/assets/COdVzed-.css +0 -3
  87. package/dist/assets/COdVzed-.js +0 -100
  88. package/dist/assets/COdVzed-.js.map +0 -1
  89. package/dist/assets/Cqnfnbvc.js +0 -6
  90. package/dist/assets/Cqnfnbvc.js.map +0 -1
  91. package/dist/assets/bundle-manifest.json +0 -630
  92. package/dist/assets/error-view-Bu4y7Nd8.js +0 -208
  93. package/dist/assets/error-view-Bu4y7Nd8.js.map +0 -1
  94. package/dist/assets/index-DXlCRM6V.js +0 -36
  95. package/dist/assets/index-DXlCRM6V.js.map +0 -1
  96. package/dist/assets/messages-2GoTm2qL.js +0 -4
  97. package/dist/assets/messages-2GoTm2qL.js.map +0 -1
  98. package/dist/assets/messages-6Cn2Jbhw.js +0 -4
  99. package/dist/assets/messages-6Cn2Jbhw.js.map +0 -1
  100. package/dist/assets/messages-75hFgOK2.js +0 -4
  101. package/dist/assets/messages-75hFgOK2.js.map +0 -1
  102. package/dist/assets/messages-B3OK4k0O.js +0 -4
  103. package/dist/assets/messages-B3OK4k0O.js.map +0 -1
  104. package/dist/assets/messages-BNXlPzKV.js +0 -4
  105. package/dist/assets/messages-BNXlPzKV.js.map +0 -1
  106. package/dist/assets/messages-BUygB8mD.js +0 -4
  107. package/dist/assets/messages-BUygB8mD.js.map +0 -1
  108. package/dist/assets/messages-BVPPcwNr.js +0 -4
  109. package/dist/assets/messages-BVPPcwNr.js.map +0 -1
  110. package/dist/assets/messages-BbbWUQS8.js +0 -4
  111. package/dist/assets/messages-BbbWUQS8.js.map +0 -1
  112. package/dist/assets/messages-BibKCYyW.js +0 -4
  113. package/dist/assets/messages-BibKCYyW.js.map +0 -1
  114. package/dist/assets/messages-BlPrr9_7.js +0 -4
  115. package/dist/assets/messages-BlPrr9_7.js.map +0 -1
  116. package/dist/assets/messages-ByVCw40U.js +0 -4
  117. package/dist/assets/messages-ByVCw40U.js.map +0 -1
  118. package/dist/assets/messages-C5DU1neP.js +0 -4
  119. package/dist/assets/messages-C5DU1neP.js.map +0 -1
  120. package/dist/assets/messages-C6IgUtbX.js +0 -4
  121. package/dist/assets/messages-C6IgUtbX.js.map +0 -1
  122. package/dist/assets/messages-C92Zzt2o.js +0 -4
  123. package/dist/assets/messages-C92Zzt2o.js.map +0 -1
  124. package/dist/assets/messages-CGZqYT14.js +0 -4
  125. package/dist/assets/messages-CGZqYT14.js.map +0 -1
  126. package/dist/assets/messages-CGlsy4wt.js +0 -4
  127. package/dist/assets/messages-CGlsy4wt.js.map +0 -1
  128. package/dist/assets/messages-CPT1nd0u.js +0 -4
  129. package/dist/assets/messages-CPT1nd0u.js.map +0 -1
  130. package/dist/assets/messages-CTTdXyw_.js +0 -4
  131. package/dist/assets/messages-CTTdXyw_.js.map +0 -1
  132. package/dist/assets/messages-ChK_C_Pj.js +0 -4
  133. package/dist/assets/messages-ChK_C_Pj.js.map +0 -1
  134. package/dist/assets/messages-CjJbk7Uf.js +0 -4
  135. package/dist/assets/messages-CjJbk7Uf.js.map +0 -1
  136. package/dist/assets/messages-CoiLjLYO.js +0 -4
  137. package/dist/assets/messages-CoiLjLYO.js.map +0 -1
  138. package/dist/assets/messages-Cwx6B4Ti.js +0 -4
  139. package/dist/assets/messages-Cwx6B4Ti.js.map +0 -1
  140. package/dist/assets/messages-D0uXAp_H.js +0 -4
  141. package/dist/assets/messages-D0uXAp_H.js.map +0 -1
  142. package/dist/assets/messages-DG0_arU0.js +0 -4
  143. package/dist/assets/messages-DG0_arU0.js.map +0 -1
  144. package/dist/assets/messages-DOXFJh9K.js +0 -4
  145. package/dist/assets/messages-DOXFJh9K.js.map +0 -1
  146. package/dist/assets/messages-DPK7nOoC.js +0 -4
  147. package/dist/assets/messages-DPK7nOoC.js.map +0 -1
  148. package/dist/assets/messages-Duccgtu0.js +0 -4
  149. package/dist/assets/messages-Duccgtu0.js.map +0 -1
  150. package/dist/assets/messages-DxTqgsHq.js +0 -4
  151. package/dist/assets/messages-DxTqgsHq.js.map +0 -1
  152. package/dist/assets/messages-E5_lTg7A.js +0 -4
  153. package/dist/assets/messages-E5_lTg7A.js.map +0 -1
  154. package/dist/assets/messages-UhunAjh1.js +0 -4
  155. package/dist/assets/messages-UhunAjh1.js.map +0 -1
  156. package/dist/assets/messages-Xg_3YLGw.js +0 -4
  157. package/dist/assets/messages-Xg_3YLGw.js.map +0 -1
  158. package/dist/assets/messages-iliBQHY2.js +0 -4
  159. package/dist/assets/messages-iliBQHY2.js.map +0 -1
  160. package/dist/assets/messages-lRprpIl-.js +0 -4
  161. package/dist/assets/messages-lRprpIl-.js.map +0 -1
  162. package/dist/assets/messages-pbPHQbz1.js +0 -4
  163. package/dist/assets/messages-pbPHQbz1.js.map +0 -1
  164. package/dist/assets/messages-q-O7ZQGs.js +0 -4
  165. package/dist/assets/messages-q-O7ZQGs.js.map +0 -1
  166. package/dist/lib/index.d.ts +0 -19
  167. package/dist/lib/index.d.ts.map +0 -1
  168. package/dist/lib/index.js +0 -47
  169. package/dist/lib/index.js.map +0 -1
  170. package/dist/tsconfig.backend.tsbuildinfo +0 -1
  171. package/lib/index.ts +0 -72
  172. package/rollup.config.js +0 -102
  173. package/src/backend-data.ts +0 -35
  174. package/src/hooks/use-csrf-token.ts +0 -5
  175. package/src/lib/backend-data.ts +0 -6
  176. package/src/lib/clsx.ts +0 -6
  177. package/src/locales/locale-context.ts +0 -19
  178. package/src/styles.css +0 -33
  179. package/tailwind.config.js +0 -31
  180. package/tsconfig.backend.json +0 -8
  181. package/tsconfig.frontend.tsbuildinfo +0 -1
  182. /package/{src/index.html → index.html} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @atproto/oauth-provider-ui
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#3659](https://github.com/bluesky-social/atproto/pull/3659) [`371e04aad`](https://github.com/bluesky-social/atproto/commit/371e04aad2a3e8ae3fe185ce15fc8eb051cab78e) Thanks [@matthieusieben](https://github.com/matthieusieben)! - New build system
8
+
9
+ ### Patch Changes
10
+
11
+ - [#3667](https://github.com/bluesky-social/atproto/pull/3667) [`8b98fec88`](https://github.com/bluesky-social/atproto/commit/8b98fec8857aacddeed9efb5c755474951e6d9d4) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Hide client id pathname if it is exaclty `/oauth-client-metadata.json`
12
+
3
13
  ## 0.0.2
4
14
 
5
15
  ### Patch Changes
@@ -26,30 +26,27 @@
26
26
  */
27
27
  </script>
28
28
  <style>
29
- /*
30
- * PDS branding configuration (colors), in R G B format.
31
- *
32
- * The variables here are meant to override the default values defined in
33
- * main.css. These values are typically generated by the backend and
34
- * injected into the HTML. The colors suffixed with "-c" denote the
35
- * "contrast" color of the corresponding color name. These are also
36
- * automatically generated by the backend from the branding colors.
37
- *
38
- * The default colors can be seen by commenting out a color name (and
39
- * corresponding "-c" contrast color) below:
40
- */
41
29
  :root {
42
- --color-brand: 10 122 255;
43
- --color-brand-c: 255 255 255;
44
- --color-error: 244 11 66;
45
- --color-error-c: 255 255 255;
46
- --color-warning: 251 86 7;
47
- --color-warning-c: 255 255 255;
48
- --color-success: 2 195 154;
49
- --color-success-c: 0 0 0;
30
+ --branding-color-primary: 10 122 255;
31
+ --branding-color-primary-contrast: 255 255 255;
32
+ --branding-color-primary-hue: 212.57142857142856;
33
+
34
+ --branding-color-error: 244 11 66;
35
+ --branding-color-error-contrast: 255 255 255;
36
+ --branding-color-error-hue: 345.83690987124464;
37
+
38
+ --branding-color-warning: 251 86 7;
39
+ --branding-color-warning-contrast: 255 255 255;
40
+ --branding-color-warning-hue: 19.426229508196723;
41
+
42
+ --branding-color-success: 2 195 154;
43
+ --branding-color-success-contrast: 0 0 0;
44
+ --branding-color-success-hue: 167.2538860103627;
50
45
  }
51
46
  </style>
52
47
  <script type="module">
48
+ import { API_ENDPOINT_PREFIX } from '@atproto/oauth-provider-api'
49
+
53
50
  /*
54
51
  * PDS branding configuration
55
52
  */
@@ -106,8 +103,6 @@
106
103
 
107
104
  document.cookie = `csrf-${requestUri}=xyz; path=/`
108
105
 
109
- window.__availableLocales = ['en', 'fr']
110
-
111
106
  window.__customizationData = {
112
107
  availableUserDomains,
113
108
  inviteCodeRequired: false,
@@ -129,7 +124,6 @@
129
124
  clientTrusted: false,
130
125
  requestUri,
131
126
  loginHint,
132
- newSessionsRequireConsent: true,
133
127
  sessions: [],
134
128
  scopeDetails: [
135
129
  { scope: 'atproto' },
@@ -143,11 +137,17 @@
143
137
  async function mockFetch(...args) {
144
138
  const [input, init] = args
145
139
 
146
- if (typeof input === 'string' && init.method === 'POST') {
147
- const url = new URL(input, window.location)
148
- switch (url.pathname) {
149
- case '/oauth/authorize/sign-up':
150
- case '/oauth/authorize/sign-in':
140
+ const method = init?.method ?? 'GET'
141
+ const url =
142
+ typeof input === 'string'
143
+ ? new URL(input, window.location)
144
+ : input instanceof URL
145
+ ? input
146
+ : undefined
147
+ if (url) {
148
+ switch (`${method} ${url.pathname}`) {
149
+ case `POST ${API_ENDPOINT_PREFIX}/sign-up`:
150
+ case `POST ${API_ENDPOINT_PREFIX}/sign-in`:
151
151
  return new Response(
152
152
  JSON.stringify({
153
153
  consentRequired: false,
@@ -160,11 +160,14 @@
160
160
  picture: 'https://cat.com/cat.jpg',
161
161
  },
162
162
  }),
163
- { status: 200 },
163
+ {
164
+ status: 200,
165
+ headers: { 'Content-Type': 'application/json' },
166
+ },
164
167
  )
165
- case '/oauth/authorize/verify-handle-availability':
166
- case '/oauth/authorize/reset-password-request':
167
- case '/oauth/authorize/reset-password-confirm':
168
+ case `POST ${API_ENDPOINT_PREFIX}/verify-handle-availability`:
169
+ case `POST ${API_ENDPOINT_PREFIX}/reset-password-request`:
170
+ case `POST ${API_ENDPOINT_PREFIX}/reset-password-confirm`:
168
171
  return new Response(null, { status: 204 })
169
172
  }
170
173
  }
@@ -178,6 +181,6 @@
178
181
  configurable: true,
179
182
  })
180
183
  </script>
181
- <script src="./authorization-page.tsx" type="module"></script>
184
+ <script src="./src/authorization-page.tsx" type="module"></script>
182
185
  </body>
183
186
  </html>
@@ -26,27 +26,22 @@
26
26
  */
27
27
  </script>
28
28
  <style>
29
- /*
30
- * PDS branding configuration (colors), in R G B format.
31
- *
32
- * The variables here are meant to override the default values defined in
33
- * main.css. These values are typically generated by the backend and
34
- * injected into the HTML. The colors suffixed with "-c" denote the
35
- * "contrast" color of the corresponding color name. These are also
36
- * automatically generated by the backend from the branding colors.
37
- *
38
- * The default colors can be seen by commenting out a color name (and
39
- * corresponding "-c" contrast color) below:
40
- */
41
29
  :root {
42
- --color-brand: 10 122 255;
43
- --color-brand-c: 255 255 255;
44
- --color-error: 244 11 66;
45
- --color-error-c: 255 255 255;
46
- --color-warning: 251 86 7;
47
- --color-warning-c: 255 255 255;
48
- --color-success: 2 195 154;
49
- --color-success-c: 0 0 0;
30
+ --branding-color-primary: 10 122 255;
31
+ --branding-color-primary-contrast: 255 255 255;
32
+ --branding-color-primary-hue: 212.57142857142856;
33
+
34
+ --branding-color-error: 244 11 66;
35
+ --branding-color-error-contrast: 255 255 255;
36
+ --branding-color-error-hue: 345.83690987124464;
37
+
38
+ --branding-color-warning: 251 86 7;
39
+ --branding-color-warning-contrast: 255 255 255;
40
+ --branding-color-warning-hue: 19.426229508196723;
41
+
42
+ --branding-color-success: 2 195 154;
43
+ --branding-color-success-contrast: 0 0 0;
44
+ --branding-color-success-hue: 167.2538860103627;
50
45
  }
51
46
  </style>
52
47
  <script type="module">
@@ -57,7 +52,7 @@
57
52
  const name = 'Bluesky'
58
53
  const links = [
59
54
  {
60
- title: { en: 'Home' },
55
+ title: { en: 'Home', fr: 'Accueil' },
61
56
  href: 'https://bsky.social/',
62
57
  rel: 'canonical', // prevents the login page from being indexed by search engines
63
58
  },
@@ -104,8 +99,6 @@
104
99
 
105
100
  const requestUri = 'foo-bar'
106
101
 
107
- window.__availableLocales = ['en', 'fr']
108
-
109
102
  window.__customizationData = {
110
103
  availableUserDomains,
111
104
  inviteCodeRequired: false,
@@ -120,6 +113,6 @@
120
113
  error_description: 'bar',
121
114
  }
122
115
  </script>
123
- <script src="./error-page.tsx" type="module"></script>
116
+ <script src="./src/error-page.tsx" type="module"></script>
124
117
  </body>
125
118
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/oauth-provider-ui",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "license": "MIT",
5
5
  "description": "Sign-in & Sign-up UI for the @atproto/oauth-provider",
6
6
  "homepage": "https://atproto.com",
@@ -9,17 +9,22 @@
9
9
  "url": "https://github.com/bluesky-social/atproto",
10
10
  "directory": "packages/oauth/oauth-provider-ui"
11
11
  },
12
+ "engines": {
13
+ "node": ">=18.7.0"
14
+ },
12
15
  "type": "commonjs",
13
- "main": "dist/lib/index.js",
14
- "types": "dist/lib/index.d.ts",
15
16
  "exports": {
16
- ".": {
17
- "types": "./dist/lib/index.d.ts",
18
- "default": "./dist/lib/index.js"
17
+ "./bundle-manifest.json": {
18
+ "default": "./dist/bundle-manifest.json"
19
+ },
20
+ "./hydration-data": {
21
+ "types": "./src/hydration-data.d.ts"
19
22
  }
20
23
  },
21
- "engines": {
22
- "node": ">=18.7.0"
24
+ "optionalDependencies": {
25
+ "@atproto-labs/rollup-plugin-bundle-manifest": "0.2.0",
26
+ "@atproto/oauth-provider-api": "0.1.0",
27
+ "@atproto/oauth-types": "0.2.5"
23
28
  },
24
29
  "devDependencies": {
25
30
  "@hcaptcha/react-hcaptcha": "^1.11.2",
@@ -28,46 +33,32 @@
28
33
  "@lingui/react": "^5.2.0",
29
34
  "@lingui/swc-plugin": "^5.4.0",
30
35
  "@lingui/vite-plugin": "^5.2.0",
31
- "@rollup/plugin-commonjs": "^28.0.2",
32
- "@rollup/plugin-dynamic-import-vars": "^2.1.5",
33
- "@rollup/plugin-node-resolve": "^16.0.0",
34
- "@rollup/plugin-swc": "^0.4.0",
35
- "@swc/core": "^1.10.18",
36
- "@swc/helpers": "^0.5.15",
36
+ "@tailwindcss/vite": "^4.1.3",
37
37
  "@types/react": "^19.0.10",
38
38
  "@types/react-dom": "^19.0.4",
39
39
  "@vitejs/plugin-react-swc": "^3.8.0",
40
- "@web/rollup-plugin-import-meta-assets": "^2.2.1",
41
- "autoprefixer": "^10.4.17",
40
+ "clsx": "^2.1.1",
42
41
  "postcss": "^8.4.38",
43
42
  "react": "^19.0.0",
44
43
  "react-dom": "^19.0.0",
45
44
  "react-error-boundary": "^5.0.0",
46
- "rollup": "^4.13.0",
47
- "rollup-plugin-postcss": "^4.0.2",
48
- "tailwindcss": "^3.4.3",
45
+ "tailwindcss": "^4.1.3",
49
46
  "typescript": "^5.6.3",
50
47
  "vite": "^6.2.0",
48
+ "@atproto-labs/rollup-plugin-bundle-manifest": "0.2.0",
51
49
  "@atproto-labs/fetch": "0.2.2",
52
- "@atproto-labs/rollup-plugin-bundle-manifest": "0.1.2",
53
- "@atproto/oauth-provider-api": "0.0.1",
54
- "@atproto/oauth-types": "0.2.4"
55
- },
56
- "postcss": {
57
- "plugins": {
58
- "tailwindcss": {},
59
- "autoprefixer": {}
60
- }
50
+ "@atproto/oauth-provider-api": "0.1.0",
51
+ "@atproto/oauth-types": "0.2.5"
61
52
  },
62
53
  "scripts": {
63
- "po:extract": "lingui extract --clean",
64
- "po:compile": "lingui compile --typescript",
65
- "prebuild:frontend": "pnpm run po:compile",
66
- "build:frontend": "rollup --config rollup.config.js",
67
- "build:backend": "tsc --build tsconfig.backend.json",
68
- "dev:ui": "vite",
69
- "dev:frontend": "rollup --config rollup.config.js --watch",
70
- "dev:catalogs": "pnpm run po:extract --debounce 250 --watch > /dev/null",
71
- "dev:messages": "pnpm run po:compile --debounce 500 --watch"
54
+ "i18n:extract": "lingui extract --clean",
55
+ "i18n:compile": "lingui compile --typescript",
56
+ "i18n": "pnpm i18n:extract && pnpm i18n:compile",
57
+ "prebuild": "pnpm run i18n",
58
+ "build": "vite build -- ignore additional npm args",
59
+ "dev:ui": "vite --port 5174",
60
+ "dev:src": "vite build --watch",
61
+ "dev:catalogs": "pnpm run i18n:extract --debounce 250 --watch > /dev/null",
62
+ "dev:messages": "pnpm run i18n:compile --debounce 500 --watch"
72
63
  }
73
64
  }
@@ -1,45 +1,38 @@
1
- import './styles.css'
1
+ import './style.css'
2
2
 
3
3
  import { StrictMode } from 'react'
4
4
  import { createRoot } from 'react-dom/client'
5
5
  import { ErrorBoundary } from 'react-error-boundary'
6
- import type {
7
- AuthorizeData,
8
- AvailableLocales,
9
- CustomizationData,
10
- } from '@atproto/oauth-provider-api'
11
- import { readBackendData } from './lib/backend-data.ts'
6
+ import type { HydrationData } from './hydration-data.d.ts'
12
7
  import { LocaleProvider } from './locales/locale-provider.tsx'
13
8
  import { AuthorizeView } from './views/authorize/authorize-view.tsx'
14
9
  import { ErrorView } from './views/error/error-view.tsx'
15
10
 
16
- export const availableLocales =
17
- readBackendData<AvailableLocales>('__availableLocales')
18
- export const customizationData = readBackendData<CustomizationData>(
19
- '__customizationData',
20
- )
21
- export const authorizeData = readBackendData<AuthorizeData>('__authorizeData')
11
+ const {
12
+ __authorizeData: authorizeData,
13
+ __sessions: sessions,
14
+ __customizationData: customizationData,
15
+ } = window as typeof window & HydrationData['authorization-page']
22
16
 
23
- if (authorizeData) {
24
- // When the user is logging in, make sure the page URL contains the
25
- // "request_uri" in case the user refreshes the page.
26
- const url = new URL(window.location.href)
27
- if (
28
- url.pathname === '/oauth/authorize' &&
29
- !url.searchParams.has('request_uri')
30
- ) {
31
- url.search = ''
32
- url.searchParams.set('client_id', authorizeData.clientId)
33
- url.searchParams.set('request_uri', authorizeData.requestUri)
34
- window.history.replaceState(history.state, '', url.pathname + url.search)
35
- }
17
+ // When the user is logging in, make sure the page URL contains the
18
+ // "request_uri" in case the user refreshes the page.
19
+ // @TODO Actually do this on the backend through a redirect.
20
+ const url = new URL(window.location.href)
21
+ if (
22
+ url.pathname === '/oauth/authorize' &&
23
+ !url.searchParams.has('request_uri')
24
+ ) {
25
+ url.search = ''
26
+ url.searchParams.set('client_id', authorizeData.clientId)
27
+ url.searchParams.set('request_uri', authorizeData.requestUri)
28
+ window.history.replaceState(history.state, '', url.pathname + url.search)
36
29
  }
37
30
 
38
31
  const container = document.getElementById('root')!
39
32
 
40
33
  createRoot(container).render(
41
34
  <StrictMode>
42
- <LocaleProvider availableLocales={availableLocales}>
35
+ <LocaleProvider userLocales={authorizeData.uiLocales?.split(' ')}>
43
36
  <ErrorBoundary
44
37
  fallbackRender={({ error }) => (
45
38
  <ErrorView error={error} customizationData={customizationData} />
@@ -48,6 +41,7 @@ createRoot(container).render(
48
41
  <AuthorizeView
49
42
  customizationData={customizationData}
50
43
  authorizeData={authorizeData}
44
+ sessions={sessions}
51
45
  />
52
46
  </ErrorBoundary>
53
47
  </LocaleProvider>
@@ -1,11 +1,11 @@
1
+ import { clsx } from 'clsx'
1
2
  import { JSX } from 'react'
2
- import { clsx } from '../../lib/clsx.ts'
3
3
  import { Override } from '../../lib/util.ts'
4
4
 
5
5
  export type ButtonProps = Override<
6
6
  JSX.IntrinsicElements['button'],
7
7
  {
8
- color?: 'brand' | 'grey'
8
+ color?: 'primary' | 'grey'
9
9
  loading?: boolean
10
10
  transparent?: boolean
11
11
  square?: boolean
@@ -33,18 +33,18 @@ export function Button({
33
33
  disabled={disabled || loading === true}
34
34
  {...props}
35
35
  className={clsx(
36
- 'rounded-lg truncate cursor-pointer touch-manipulation tracking-wide overflow-hidden',
37
- square ? 'p-2' : 'py-2 px-6',
38
- color === 'brand'
36
+ 'cursor-pointer touch-manipulation overflow-hidden truncate rounded-md tracking-wide',
37
+ square ? 'p-2' : 'px-6 py-2',
38
+ color === 'primary'
39
39
  ? clsx(
40
40
  'accent-slate-100',
41
41
  transparent
42
- ? 'bg-transparent text-brand'
43
- : 'bg-brand text-brand-c',
42
+ ? 'text-primary bg-transparent'
43
+ : 'bg-primary text-primary-contrast',
44
44
  )
45
45
  : color === 'grey'
46
46
  ? clsx(
47
- 'accent-brand',
47
+ 'accent-primary',
48
48
  'text-slate-600 dark:text-slate-300',
49
49
  'hover:bg-gray-200 dark:hover:bg-gray-700',
50
50
  transparent ? 'bg-transparent' : 'bg-gray-100 dark:bg-gray-800',
@@ -41,7 +41,7 @@ export function Fieldset({
41
41
  <legend
42
42
  id={labelId}
43
43
  key="title"
44
- className="mb-1 text-slate-600 dark:text-slate-400 text-sm font-medium"
44
+ className="mb-1 text-sm font-medium text-slate-600 dark:text-slate-400"
45
45
  >
46
46
  {label}
47
47
  </legend>
@@ -88,7 +88,7 @@ export function FormCardAsync({
88
88
  }
89
89
  actions={
90
90
  <Button
91
- color="brand"
91
+ color="primary"
92
92
  type="submit"
93
93
  loading={loading}
94
94
  disabled={disabled}
@@ -37,7 +37,7 @@ export function FormCard({
37
37
  {(actions || cancel) && (
38
38
  <div
39
39
  key="buttons"
40
- className="flex flex-wrap flex-row-reverse items-center justify-end space-x-reverse space-x-2"
40
+ className="flex flex-row-reverse flex-wrap items-center justify-end space-x-2 space-x-reverse"
41
41
  >
42
42
  {actions}
43
43
  <div className="flex-auto" />
@@ -1,6 +1,6 @@
1
+ import { clsx } from 'clsx'
1
2
  import { JSX, ReactNode, useContext, useRef } from 'react'
2
3
  import { useRandomString } from '../../hooks/use-random-string.ts'
3
- import { clsx } from '../../lib/clsx.ts'
4
4
  import { mergeRefs } from '../../lib/ref.ts'
5
5
  import { Override } from '../../lib/util.ts'
6
6
  import { FieldsetContext } from './fieldset.tsx'
@@ -51,7 +51,7 @@ export function InputCheckbox({
51
51
  }
52
52
  ref={mergeRefs([ref, inputRef])}
53
53
  id={inputId}
54
- className="accent-brand outline-none"
54
+ className="accent-primary outline-hidden"
55
55
  type="checkbox"
56
56
  />
57
57
  }
@@ -68,7 +68,7 @@ export function InputCheckbox({
68
68
  <label
69
69
  ref={labelRef}
70
70
  htmlFor={inputId}
71
- className="block w-full leading-[1.6] select-none cursor-pointer"
71
+ className="block w-full cursor-pointer select-none leading-[1.6]"
72
72
  >
73
73
  {children}
74
74
  </label>
@@ -1,5 +1,5 @@
1
+ import { clsx } from 'clsx'
1
2
  import { JSX, ReactNode, useState } from 'react'
2
- import { clsx } from '../../lib/clsx.ts'
3
3
  import { Override } from '../../lib/util.ts'
4
4
 
5
5
  export type InputContainerProps = Override<
@@ -50,22 +50,22 @@ export function InputContainer({
50
50
  className={clsx(
51
51
  // Layout
52
52
  'px-1',
53
- 'w-full min-h-12',
53
+ 'min-h-12 w-full',
54
54
  'flex items-center justify-stretch',
55
55
  // Border
56
56
  'rounded-lg',
57
- bellow ? 'rounded-br-none rounded-bl-none' : undefined,
58
- 'outline-none',
59
- 'border-solid border-2 border-transparent',
60
- 'focus:border-brand has-[:focus]:border-brand',
57
+ bellow ? 'rounded-bl-none rounded-br-none' : undefined,
58
+ 'outline-hidden',
59
+ 'border-2 border-solid border-transparent',
60
+ 'focus:border-primary has-focus:border-primary',
61
61
  'hover:border-gray-400 hover:focus:border-gray-400',
62
62
  'dark:hover:border-gray-500 dark:hover:focus:border-gray-500',
63
63
  // Background
64
- 'bg-gray-100 focus:bg-slate-200 has-[:focus]:bg-slate-200',
65
- 'dark:bg-slate-800 dark:focus:bg-slate-700 dark:has-[:focus]:bg-slate-700',
64
+ 'has-focus:bg-slate-200 bg-gray-100 focus:bg-slate-200',
65
+ 'dark:has-focus:bg-slate-700 dark:bg-slate-800 dark:focus:bg-slate-700',
66
66
  // Font
67
67
  'text-slate-600 dark:text-slate-300',
68
- 'accent-brand',
68
+ 'accent-primary',
69
69
  )}
70
70
  >
71
71
  {icon && (
@@ -73,7 +73,7 @@ export function InputContainer({
73
73
  className={clsx(
74
74
  'shrink-0 grow-0',
75
75
  'mx-1',
76
- hasFocus ? 'text-brand' : 'text-slate-500',
76
+ hasFocus ? 'text-primary' : 'text-slate-500',
77
77
  )}
78
78
  >
79
79
  {icon}
@@ -82,13 +82,13 @@ export function InputContainer({
82
82
 
83
83
  {children}
84
84
 
85
- <div className="ml-1 grow-0 shrink-0 flex items-center">{append}</div>
85
+ <div className="ml-1 flex shrink-0 grow-0 items-center">{append}</div>
86
86
  </div>
87
87
  {bellow && (
88
88
  <div
89
89
  className={clsx(
90
90
  // Layout
91
- 'px-3 py-2 space-x-2',
91
+ 'space-x-2 px-3 py-2',
92
92
  'flex flex-row items-center gap-1',
93
93
  // Border
94
94
  'rounded-br-2 rounded-bl-2',
@@ -1,5 +1,5 @@
1
+ import { clsx } from 'clsx'
1
2
  import { JSX, ReactNode, useContext, useRef } from 'react'
2
- import { clsx } from '../../lib/clsx.ts'
3
3
  import { mergeRefs } from '../../lib/ref.ts'
4
4
  import { Override } from '../../lib/util.ts'
5
5
  import { FieldsetContext } from './fieldset.tsx'
@@ -67,7 +67,7 @@ export function InputText({
67
67
  aria-label={ariaLabel}
68
68
  aria-labelledby={ariaLabelledBy ?? ctx.labelId}
69
69
  ref={mergeRefs([ref, inputRef])}
70
- className="w-full bg-transparent bg-clip-padding text-base text-inherit outline-none dark:placeholder-gray-500 text-ellipsis"
70
+ className="outline-hidden w-full text-ellipsis bg-transparent bg-clip-padding text-base text-inherit dark:placeholder-gray-500"
71
71
  onFocus={(event) => {
72
72
  onFocus?.(event)
73
73
  if (!event.defaultPrevented) focusedRef.current = true
@@ -1,7 +1,7 @@
1
1
  import { Trans } from '@lingui/react/macro'
2
+ import { clsx } from 'clsx'
2
3
  import { JSX, ReactNode, useCallback } from 'react'
3
4
  import { DisabledStep, Step, useStepper } from '../../hooks/use-stepper.ts'
4
- import { clsx } from '../../lib/clsx.ts'
5
5
  import { Override } from '../../lib/util.ts'
6
6
 
7
7
  export type DoneFn = (...a: any) => unknown
@@ -108,7 +108,7 @@ export function WizardCard<TDone extends DoneFn>({
108
108
  </Trans>
109
109
  </p>
110
110
 
111
- {stepTitle && <h2 className="font-medium text-xl mb-4">{stepTitle}</h2>}
111
+ {stepTitle && <h2 className="mb-4 text-xl font-medium">{stepTitle}</h2>}
112
112
 
113
113
  {stepContent}
114
114
  </div>
@@ -1,5 +1,5 @@
1
+ import { clsx } from 'clsx'
1
2
  import { JSX, ReactNode } from 'react'
2
- import { clsx } from '../../lib/clsx.ts'
3
3
  import { Override } from '../../lib/util.ts'
4
4
  import { LocaleSelector } from '../../locales/locale-selector.tsx'
5
5
 
@@ -27,8 +27,8 @@ export function LayoutTitlePage({
27
27
  className={clsx(
28
28
  className,
29
29
  'flex flex-col items-center',
30
- 'md:flex md:flex-row md:justify-stretch md:items-center',
31
- 'min-h-screen min-w-screen',
30
+ 'md:flex md:flex-row md:items-center md:justify-stretch',
31
+ 'min-w-screen min-h-screen',
32
32
  'bg-white text-slate-900',
33
33
  'dark:bg-slate-900 dark:text-slate-100',
34
34
  )}
@@ -40,19 +40,20 @@ export function LayoutTitlePage({
40
40
  'px-6 pt-4',
41
41
  'w-full',
42
42
  'md:max-w-lg',
43
- 'flex flex-row md:flex-col',
43
+ 'flex flex-row items-start',
44
+ 'md:flex-col md:items-end',
44
45
  'md:self-stretch',
45
- 'md:w-1/2 md:max-w-fix md:p-4',
46
+ 'md:max-w-fix md:w-1/2 md:p-4',
46
47
  'md:text-right',
47
48
  'md:dark:border-r md:dark:border-slate-700',
48
49
  'md:bg-slate-100 md:dark:bg-slate-800',
49
50
  )}
50
51
  >
51
- <div className="flex-grow grid content-center md:justify-items-end">
52
+ <div className="grid grow content-center md:justify-items-end">
52
53
  {title && (
53
54
  <h1
54
55
  key="title"
55
- className="text-xl md:text-2xl lg:text-5xl md:my-4 font-semibold text-brand"
56
+ className="text-primary text-xl font-semibold md:my-4 md:text-2xl lg:text-5xl"
56
57
  >
57
58
  {title}
58
59
  </h1>
@@ -61,7 +62,7 @@ export function LayoutTitlePage({
61
62
  {subtitle && (
62
63
  <p
63
64
  key="subtitle"
64
- className="hidden md:block max-w-xs text-slate-600 dark:text-slate-400"
65
+ className="hidden max-w-xs text-slate-600 md:block dark:text-slate-400"
65
66
  >
66
67
  {subtitle}
67
68
  </p>