@olmocms/front 0.1.2 → 0.1.6
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/README.md +30 -44
- package/dist/auth/action.cjs +106 -0
- package/dist/auth/action.cjs.map +1 -0
- package/dist/auth/action.d.cts +7 -0
- package/dist/auth/action.d.ts +7 -0
- package/dist/auth/action.js +82 -0
- package/dist/auth/action.js.map +1 -0
- package/dist/chunk-UCR7WW3X.js +169 -0
- package/dist/chunk-UCR7WW3X.js.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/components/index.cjs +93 -0
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +18 -1
- package/dist/components/index.d.ts +18 -1
- package/dist/components/index.js +92 -0
- package/dist/components/index.js.map +1 -1
- package/dist/index.cjs +197 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +96 -2
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.cjs +106 -2
- package/dist/middleware/index.cjs.map +1 -1
- package/dist/middleware/index.d.cts +3 -1
- package/dist/middleware/index.d.ts +3 -1
- package/dist/middleware/index.js +5 -3
- package/package.json +9 -3
- package/dist/chunk-GQITFXCV.js +0 -66
- package/dist/chunk-GQITFXCV.js.map +0 -1
|
@@ -25,6 +25,7 @@ __export(components_exports, {
|
|
|
25
25
|
JsonLd: () => JsonLd,
|
|
26
26
|
RouteProvider: () => RouteProvider,
|
|
27
27
|
RouteSetter: () => RouteSetter,
|
|
28
|
+
StageLogin: () => StageLogin,
|
|
28
29
|
gtmClick: () => gtmClick,
|
|
29
30
|
gtmFormSent: () => gtmFormSent,
|
|
30
31
|
gtmPageView: () => gtmPageView,
|
|
@@ -100,12 +101,104 @@ function gtmClick({ category, action, label }) {
|
|
|
100
101
|
label: cleanLabel[cleanLabel.length - 1]
|
|
101
102
|
});
|
|
102
103
|
}
|
|
104
|
+
|
|
105
|
+
// src/components/StageLogin.tsx
|
|
106
|
+
var import_react4 = require("react");
|
|
107
|
+
var import_navigation = require("next/navigation");
|
|
108
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
109
|
+
function OlmoLogo({ className }) {
|
|
110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
111
|
+
"svg",
|
|
112
|
+
{
|
|
113
|
+
role: "img",
|
|
114
|
+
"aria-label": "Olmo",
|
|
115
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
116
|
+
viewBox: "0 0 225 232",
|
|
117
|
+
className,
|
|
118
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M102.3,12.2c75-6.4,129.5,63.8,108.1,135.4-23.3,77.6-124.6,98.3-176.6,36.2C-18.2,121.7,19.1,19.2,102.4,12.2h-.1ZM87.4,202.3c35.6,9.9,73.6-2.3,95.6-32.1,37.4-50.9,12.4-125.6-49.4-140.8C59.5,11.2,1.3,86.9,32.6,154.9c7.7,16.8,23.8,34.9,41.6,40.8l5.5-20.1c-20-27-17.3-63.2,7.3-86.4,11-10.3,38.6-24.9,53.1-28.9s8.1-.9,10.4,3.2,6.5,23.1,7.4,28.4c4,22.6,2.1,44.6-13,62.8-13.1,15.8-31,22.5-50.8,25.5l-6.6,22.1h0ZM139.2,77c-33.7,10.7-72,38.9-54.1,79.1l11-20.1c4.1-4.6,12.6-23.1,17.7-24.7,6.3-2,10.9,3.5,8.7,9.7s-11.8,18.1-15.5,25.1-9,17.8-8.3,18.5c43-8.8,54.8-49.5,40.5-87.6h0Z" })
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
function StageLogin({
|
|
123
|
+
action,
|
|
124
|
+
title = "Olmo Staging access",
|
|
125
|
+
description = "This environment is restricted. Please sign in to continue.",
|
|
126
|
+
usernameLabel = "Username",
|
|
127
|
+
passwordLabel = "Password",
|
|
128
|
+
submitLabel = "Sign in",
|
|
129
|
+
invalidCredentialsMessage = "Invalid username or password.",
|
|
130
|
+
missingConfigMessage = "Stage authentication is not configured."
|
|
131
|
+
}) {
|
|
132
|
+
const params = (0, import_navigation.useSearchParams)();
|
|
133
|
+
const router = (0, import_navigation.useRouter)();
|
|
134
|
+
const from = params.get("from") ?? "/";
|
|
135
|
+
const [state, formAction, pending] = (0, import_react4.useActionState)(action, {});
|
|
136
|
+
(0, import_react4.useEffect)(() => {
|
|
137
|
+
if (state.redirectTo) router.replace(state.redirectTo);
|
|
138
|
+
}, [state.redirectTo, router]);
|
|
139
|
+
const errorMessage = state.error === "invalid_credentials" ? invalidCredentialsMessage : state.error === "missing_config" ? missingConfigMessage : null;
|
|
140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex min-h-full flex-col justify-center px-6 py-12 lg:px-8", children: [
|
|
141
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "sm:mx-auto sm:w-full sm:max-w-[384px]", children: [
|
|
142
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(OlmoLogo, { className: "mx-auto h-10 w-auto " }),
|
|
143
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "space-y-1", children: [
|
|
144
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { className: "text-xl text-center font-semibold text-neutral-900", children: title }),
|
|
145
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-sm text-center text-neutral-600", children: description })
|
|
146
|
+
] })
|
|
147
|
+
] }),
|
|
148
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-10 sm:mx-auto sm:w-full sm:max-w-[384px]", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { action: formAction, method: "POST", className: "space-y-6", children: [
|
|
149
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "hidden", name: "from", value: from }),
|
|
150
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
151
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { htmlFor: "username", className: "block text-sm/6 font-medium text-gray-900", children: usernameLabel }),
|
|
152
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
153
|
+
"input",
|
|
154
|
+
{
|
|
155
|
+
id: "username",
|
|
156
|
+
name: "username",
|
|
157
|
+
type: "username",
|
|
158
|
+
disabled: pending,
|
|
159
|
+
required: true,
|
|
160
|
+
autoComplete: "username",
|
|
161
|
+
className: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6"
|
|
162
|
+
}
|
|
163
|
+
) })
|
|
164
|
+
] }),
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { htmlFor: "password", className: "block text-sm/6 font-medium text-gray-900", children: passwordLabel }) }),
|
|
167
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
168
|
+
"input",
|
|
169
|
+
{
|
|
170
|
+
id: "password",
|
|
171
|
+
name: "password",
|
|
172
|
+
type: "password",
|
|
173
|
+
disabled: pending,
|
|
174
|
+
required: true,
|
|
175
|
+
autoComplete: "current-password",
|
|
176
|
+
className: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6"
|
|
177
|
+
}
|
|
178
|
+
) })
|
|
179
|
+
] }),
|
|
180
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
181
|
+
errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { role: "alert", className: "text-sm text-red-600", children: errorMessage }) : null,
|
|
182
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
183
|
+
"button",
|
|
184
|
+
{
|
|
185
|
+
type: "submit",
|
|
186
|
+
disabled: pending,
|
|
187
|
+
className: "cursor-pointer flex w-full justify-center rounded-md bg-black px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-black focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-black",
|
|
188
|
+
children: pending ? "\u2026" : submitLabel
|
|
189
|
+
}
|
|
190
|
+
)
|
|
191
|
+
] })
|
|
192
|
+
] }) })
|
|
193
|
+
] }) });
|
|
194
|
+
}
|
|
103
195
|
// Annotate the CommonJS export names for ESM import in node:
|
|
104
196
|
0 && (module.exports = {
|
|
105
197
|
GtmPage,
|
|
106
198
|
JsonLd,
|
|
107
199
|
RouteProvider,
|
|
108
200
|
RouteSetter,
|
|
201
|
+
StageLogin,
|
|
109
202
|
gtmClick,
|
|
110
203
|
gtmFormSent,
|
|
111
204
|
gtmPageView,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/index.ts","../../src/components/RouteContext.tsx","../../src/components/RouteSetter.tsx","../../src/components/JsonLd.tsx","../../src/components/GtmPage.tsx"],"sourcesContent":["export { RouteProvider, useRoute } from './RouteContext.js';\nexport { RouteSetter } from './RouteSetter.js';\nexport { JsonLd } from './JsonLd.js';\nexport { GtmPage, gtmPageView, gtmFormSent, gtmClick } from './GtmPage.js';\n","'use client';\n\nimport { createContext, useContext, useState } from 'react';\nimport type { ReactNode } from 'react';\n\ntype LocaleSlugs = Record<string, string>;\n\nconst RouteContext = createContext<{\n slugs: LocaleSlugs;\n setSlugs: (slugs: LocaleSlugs) => void;\n}>({ slugs: {}, setSlugs: () => {} });\n\nexport function RouteProvider({ children }: { children: ReactNode }) {\n const [slugs, setSlugs] = useState<LocaleSlugs>({});\n return (\n <RouteContext.Provider value={{ slugs, setSlugs }}>\n {children}\n </RouteContext.Provider>\n );\n}\n\nexport const useRoute = () => useContext(RouteContext);\n","'use client';\n\nimport { useEffect } from 'react';\nimport { useRoute } from './RouteContext.js';\n\nexport function RouteSetter({ slugs }: { slugs: Record<string, string> }) {\n const { setSlugs } = useRoute();\n\n useEffect(() => {\n const leafSlugs = Object.fromEntries(\n Object.entries(slugs).map(([locale, slug]) => [locale, slug.split('/').pop() ?? slug]),\n );\n setSlugs(leafSlugs);\n return () => setSlugs({});\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [JSON.stringify(slugs)]);\n\n return null;\n}\n","export function JsonLd({ schema }: { schema: object }) {\n return (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}\n />\n );\n}\n","'use client';\n\nimport { useEffect } from 'react';\n\ninterface GtmPageProps {\n slug: string | null;\n lang: string | null;\n name: string | null;\n template: string | null;\n}\n\ninterface GtmFormProps {\n data: object | null;\n name: string | null;\n}\n\ninterface GtmClickProps {\n category: string | null;\n action: string | null;\n label: string | null;\n}\n\ndeclare global {\n interface Window {\n dataLayer: any[];\n }\n}\n\nexport function GtmPage({ slug, lang, name, template }: GtmPageProps) {\n useEffect(() => {\n if (slug) {\n gtmPageView({\n page_name: name,\n page_category: (template as any)?.name,\n page_language: lang,\n path_clean: slug,\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [slug]);\n\n return <></>;\n}\n\nexport function gtmPageView(props: Record<string, any>) {\n return window.dataLayer?.push({ event: 'page_view', url: window.location.href, ...props });\n}\n\nexport function gtmFormSent({ data, name }: GtmFormProps) {\n return window.dataLayer?.push({ ...data, event: 'form_sent', form: name });\n}\n\nexport function gtmClick({ category, action, label }: GtmClickProps) {\n const cleanLabel = label?.split('/') ?? [];\n return window.dataLayer?.push({\n event: 'click',\n category,\n action,\n label: cleanLabel[cleanLabel.length - 1],\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAoD;AAahD;AARJ,IAAM,mBAAe,4BAGlB,EAAE,OAAO,CAAC,GAAG,UAAU,MAAM;AAAC,EAAE,CAAC;AAE7B,SAAS,cAAc,EAAE,SAAS,GAA4B;AACnE,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAsB,CAAC,CAAC;AAClD,SACE,4CAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,OAAO,SAAS,GAC7C,UACH;AAEJ;AAEO,IAAM,WAAW,UAAM,yBAAW,YAAY;;;ACnBrD,IAAAA,gBAA0B;AAGnB,SAAS,YAAY,EAAE,MAAM,GAAsC;AACxE,QAAM,EAAE,SAAS,IAAI,SAAS;AAE9B,+BAAU,MAAM;AACd,UAAM,YAAY,OAAO;AAAA,MACvB,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI,CAAC;AAAA,IACvF;AACA,aAAS,SAAS;AAClB,WAAO,MAAM,SAAS,CAAC,CAAC;AAAA,EAE1B,GAAG,CAAC,KAAK,UAAU,KAAK,CAAC,CAAC;AAE1B,SAAO;AACT;;;AChBI,IAAAC,sBAAA;AAFG,SAAS,OAAO,EAAE,OAAO,GAAuB;AACrD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,yBAAyB,EAAE,QAAQ,KAAK,UAAU,MAAM,EAAE;AAAA;AAAA,EAC5D;AAEJ;;;ACLA,IAAAC,gBAA0B;AAuCjB,IAAAC,sBAAA;AAbF,SAAS,QAAQ,EAAE,MAAM,MAAM,MAAM,SAAS,GAAiB;AACpE,+BAAU,MAAM;AACd,QAAI,MAAM;AACR,kBAAY;AAAA,QACV,WAAW;AAAA,QACX,eAAgB,UAAkB;AAAA,QAClC,eAAe;AAAA,QACf,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EAEF,GAAG,CAAC,IAAI,CAAC;AAET,SAAO,6EAAE;AACX;AAEO,SAAS,YAAY,OAA4B;AACtD,SAAO,OAAO,WAAW,KAAK,EAAE,OAAO,aAAa,KAAK,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC;AAC3F;AAEO,SAAS,YAAY,EAAE,MAAM,KAAK,GAAiB;AACxD,SAAO,OAAO,WAAW,KAAK,EAAE,GAAG,MAAM,OAAO,aAAa,MAAM,KAAK,CAAC;AAC3E;AAEO,SAAS,SAAS,EAAE,UAAU,QAAQ,MAAM,GAAkB;AACnE,QAAM,aAAa,OAAO,MAAM,GAAG,KAAK,CAAC;AACzC,SAAO,OAAO,WAAW,KAAK;AAAA,IAC5B,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,OAAO,WAAW,WAAW,SAAS,CAAC;AAAA,EACzC,CAAC;AACH;","names":["import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/index.ts","../../src/components/RouteContext.tsx","../../src/components/RouteSetter.tsx","../../src/components/JsonLd.tsx","../../src/components/GtmPage.tsx","../../src/components/StageLogin.tsx"],"sourcesContent":["export { RouteProvider, useRoute } from './RouteContext.js';\nexport { RouteSetter } from './RouteSetter.js';\nexport { JsonLd } from './JsonLd.js';\nexport { GtmPage, gtmPageView, gtmFormSent, gtmClick } from './GtmPage.js';\nexport { StageLogin } from './StageLogin.js';\nexport type { StageLoginProps } from './StageLogin.js';\n","'use client';\n\nimport { createContext, useContext, useState } from 'react';\nimport type { ReactNode } from 'react';\n\ntype LocaleSlugs = Record<string, string>;\n\nconst RouteContext = createContext<{\n slugs: LocaleSlugs;\n setSlugs: (slugs: LocaleSlugs) => void;\n}>({ slugs: {}, setSlugs: () => {} });\n\nexport function RouteProvider({ children }: { children: ReactNode }) {\n const [slugs, setSlugs] = useState<LocaleSlugs>({});\n return (\n <RouteContext.Provider value={{ slugs, setSlugs }}>\n {children}\n </RouteContext.Provider>\n );\n}\n\nexport const useRoute = () => useContext(RouteContext);\n","'use client';\n\nimport { useEffect } from 'react';\nimport { useRoute } from './RouteContext.js';\n\nexport function RouteSetter({ slugs }: { slugs: Record<string, string> }) {\n const { setSlugs } = useRoute();\n\n useEffect(() => {\n const leafSlugs = Object.fromEntries(\n Object.entries(slugs).map(([locale, slug]) => [locale, slug.split('/').pop() ?? slug]),\n );\n setSlugs(leafSlugs);\n return () => setSlugs({});\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [JSON.stringify(slugs)]);\n\n return null;\n}\n","export function JsonLd({ schema }: { schema: object }) {\n return (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}\n />\n );\n}\n","'use client';\n\nimport { useEffect } from 'react';\n\ninterface GtmPageProps {\n slug: string | null;\n lang: string | null;\n name: string | null;\n template: string | null;\n}\n\ninterface GtmFormProps {\n data: object | null;\n name: string | null;\n}\n\ninterface GtmClickProps {\n category: string | null;\n action: string | null;\n label: string | null;\n}\n\ndeclare global {\n interface Window {\n dataLayer: any[];\n }\n}\n\nexport function GtmPage({ slug, lang, name, template }: GtmPageProps) {\n useEffect(() => {\n if (slug) {\n gtmPageView({\n page_name: name,\n page_category: (template as any)?.name,\n page_language: lang,\n path_clean: slug,\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [slug]);\n\n return <></>;\n}\n\nexport function gtmPageView(props: Record<string, any>) {\n return window.dataLayer?.push({ event: 'page_view', url: window.location.href, ...props });\n}\n\nexport function gtmFormSent({ data, name }: GtmFormProps) {\n return window.dataLayer?.push({ ...data, event: 'form_sent', form: name });\n}\n\nexport function gtmClick({ category, action, label }: GtmClickProps) {\n const cleanLabel = label?.split('/') ?? [];\n return window.dataLayer?.push({\n event: 'click',\n category,\n action,\n label: cleanLabel[cleanLabel.length - 1],\n });\n}\n","import { useActionState, useEffect } from 'react';\nimport { useSearchParams, useRouter } from 'next/navigation';\n\nfunction OlmoLogo({ className }: { className?: string }) {\n return (\n <svg\n role=\"img\"\n aria-label=\"Olmo\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 225 232\"\n className={className}\n >\n <path d=\"M102.3,12.2c75-6.4,129.5,63.8,108.1,135.4-23.3,77.6-124.6,98.3-176.6,36.2C-18.2,121.7,19.1,19.2,102.4,12.2h-.1ZM87.4,202.3c35.6,9.9,73.6-2.3,95.6-32.1,37.4-50.9,12.4-125.6-49.4-140.8C59.5,11.2,1.3,86.9,32.6,154.9c7.7,16.8,23.8,34.9,41.6,40.8l5.5-20.1c-20-27-17.3-63.2,7.3-86.4,11-10.3,38.6-24.9,53.1-28.9s8.1-.9,10.4,3.2,6.5,23.1,7.4,28.4c4,22.6,2.1,44.6-13,62.8-13.1,15.8-31,22.5-50.8,25.5l-6.6,22.1h0ZM139.2,77c-33.7,10.7-72,38.9-54.1,79.1l11-20.1c4.1-4.6,12.6-23.1,17.7-24.7,6.3-2,10.9,3.5,8.7,9.7s-11.8,18.1-15.5,25.1-9,17.8-8.3,18.5c43-8.8,54.8-49.5,40.5-87.6h0Z\" />\n </svg>\n );\n}\n\ntype StageLoginState = {\n error?: 'missing_config' | 'invalid_credentials' | null;\n redirectTo?: string | null;\n};\n\ntype StageLoginAction = (prev: StageLoginState, formData: FormData) => Promise<StageLoginState>;\n\nexport type StageLoginProps = {\n action: StageLoginAction;\n title?: string;\n description?: string;\n usernameLabel?: string;\n passwordLabel?: string;\n submitLabel?: string;\n invalidCredentialsMessage?: string;\n missingConfigMessage?: string;\n};\n\nexport function StageLoginOLD({\n action,\n title = 'Staging access',\n description = 'This environment is restricted. Please sign in to continue.',\n usernameLabel = 'Username',\n passwordLabel = 'Password',\n submitLabel = 'Sign in',\n invalidCredentialsMessage = 'Invalid username or password.',\n missingConfigMessage = 'Stage authentication is not configured.',\n}: StageLoginProps) {\n const params = useSearchParams();\n const from = params.get('from') ?? '/';\n const [state, formAction, pending] = useActionState<StageLoginState, FormData>(action, {});\n\n const errorMessage =\n state.error === 'invalid_credentials'\n ? invalidCredentialsMessage\n : state.error === 'missing_config'\n ? missingConfigMessage\n : null;\n\n return (\n <main className=\"flex min-h-screen items-center justify-center bg-neutral-50 px-4 py-12\">\n <form\n action={formAction}\n className=\"relative w-full max-w-md space-y-5 rounded-lg border border-neutral-200 bg-white p-8 shadow-sm\"\n >\n <div className=\"w-full min-w-[200px]\">\n <header className=\"space-y-1 text-center\">\n <h1 className=\"text-xl font-semibold text-neutral-900\">{title}</h1>\n <p className=\"text-sm text-neutral-600\">{description}</p>\n </header>\n\n <input type=\"hidden\" name=\"from\" value={from} />\n\n <label className=\"block space-y-1\">\n <span className=\"text-sm font-medium text-neutral-800\">{usernameLabel}</span>\n <input\n name=\"username\"\n type=\"text\"\n autoComplete=\"username\"\n required\n disabled={pending}\n className=\"w-full rounded border border-neutral-300 px-3 py-2 text-sm outline-none focus:border-neutral-900\"\n />\n </label>\n\n <label className=\"block space-y-1\">\n <span className=\"text-sm font-medium text-neutral-800\">{passwordLabel}</span>\n <input\n name=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n required\n disabled={pending}\n className=\"w-full rounded border border-neutral-300 px-3 py-2 text-sm outline-none focus:border-neutral-900\"\n />\n </label>\n\n {errorMessage ? (\n <p role=\"alert\" className=\"text-sm text-red-600\">\n {errorMessage}\n </p>\n ) : null}\n\n <button\n type=\"submit\"\n disabled={pending}\n className=\"w-full rounded bg-neutral-900 px-4 py-2 text-sm font-medium text-white transition hover:bg-neutral-800 disabled:opacity-60\"\n >\n {pending ? '…' : submitLabel}\n </button>\n </div>\n </form>\n </main>\n );\n}\n\n\nexport function StageLogin({\n action,\n title = 'Olmo Staging access',\n description = 'This environment is restricted. Please sign in to continue.',\n usernameLabel = 'Username',\n passwordLabel = 'Password',\n submitLabel = 'Sign in',\n invalidCredentialsMessage = 'Invalid username or password.',\n missingConfigMessage = 'Stage authentication is not configured.', \n}: StageLoginProps) {\n \n const params = useSearchParams();\n const router = useRouter();\n const from = params.get('from') ?? '/';\n const [state, formAction, pending] = useActionState<StageLoginState, FormData>(action, {});\n\n // Once the action returns a redirect target the cookie is already in the\n // browser's jar (it shipped as Set-Cookie on the action response). Only\n // then do we navigate, so the next GET carries the session and middleware\n // doesn't bounce the user back to login.\n useEffect(() => {\n if (state.redirectTo) router.replace(state.redirectTo);\n }, [state.redirectTo, router]);\n\n const errorMessage =\n state.error === 'invalid_credentials'\n ? invalidCredentialsMessage\n : state.error === 'missing_config'\n ? missingConfigMessage\n : null;\n\n return (\n <>\n <div className=\"flex min-h-full flex-col justify-center px-6 py-12 lg:px-8\">\n <div className=\"sm:mx-auto sm:w-full sm:max-w-[384px]\">\n <OlmoLogo className=\"mx-auto h-10 w-auto \" />\n {/* <h2 className=\"mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900\">\n Sign in to your account\n </h2> */}\n <header className=\"space-y-1\">\n <h1 className=\"text-xl text-center font-semibold text-neutral-900\">{title}</h1>\n <p className=\"text-sm text-center text-neutral-600\">{description}</p>\n </header> \n </div>\n\n <div className=\"mt-10 sm:mx-auto sm:w-full sm:max-w-[384px]\">\n <form action={formAction} method=\"POST\" className=\"space-y-6\">\n <input type=\"hidden\" name=\"from\" value={from} />\n <div>\n <label htmlFor=\"username\" className=\"block text-sm/6 font-medium text-gray-900\">\n {usernameLabel}\n </label>\n <div className=\"mt-2\">\n <input\n id=\"username\"\n name=\"username\"\n type=\"username\"\n disabled={pending}\n required\n autoComplete=\"username\"\n className=\"block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6\"\n />\n </div>\n </div>\n\n <div>\n <div className=\"flex items-center justify-between\">\n <label htmlFor=\"password\" className=\"block text-sm/6 font-medium text-gray-900\">\n {passwordLabel}\n </label>\n </div>\n <div className=\"mt-2\">\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n disabled={pending}\n required\n autoComplete=\"current-password\"\n className=\"block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6\"\n />\n </div>\n </div>\n\n <div>\n {errorMessage ? (\n <p role=\"alert\" className=\"text-sm text-red-600\">\n {errorMessage}\n </p>\n ) : null} \n <button\n type=\"submit\"\n disabled={pending}\n className=\"cursor-pointer flex w-full justify-center rounded-md bg-black px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-black focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-black\"\n >\n {pending ? '…' : submitLabel}\n </button>\n </div>\n </form>\n\n </div>\n </div>\n </>\n )\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
|
@@ -43,4 +43,21 @@ declare function gtmPageView(props: Record<string, any>): number;
|
|
|
43
43
|
declare function gtmFormSent({ data, name }: GtmFormProps): number;
|
|
44
44
|
declare function gtmClick({ category, action, label }: GtmClickProps): number;
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
type StageLoginState = {
|
|
47
|
+
error?: 'missing_config' | 'invalid_credentials' | null;
|
|
48
|
+
redirectTo?: string | null;
|
|
49
|
+
};
|
|
50
|
+
type StageLoginAction = (prev: StageLoginState, formData: FormData) => Promise<StageLoginState>;
|
|
51
|
+
type StageLoginProps = {
|
|
52
|
+
action: StageLoginAction;
|
|
53
|
+
title?: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
usernameLabel?: string;
|
|
56
|
+
passwordLabel?: string;
|
|
57
|
+
submitLabel?: string;
|
|
58
|
+
invalidCredentialsMessage?: string;
|
|
59
|
+
missingConfigMessage?: string;
|
|
60
|
+
};
|
|
61
|
+
declare function StageLogin({ action, title, description, usernameLabel, passwordLabel, submitLabel, invalidCredentialsMessage, missingConfigMessage, }: StageLoginProps): react_jsx_runtime.JSX.Element;
|
|
62
|
+
|
|
63
|
+
export { GtmPage, JsonLd, RouteProvider, RouteSetter, StageLogin, type StageLoginProps, gtmClick, gtmFormSent, gtmPageView, useRoute };
|
|
@@ -43,4 +43,21 @@ declare function gtmPageView(props: Record<string, any>): number;
|
|
|
43
43
|
declare function gtmFormSent({ data, name }: GtmFormProps): number;
|
|
44
44
|
declare function gtmClick({ category, action, label }: GtmClickProps): number;
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
type StageLoginState = {
|
|
47
|
+
error?: 'missing_config' | 'invalid_credentials' | null;
|
|
48
|
+
redirectTo?: string | null;
|
|
49
|
+
};
|
|
50
|
+
type StageLoginAction = (prev: StageLoginState, formData: FormData) => Promise<StageLoginState>;
|
|
51
|
+
type StageLoginProps = {
|
|
52
|
+
action: StageLoginAction;
|
|
53
|
+
title?: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
usernameLabel?: string;
|
|
56
|
+
passwordLabel?: string;
|
|
57
|
+
submitLabel?: string;
|
|
58
|
+
invalidCredentialsMessage?: string;
|
|
59
|
+
missingConfigMessage?: string;
|
|
60
|
+
};
|
|
61
|
+
declare function StageLogin({ action, title, description, usernameLabel, passwordLabel, submitLabel, invalidCredentialsMessage, missingConfigMessage, }: StageLoginProps): react_jsx_runtime.JSX.Element;
|
|
62
|
+
|
|
63
|
+
export { GtmPage, JsonLd, RouteProvider, RouteSetter, StageLogin, type StageLoginProps, gtmClick, gtmFormSent, gtmPageView, useRoute };
|
package/dist/components/index.js
CHANGED
|
@@ -68,11 +68,103 @@ function gtmClick({ category, action, label }) {
|
|
|
68
68
|
label: cleanLabel[cleanLabel.length - 1]
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
// src/components/StageLogin.tsx
|
|
73
|
+
import { useActionState, useEffect as useEffect3 } from "react";
|
|
74
|
+
import { useSearchParams, useRouter } from "next/navigation";
|
|
75
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
76
|
+
function OlmoLogo({ className }) {
|
|
77
|
+
return /* @__PURE__ */ jsx4(
|
|
78
|
+
"svg",
|
|
79
|
+
{
|
|
80
|
+
role: "img",
|
|
81
|
+
"aria-label": "Olmo",
|
|
82
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
83
|
+
viewBox: "0 0 225 232",
|
|
84
|
+
className,
|
|
85
|
+
children: /* @__PURE__ */ jsx4("path", { d: "M102.3,12.2c75-6.4,129.5,63.8,108.1,135.4-23.3,77.6-124.6,98.3-176.6,36.2C-18.2,121.7,19.1,19.2,102.4,12.2h-.1ZM87.4,202.3c35.6,9.9,73.6-2.3,95.6-32.1,37.4-50.9,12.4-125.6-49.4-140.8C59.5,11.2,1.3,86.9,32.6,154.9c7.7,16.8,23.8,34.9,41.6,40.8l5.5-20.1c-20-27-17.3-63.2,7.3-86.4,11-10.3,38.6-24.9,53.1-28.9s8.1-.9,10.4,3.2,6.5,23.1,7.4,28.4c4,22.6,2.1,44.6-13,62.8-13.1,15.8-31,22.5-50.8,25.5l-6.6,22.1h0ZM139.2,77c-33.7,10.7-72,38.9-54.1,79.1l11-20.1c4.1-4.6,12.6-23.1,17.7-24.7,6.3-2,10.9,3.5,8.7,9.7s-11.8,18.1-15.5,25.1-9,17.8-8.3,18.5c43-8.8,54.8-49.5,40.5-87.6h0Z" })
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
function StageLogin({
|
|
90
|
+
action,
|
|
91
|
+
title = "Olmo Staging access",
|
|
92
|
+
description = "This environment is restricted. Please sign in to continue.",
|
|
93
|
+
usernameLabel = "Username",
|
|
94
|
+
passwordLabel = "Password",
|
|
95
|
+
submitLabel = "Sign in",
|
|
96
|
+
invalidCredentialsMessage = "Invalid username or password.",
|
|
97
|
+
missingConfigMessage = "Stage authentication is not configured."
|
|
98
|
+
}) {
|
|
99
|
+
const params = useSearchParams();
|
|
100
|
+
const router = useRouter();
|
|
101
|
+
const from = params.get("from") ?? "/";
|
|
102
|
+
const [state, formAction, pending] = useActionState(action, {});
|
|
103
|
+
useEffect3(() => {
|
|
104
|
+
if (state.redirectTo) router.replace(state.redirectTo);
|
|
105
|
+
}, [state.redirectTo, router]);
|
|
106
|
+
const errorMessage = state.error === "invalid_credentials" ? invalidCredentialsMessage : state.error === "missing_config" ? missingConfigMessage : null;
|
|
107
|
+
return /* @__PURE__ */ jsx4(Fragment2, { children: /* @__PURE__ */ jsxs("div", { className: "flex min-h-full flex-col justify-center px-6 py-12 lg:px-8", children: [
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { className: "sm:mx-auto sm:w-full sm:max-w-[384px]", children: [
|
|
109
|
+
/* @__PURE__ */ jsx4(OlmoLogo, { className: "mx-auto h-10 w-auto " }),
|
|
110
|
+
/* @__PURE__ */ jsxs("header", { className: "space-y-1", children: [
|
|
111
|
+
/* @__PURE__ */ jsx4("h1", { className: "text-xl text-center font-semibold text-neutral-900", children: title }),
|
|
112
|
+
/* @__PURE__ */ jsx4("p", { className: "text-sm text-center text-neutral-600", children: description })
|
|
113
|
+
] })
|
|
114
|
+
] }),
|
|
115
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-10 sm:mx-auto sm:w-full sm:max-w-[384px]", children: /* @__PURE__ */ jsxs("form", { action: formAction, method: "POST", className: "space-y-6", children: [
|
|
116
|
+
/* @__PURE__ */ jsx4("input", { type: "hidden", name: "from", value: from }),
|
|
117
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
118
|
+
/* @__PURE__ */ jsx4("label", { htmlFor: "username", className: "block text-sm/6 font-medium text-gray-900", children: usernameLabel }),
|
|
119
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-2", children: /* @__PURE__ */ jsx4(
|
|
120
|
+
"input",
|
|
121
|
+
{
|
|
122
|
+
id: "username",
|
|
123
|
+
name: "username",
|
|
124
|
+
type: "username",
|
|
125
|
+
disabled: pending,
|
|
126
|
+
required: true,
|
|
127
|
+
autoComplete: "username",
|
|
128
|
+
className: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6"
|
|
129
|
+
}
|
|
130
|
+
) })
|
|
131
|
+
] }),
|
|
132
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
133
|
+
/* @__PURE__ */ jsx4("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx4("label", { htmlFor: "password", className: "block text-sm/6 font-medium text-gray-900", children: passwordLabel }) }),
|
|
134
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-2", children: /* @__PURE__ */ jsx4(
|
|
135
|
+
"input",
|
|
136
|
+
{
|
|
137
|
+
id: "password",
|
|
138
|
+
name: "password",
|
|
139
|
+
type: "password",
|
|
140
|
+
disabled: pending,
|
|
141
|
+
required: true,
|
|
142
|
+
autoComplete: "current-password",
|
|
143
|
+
className: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6"
|
|
144
|
+
}
|
|
145
|
+
) })
|
|
146
|
+
] }),
|
|
147
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
148
|
+
errorMessage ? /* @__PURE__ */ jsx4("p", { role: "alert", className: "text-sm text-red-600", children: errorMessage }) : null,
|
|
149
|
+
/* @__PURE__ */ jsx4(
|
|
150
|
+
"button",
|
|
151
|
+
{
|
|
152
|
+
type: "submit",
|
|
153
|
+
disabled: pending,
|
|
154
|
+
className: "cursor-pointer flex w-full justify-center rounded-md bg-black px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-black focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-black",
|
|
155
|
+
children: pending ? "\u2026" : submitLabel
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
] })
|
|
159
|
+
] }) })
|
|
160
|
+
] }) });
|
|
161
|
+
}
|
|
71
162
|
export {
|
|
72
163
|
GtmPage,
|
|
73
164
|
JsonLd,
|
|
74
165
|
RouteProvider,
|
|
75
166
|
RouteSetter,
|
|
167
|
+
StageLogin,
|
|
76
168
|
gtmClick,
|
|
77
169
|
gtmFormSent,
|
|
78
170
|
gtmPageView,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/RouteContext.tsx","../../src/components/RouteSetter.tsx","../../src/components/JsonLd.tsx","../../src/components/GtmPage.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, useContext, useState } from 'react';\nimport type { ReactNode } from 'react';\n\ntype LocaleSlugs = Record<string, string>;\n\nconst RouteContext = createContext<{\n slugs: LocaleSlugs;\n setSlugs: (slugs: LocaleSlugs) => void;\n}>({ slugs: {}, setSlugs: () => {} });\n\nexport function RouteProvider({ children }: { children: ReactNode }) {\n const [slugs, setSlugs] = useState<LocaleSlugs>({});\n return (\n <RouteContext.Provider value={{ slugs, setSlugs }}>\n {children}\n </RouteContext.Provider>\n );\n}\n\nexport const useRoute = () => useContext(RouteContext);\n","'use client';\n\nimport { useEffect } from 'react';\nimport { useRoute } from './RouteContext.js';\n\nexport function RouteSetter({ slugs }: { slugs: Record<string, string> }) {\n const { setSlugs } = useRoute();\n\n useEffect(() => {\n const leafSlugs = Object.fromEntries(\n Object.entries(slugs).map(([locale, slug]) => [locale, slug.split('/').pop() ?? slug]),\n );\n setSlugs(leafSlugs);\n return () => setSlugs({});\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [JSON.stringify(slugs)]);\n\n return null;\n}\n","export function JsonLd({ schema }: { schema: object }) {\n return (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}\n />\n );\n}\n","'use client';\n\nimport { useEffect } from 'react';\n\ninterface GtmPageProps {\n slug: string | null;\n lang: string | null;\n name: string | null;\n template: string | null;\n}\n\ninterface GtmFormProps {\n data: object | null;\n name: string | null;\n}\n\ninterface GtmClickProps {\n category: string | null;\n action: string | null;\n label: string | null;\n}\n\ndeclare global {\n interface Window {\n dataLayer: any[];\n }\n}\n\nexport function GtmPage({ slug, lang, name, template }: GtmPageProps) {\n useEffect(() => {\n if (slug) {\n gtmPageView({\n page_name: name,\n page_category: (template as any)?.name,\n page_language: lang,\n path_clean: slug,\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [slug]);\n\n return <></>;\n}\n\nexport function gtmPageView(props: Record<string, any>) {\n return window.dataLayer?.push({ event: 'page_view', url: window.location.href, ...props });\n}\n\nexport function gtmFormSent({ data, name }: GtmFormProps) {\n return window.dataLayer?.push({ ...data, event: 'form_sent', form: name });\n}\n\nexport function gtmClick({ category, action, label }: GtmClickProps) {\n const cleanLabel = label?.split('/') ?? [];\n return window.dataLayer?.push({\n event: 'click',\n category,\n action,\n label: cleanLabel[cleanLabel.length - 1],\n });\n}\n"],"mappings":";;;AAEA,SAAS,eAAe,YAAY,gBAAgB;AAahD;AARJ,IAAM,eAAe,cAGlB,EAAE,OAAO,CAAC,GAAG,UAAU,MAAM;AAAC,EAAE,CAAC;AAE7B,SAAS,cAAc,EAAE,SAAS,GAA4B;AACnE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAsB,CAAC,CAAC;AAClD,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,OAAO,SAAS,GAC7C,UACH;AAEJ;AAEO,IAAM,WAAW,MAAM,WAAW,YAAY;;;ACnBrD,SAAS,iBAAiB;AAGnB,SAAS,YAAY,EAAE,MAAM,GAAsC;AACxE,QAAM,EAAE,SAAS,IAAI,SAAS;AAE9B,YAAU,MAAM;AACd,UAAM,YAAY,OAAO;AAAA,MACvB,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI,CAAC;AAAA,IACvF;AACA,aAAS,SAAS;AAClB,WAAO,MAAM,SAAS,CAAC,CAAC;AAAA,EAE1B,GAAG,CAAC,KAAK,UAAU,KAAK,CAAC,CAAC;AAE1B,SAAO;AACT;;;AChBI,gBAAAA,YAAA;AAFG,SAAS,OAAO,EAAE,OAAO,GAAuB;AACrD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,yBAAyB,EAAE,QAAQ,KAAK,UAAU,MAAM,EAAE;AAAA;AAAA,EAC5D;AAEJ;;;ACLA,SAAS,aAAAC,kBAAiB;AAuCjB,0BAAAC,YAAA;AAbF,SAAS,QAAQ,EAAE,MAAM,MAAM,MAAM,SAAS,GAAiB;AACpE,EAAAD,WAAU,MAAM;AACd,QAAI,MAAM;AACR,kBAAY;AAAA,QACV,WAAW;AAAA,QACX,eAAgB,UAAkB;AAAA,QAClC,eAAe;AAAA,QACf,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EAEF,GAAG,CAAC,IAAI,CAAC;AAET,SAAO,gBAAAC,KAAA,YAAE;AACX;AAEO,SAAS,YAAY,OAA4B;AACtD,SAAO,OAAO,WAAW,KAAK,EAAE,OAAO,aAAa,KAAK,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC;AAC3F;AAEO,SAAS,YAAY,EAAE,MAAM,KAAK,GAAiB;AACxD,SAAO,OAAO,WAAW,KAAK,EAAE,GAAG,MAAM,OAAO,aAAa,MAAM,KAAK,CAAC;AAC3E;AAEO,SAAS,SAAS,EAAE,UAAU,QAAQ,MAAM,GAAkB;AACnE,QAAM,aAAa,OAAO,MAAM,GAAG,KAAK,CAAC;AACzC,SAAO,OAAO,WAAW,KAAK;AAAA,IAC5B,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,OAAO,WAAW,WAAW,SAAS,CAAC;AAAA,EACzC,CAAC;AACH;","names":["jsx","useEffect","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/RouteContext.tsx","../../src/components/RouteSetter.tsx","../../src/components/JsonLd.tsx","../../src/components/GtmPage.tsx","../../src/components/StageLogin.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, useContext, useState } from 'react';\nimport type { ReactNode } from 'react';\n\ntype LocaleSlugs = Record<string, string>;\n\nconst RouteContext = createContext<{\n slugs: LocaleSlugs;\n setSlugs: (slugs: LocaleSlugs) => void;\n}>({ slugs: {}, setSlugs: () => {} });\n\nexport function RouteProvider({ children }: { children: ReactNode }) {\n const [slugs, setSlugs] = useState<LocaleSlugs>({});\n return (\n <RouteContext.Provider value={{ slugs, setSlugs }}>\n {children}\n </RouteContext.Provider>\n );\n}\n\nexport const useRoute = () => useContext(RouteContext);\n","'use client';\n\nimport { useEffect } from 'react';\nimport { useRoute } from './RouteContext.js';\n\nexport function RouteSetter({ slugs }: { slugs: Record<string, string> }) {\n const { setSlugs } = useRoute();\n\n useEffect(() => {\n const leafSlugs = Object.fromEntries(\n Object.entries(slugs).map(([locale, slug]) => [locale, slug.split('/').pop() ?? slug]),\n );\n setSlugs(leafSlugs);\n return () => setSlugs({});\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [JSON.stringify(slugs)]);\n\n return null;\n}\n","export function JsonLd({ schema }: { schema: object }) {\n return (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}\n />\n );\n}\n","'use client';\n\nimport { useEffect } from 'react';\n\ninterface GtmPageProps {\n slug: string | null;\n lang: string | null;\n name: string | null;\n template: string | null;\n}\n\ninterface GtmFormProps {\n data: object | null;\n name: string | null;\n}\n\ninterface GtmClickProps {\n category: string | null;\n action: string | null;\n label: string | null;\n}\n\ndeclare global {\n interface Window {\n dataLayer: any[];\n }\n}\n\nexport function GtmPage({ slug, lang, name, template }: GtmPageProps) {\n useEffect(() => {\n if (slug) {\n gtmPageView({\n page_name: name,\n page_category: (template as any)?.name,\n page_language: lang,\n path_clean: slug,\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [slug]);\n\n return <></>;\n}\n\nexport function gtmPageView(props: Record<string, any>) {\n return window.dataLayer?.push({ event: 'page_view', url: window.location.href, ...props });\n}\n\nexport function gtmFormSent({ data, name }: GtmFormProps) {\n return window.dataLayer?.push({ ...data, event: 'form_sent', form: name });\n}\n\nexport function gtmClick({ category, action, label }: GtmClickProps) {\n const cleanLabel = label?.split('/') ?? [];\n return window.dataLayer?.push({\n event: 'click',\n category,\n action,\n label: cleanLabel[cleanLabel.length - 1],\n });\n}\n","import { useActionState, useEffect } from 'react';\nimport { useSearchParams, useRouter } from 'next/navigation';\n\nfunction OlmoLogo({ className }: { className?: string }) {\n return (\n <svg\n role=\"img\"\n aria-label=\"Olmo\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 225 232\"\n className={className}\n >\n <path d=\"M102.3,12.2c75-6.4,129.5,63.8,108.1,135.4-23.3,77.6-124.6,98.3-176.6,36.2C-18.2,121.7,19.1,19.2,102.4,12.2h-.1ZM87.4,202.3c35.6,9.9,73.6-2.3,95.6-32.1,37.4-50.9,12.4-125.6-49.4-140.8C59.5,11.2,1.3,86.9,32.6,154.9c7.7,16.8,23.8,34.9,41.6,40.8l5.5-20.1c-20-27-17.3-63.2,7.3-86.4,11-10.3,38.6-24.9,53.1-28.9s8.1-.9,10.4,3.2,6.5,23.1,7.4,28.4c4,22.6,2.1,44.6-13,62.8-13.1,15.8-31,22.5-50.8,25.5l-6.6,22.1h0ZM139.2,77c-33.7,10.7-72,38.9-54.1,79.1l11-20.1c4.1-4.6,12.6-23.1,17.7-24.7,6.3-2,10.9,3.5,8.7,9.7s-11.8,18.1-15.5,25.1-9,17.8-8.3,18.5c43-8.8,54.8-49.5,40.5-87.6h0Z\" />\n </svg>\n );\n}\n\ntype StageLoginState = {\n error?: 'missing_config' | 'invalid_credentials' | null;\n redirectTo?: string | null;\n};\n\ntype StageLoginAction = (prev: StageLoginState, formData: FormData) => Promise<StageLoginState>;\n\nexport type StageLoginProps = {\n action: StageLoginAction;\n title?: string;\n description?: string;\n usernameLabel?: string;\n passwordLabel?: string;\n submitLabel?: string;\n invalidCredentialsMessage?: string;\n missingConfigMessage?: string;\n};\n\nexport function StageLoginOLD({\n action,\n title = 'Staging access',\n description = 'This environment is restricted. Please sign in to continue.',\n usernameLabel = 'Username',\n passwordLabel = 'Password',\n submitLabel = 'Sign in',\n invalidCredentialsMessage = 'Invalid username or password.',\n missingConfigMessage = 'Stage authentication is not configured.',\n}: StageLoginProps) {\n const params = useSearchParams();\n const from = params.get('from') ?? '/';\n const [state, formAction, pending] = useActionState<StageLoginState, FormData>(action, {});\n\n const errorMessage =\n state.error === 'invalid_credentials'\n ? invalidCredentialsMessage\n : state.error === 'missing_config'\n ? missingConfigMessage\n : null;\n\n return (\n <main className=\"flex min-h-screen items-center justify-center bg-neutral-50 px-4 py-12\">\n <form\n action={formAction}\n className=\"relative w-full max-w-md space-y-5 rounded-lg border border-neutral-200 bg-white p-8 shadow-sm\"\n >\n <div className=\"w-full min-w-[200px]\">\n <header className=\"space-y-1 text-center\">\n <h1 className=\"text-xl font-semibold text-neutral-900\">{title}</h1>\n <p className=\"text-sm text-neutral-600\">{description}</p>\n </header>\n\n <input type=\"hidden\" name=\"from\" value={from} />\n\n <label className=\"block space-y-1\">\n <span className=\"text-sm font-medium text-neutral-800\">{usernameLabel}</span>\n <input\n name=\"username\"\n type=\"text\"\n autoComplete=\"username\"\n required\n disabled={pending}\n className=\"w-full rounded border border-neutral-300 px-3 py-2 text-sm outline-none focus:border-neutral-900\"\n />\n </label>\n\n <label className=\"block space-y-1\">\n <span className=\"text-sm font-medium text-neutral-800\">{passwordLabel}</span>\n <input\n name=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n required\n disabled={pending}\n className=\"w-full rounded border border-neutral-300 px-3 py-2 text-sm outline-none focus:border-neutral-900\"\n />\n </label>\n\n {errorMessage ? (\n <p role=\"alert\" className=\"text-sm text-red-600\">\n {errorMessage}\n </p>\n ) : null}\n\n <button\n type=\"submit\"\n disabled={pending}\n className=\"w-full rounded bg-neutral-900 px-4 py-2 text-sm font-medium text-white transition hover:bg-neutral-800 disabled:opacity-60\"\n >\n {pending ? '…' : submitLabel}\n </button>\n </div>\n </form>\n </main>\n );\n}\n\n\nexport function StageLogin({\n action,\n title = 'Olmo Staging access',\n description = 'This environment is restricted. Please sign in to continue.',\n usernameLabel = 'Username',\n passwordLabel = 'Password',\n submitLabel = 'Sign in',\n invalidCredentialsMessage = 'Invalid username or password.',\n missingConfigMessage = 'Stage authentication is not configured.', \n}: StageLoginProps) {\n \n const params = useSearchParams();\n const router = useRouter();\n const from = params.get('from') ?? '/';\n const [state, formAction, pending] = useActionState<StageLoginState, FormData>(action, {});\n\n // Once the action returns a redirect target the cookie is already in the\n // browser's jar (it shipped as Set-Cookie on the action response). Only\n // then do we navigate, so the next GET carries the session and middleware\n // doesn't bounce the user back to login.\n useEffect(() => {\n if (state.redirectTo) router.replace(state.redirectTo);\n }, [state.redirectTo, router]);\n\n const errorMessage =\n state.error === 'invalid_credentials'\n ? invalidCredentialsMessage\n : state.error === 'missing_config'\n ? missingConfigMessage\n : null;\n\n return (\n <>\n <div className=\"flex min-h-full flex-col justify-center px-6 py-12 lg:px-8\">\n <div className=\"sm:mx-auto sm:w-full sm:max-w-[384px]\">\n <OlmoLogo className=\"mx-auto h-10 w-auto \" />\n {/* <h2 className=\"mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900\">\n Sign in to your account\n </h2> */}\n <header className=\"space-y-1\">\n <h1 className=\"text-xl text-center font-semibold text-neutral-900\">{title}</h1>\n <p className=\"text-sm text-center text-neutral-600\">{description}</p>\n </header> \n </div>\n\n <div className=\"mt-10 sm:mx-auto sm:w-full sm:max-w-[384px]\">\n <form action={formAction} method=\"POST\" className=\"space-y-6\">\n <input type=\"hidden\" name=\"from\" value={from} />\n <div>\n <label htmlFor=\"username\" className=\"block text-sm/6 font-medium text-gray-900\">\n {usernameLabel}\n </label>\n <div className=\"mt-2\">\n <input\n id=\"username\"\n name=\"username\"\n type=\"username\"\n disabled={pending}\n required\n autoComplete=\"username\"\n className=\"block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6\"\n />\n </div>\n </div>\n\n <div>\n <div className=\"flex items-center justify-between\">\n <label htmlFor=\"password\" className=\"block text-sm/6 font-medium text-gray-900\">\n {passwordLabel}\n </label>\n </div>\n <div className=\"mt-2\">\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n disabled={pending}\n required\n autoComplete=\"current-password\"\n className=\"block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6\"\n />\n </div>\n </div>\n\n <div>\n {errorMessage ? (\n <p role=\"alert\" className=\"text-sm text-red-600\">\n {errorMessage}\n </p>\n ) : null} \n <button\n type=\"submit\"\n disabled={pending}\n className=\"cursor-pointer flex w-full justify-center rounded-md bg-black px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-black focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-black\"\n >\n {pending ? '…' : submitLabel}\n </button>\n </div>\n </form>\n\n </div>\n </div>\n </>\n )\n}\n"],"mappings":"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","names":["jsx","useEffect","jsx","useEffect","Fragment","jsx","useEffect","jsx","Fragment"]}
|
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(src_exports, {
|
|
|
24
24
|
JsonLd: () => JsonLd,
|
|
25
25
|
RouteProvider: () => RouteProvider,
|
|
26
26
|
RouteSetter: () => RouteSetter,
|
|
27
|
+
StageLogin: () => StageLogin,
|
|
27
28
|
buildArticle: () => buildArticle,
|
|
28
29
|
buildBreadcrumb: () => buildBreadcrumb,
|
|
29
30
|
buildItemList: () => buildItemList,
|
|
@@ -38,6 +39,7 @@ __export(src_exports, {
|
|
|
38
39
|
posting: () => posting,
|
|
39
40
|
redirectmiddleware: () => redirectmiddleware,
|
|
40
41
|
setSeoData: () => setSeoData,
|
|
42
|
+
stagegatemiddleware: () => stagegatemiddleware,
|
|
41
43
|
useRoute: () => useRoute
|
|
42
44
|
});
|
|
43
45
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -277,6 +279,108 @@ var redirectmiddleware = (next) => {
|
|
|
277
279
|
};
|
|
278
280
|
};
|
|
279
281
|
|
|
282
|
+
// src/middleware/stagegatemiddleware.ts
|
|
283
|
+
var import_server4 = require("next/server");
|
|
284
|
+
|
|
285
|
+
// src/auth/stage.ts
|
|
286
|
+
var COOKIE_NAME = "olmo_stage_auth";
|
|
287
|
+
var DEFAULT_SESSION_DAYS = 7;
|
|
288
|
+
function readStageEnv() {
|
|
289
|
+
const username = process.env.OLMO_STAGE_USERNAME;
|
|
290
|
+
const password = process.env.OLMO_STAGE_PASSWORD;
|
|
291
|
+
const secret = process.env.OLMO_STAGE_SECRET;
|
|
292
|
+
if (!username || !password || !secret) return null;
|
|
293
|
+
const days = Number(process.env.OLMO_STAGE_SESSION_DAYS);
|
|
294
|
+
return {
|
|
295
|
+
username,
|
|
296
|
+
password,
|
|
297
|
+
secret,
|
|
298
|
+
sessionDays: Number.isFinite(days) && days > 0 ? days : DEFAULT_SESSION_DAYS
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function getStageCookieName() {
|
|
302
|
+
return COOKIE_NAME;
|
|
303
|
+
}
|
|
304
|
+
function fromBase64Url(input) {
|
|
305
|
+
const pad = input.length % 4 === 0 ? "" : "=".repeat(4 - input.length % 4);
|
|
306
|
+
const b64 = input.replace(/-/g, "+").replace(/_/g, "/") + pad;
|
|
307
|
+
const bin = atob(b64);
|
|
308
|
+
const out = new Uint8Array(bin.length);
|
|
309
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
310
|
+
return out;
|
|
311
|
+
}
|
|
312
|
+
async function importKey(secret) {
|
|
313
|
+
return crypto.subtle.importKey(
|
|
314
|
+
"raw",
|
|
315
|
+
new TextEncoder().encode(secret),
|
|
316
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
317
|
+
false,
|
|
318
|
+
["sign", "verify"]
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
async function verifySession(token, secret) {
|
|
322
|
+
if (!token || typeof token !== "string" || token.indexOf(".") === -1) return null;
|
|
323
|
+
const [body, sig] = token.split(".");
|
|
324
|
+
if (!body || !sig) return null;
|
|
325
|
+
let key;
|
|
326
|
+
try {
|
|
327
|
+
key = await importKey(secret);
|
|
328
|
+
} catch {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
let valid = false;
|
|
332
|
+
try {
|
|
333
|
+
valid = await crypto.subtle.verify("HMAC", key, fromBase64Url(sig), new TextEncoder().encode(body));
|
|
334
|
+
} catch {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
if (!valid) return null;
|
|
338
|
+
let payload;
|
|
339
|
+
try {
|
|
340
|
+
payload = JSON.parse(new TextDecoder().decode(fromBase64Url(body)));
|
|
341
|
+
} catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
if (!payload || typeof payload.exp !== "number" || payload.exp < Date.now()) return null;
|
|
345
|
+
return payload;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// src/middleware/stagegatemiddleware.ts
|
|
349
|
+
var LOGIN_PATH = "/olmo-stage-login/";
|
|
350
|
+
var NOINDEX = "noindex, nofollow, noarchive";
|
|
351
|
+
function withNoindex(res) {
|
|
352
|
+
res.headers.set("X-Robots-Tag", NOINDEX);
|
|
353
|
+
return res;
|
|
354
|
+
}
|
|
355
|
+
var stagegatemiddleware = (next) => {
|
|
356
|
+
return async (request, _next) => {
|
|
357
|
+
if (process.env.NEXT_PUBLIC_ENV !== "stage") {
|
|
358
|
+
return next(request, _next);
|
|
359
|
+
}
|
|
360
|
+
const { pathname, search } = request.nextUrl;
|
|
361
|
+
if (pathname === LOGIN_PATH) {
|
|
362
|
+
return withNoindex(import_server4.NextResponse.next());
|
|
363
|
+
}
|
|
364
|
+
const env = readStageEnv();
|
|
365
|
+
if (!env) {
|
|
366
|
+
const url2 = request.nextUrl.clone();
|
|
367
|
+
url2.pathname = LOGIN_PATH;
|
|
368
|
+
url2.search = "";
|
|
369
|
+
return withNoindex(import_server4.NextResponse.redirect(url2, { status: 307 }));
|
|
370
|
+
}
|
|
371
|
+
const token = request.cookies.get(getStageCookieName())?.value;
|
|
372
|
+
const session = await verifySession(token, env.secret);
|
|
373
|
+
if (session) {
|
|
374
|
+
const res = await next(request, _next);
|
|
375
|
+
return withNoindex(res instanceof import_server4.NextResponse ? res : import_server4.NextResponse.next());
|
|
376
|
+
}
|
|
377
|
+
const url = request.nextUrl.clone();
|
|
378
|
+
url.pathname = LOGIN_PATH;
|
|
379
|
+
url.search = `?from=${encodeURIComponent(pathname + search)}`;
|
|
380
|
+
return withNoindex(import_server4.NextResponse.redirect(url, { status: 307 }));
|
|
381
|
+
};
|
|
382
|
+
};
|
|
383
|
+
|
|
280
384
|
// src/components/RouteContext.tsx
|
|
281
385
|
var import_react = require("react");
|
|
282
386
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -345,12 +449,104 @@ function gtmClick({ category, action, label }) {
|
|
|
345
449
|
label: cleanLabel[cleanLabel.length - 1]
|
|
346
450
|
});
|
|
347
451
|
}
|
|
452
|
+
|
|
453
|
+
// src/components/StageLogin.tsx
|
|
454
|
+
var import_react4 = require("react");
|
|
455
|
+
var import_navigation = require("next/navigation");
|
|
456
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
457
|
+
function OlmoLogo({ className }) {
|
|
458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
459
|
+
"svg",
|
|
460
|
+
{
|
|
461
|
+
role: "img",
|
|
462
|
+
"aria-label": "Olmo",
|
|
463
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
464
|
+
viewBox: "0 0 225 232",
|
|
465
|
+
className,
|
|
466
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M102.3,12.2c75-6.4,129.5,63.8,108.1,135.4-23.3,77.6-124.6,98.3-176.6,36.2C-18.2,121.7,19.1,19.2,102.4,12.2h-.1ZM87.4,202.3c35.6,9.9,73.6-2.3,95.6-32.1,37.4-50.9,12.4-125.6-49.4-140.8C59.5,11.2,1.3,86.9,32.6,154.9c7.7,16.8,23.8,34.9,41.6,40.8l5.5-20.1c-20-27-17.3-63.2,7.3-86.4,11-10.3,38.6-24.9,53.1-28.9s8.1-.9,10.4,3.2,6.5,23.1,7.4,28.4c4,22.6,2.1,44.6-13,62.8-13.1,15.8-31,22.5-50.8,25.5l-6.6,22.1h0ZM139.2,77c-33.7,10.7-72,38.9-54.1,79.1l11-20.1c4.1-4.6,12.6-23.1,17.7-24.7,6.3-2,10.9,3.5,8.7,9.7s-11.8,18.1-15.5,25.1-9,17.8-8.3,18.5c43-8.8,54.8-49.5,40.5-87.6h0Z" })
|
|
467
|
+
}
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
function StageLogin({
|
|
471
|
+
action,
|
|
472
|
+
title = "Olmo Staging access",
|
|
473
|
+
description = "This environment is restricted. Please sign in to continue.",
|
|
474
|
+
usernameLabel = "Username",
|
|
475
|
+
passwordLabel = "Password",
|
|
476
|
+
submitLabel = "Sign in",
|
|
477
|
+
invalidCredentialsMessage = "Invalid username or password.",
|
|
478
|
+
missingConfigMessage = "Stage authentication is not configured."
|
|
479
|
+
}) {
|
|
480
|
+
const params = (0, import_navigation.useSearchParams)();
|
|
481
|
+
const router = (0, import_navigation.useRouter)();
|
|
482
|
+
const from = params.get("from") ?? "/";
|
|
483
|
+
const [state, formAction, pending] = (0, import_react4.useActionState)(action, {});
|
|
484
|
+
(0, import_react4.useEffect)(() => {
|
|
485
|
+
if (state.redirectTo) router.replace(state.redirectTo);
|
|
486
|
+
}, [state.redirectTo, router]);
|
|
487
|
+
const errorMessage = state.error === "invalid_credentials" ? invalidCredentialsMessage : state.error === "missing_config" ? missingConfigMessage : null;
|
|
488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex min-h-full flex-col justify-center px-6 py-12 lg:px-8", children: [
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "sm:mx-auto sm:w-full sm:max-w-[384px]", children: [
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(OlmoLogo, { className: "mx-auto h-10 w-auto " }),
|
|
491
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "space-y-1", children: [
|
|
492
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { className: "text-xl text-center font-semibold text-neutral-900", children: title }),
|
|
493
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-sm text-center text-neutral-600", children: description })
|
|
494
|
+
] })
|
|
495
|
+
] }),
|
|
496
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-10 sm:mx-auto sm:w-full sm:max-w-[384px]", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { action: formAction, method: "POST", className: "space-y-6", children: [
|
|
497
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "hidden", name: "from", value: from }),
|
|
498
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
499
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { htmlFor: "username", className: "block text-sm/6 font-medium text-gray-900", children: usernameLabel }),
|
|
500
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
501
|
+
"input",
|
|
502
|
+
{
|
|
503
|
+
id: "username",
|
|
504
|
+
name: "username",
|
|
505
|
+
type: "username",
|
|
506
|
+
disabled: pending,
|
|
507
|
+
required: true,
|
|
508
|
+
autoComplete: "username",
|
|
509
|
+
className: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6"
|
|
510
|
+
}
|
|
511
|
+
) })
|
|
512
|
+
] }),
|
|
513
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
514
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { htmlFor: "password", className: "block text-sm/6 font-medium text-gray-900", children: passwordLabel }) }),
|
|
515
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
516
|
+
"input",
|
|
517
|
+
{
|
|
518
|
+
id: "password",
|
|
519
|
+
name: "password",
|
|
520
|
+
type: "password",
|
|
521
|
+
disabled: pending,
|
|
522
|
+
required: true,
|
|
523
|
+
autoComplete: "current-password",
|
|
524
|
+
className: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-black sm:text-sm/6"
|
|
525
|
+
}
|
|
526
|
+
) })
|
|
527
|
+
] }),
|
|
528
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
529
|
+
errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { role: "alert", className: "text-sm text-red-600", children: errorMessage }) : null,
|
|
530
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
531
|
+
"button",
|
|
532
|
+
{
|
|
533
|
+
type: "submit",
|
|
534
|
+
disabled: pending,
|
|
535
|
+
className: "cursor-pointer flex w-full justify-center rounded-md bg-black px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-black focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-black",
|
|
536
|
+
children: pending ? "\u2026" : submitLabel
|
|
537
|
+
}
|
|
538
|
+
)
|
|
539
|
+
] })
|
|
540
|
+
] }) })
|
|
541
|
+
] }) });
|
|
542
|
+
}
|
|
348
543
|
// Annotate the CommonJS export names for ESM import in node:
|
|
349
544
|
0 && (module.exports = {
|
|
350
545
|
GtmPage,
|
|
351
546
|
JsonLd,
|
|
352
547
|
RouteProvider,
|
|
353
548
|
RouteSetter,
|
|
549
|
+
StageLogin,
|
|
354
550
|
buildArticle,
|
|
355
551
|
buildBreadcrumb,
|
|
356
552
|
buildItemList,
|
|
@@ -365,6 +561,7 @@ function gtmClick({ category, action, label }) {
|
|
|
365
561
|
posting,
|
|
366
562
|
redirectmiddleware,
|
|
367
563
|
setSeoData,
|
|
564
|
+
stagegatemiddleware,
|
|
368
565
|
useRoute
|
|
369
566
|
});
|
|
370
567
|
//# sourceMappingURL=index.cjs.map
|