@olmocms/front 0.1.2 → 0.1.5
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 +107 -0
- package/dist/auth/action.cjs.map +1 -0
- package/dist/auth/action.d.cts +6 -0
- package/dist/auth/action.d.ts +6 -0
- package/dist/auth/action.js +83 -0
- package/dist/auth/action.js.map +1 -0
- package/dist/chunk-RAI2AUWN.js +168 -0
- package/dist/chunk-RAI2AUWN.js.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/components/index.cjs +88 -0
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +17 -1
- package/dist/components/index.d.ts +17 -1
- package/dist/components/index.js +87 -0
- package/dist/components/index.js.map +1 -1
- package/dist/index.cjs +191 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.js +91 -2
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.cjs +105 -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,99 @@ 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 from = params.get("from") ?? "/";
|
|
134
|
+
const [state, formAction, pending] = (0, import_react4.useActionState)(action, {});
|
|
135
|
+
const errorMessage = state.error === "invalid_credentials" ? invalidCredentialsMessage : state.error === "missing_config" ? missingConfigMessage : null;
|
|
136
|
+
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: [
|
|
137
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "sm:mx-auto sm:w-full sm:max-w-[384px]", children: [
|
|
138
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(OlmoLogo, { className: "mx-auto h-10 w-auto " }),
|
|
139
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "space-y-1", children: [
|
|
140
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { className: "text-xl text-center font-semibold text-neutral-900", children: title }),
|
|
141
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-sm text-center text-neutral-600", children: description })
|
|
142
|
+
] })
|
|
143
|
+
] }),
|
|
144
|
+
/* @__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: [
|
|
145
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
146
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { htmlFor: "username", className: "block text-sm/6 font-medium text-gray-900", children: usernameLabel }),
|
|
147
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
148
|
+
"input",
|
|
149
|
+
{
|
|
150
|
+
id: "username",
|
|
151
|
+
name: "username",
|
|
152
|
+
type: "username",
|
|
153
|
+
disabled: pending,
|
|
154
|
+
required: true,
|
|
155
|
+
autoComplete: "username",
|
|
156
|
+
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"
|
|
157
|
+
}
|
|
158
|
+
) })
|
|
159
|
+
] }),
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
161
|
+
/* @__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 }) }),
|
|
162
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
163
|
+
"input",
|
|
164
|
+
{
|
|
165
|
+
id: "password",
|
|
166
|
+
name: "password",
|
|
167
|
+
type: "password",
|
|
168
|
+
disabled: pending,
|
|
169
|
+
required: true,
|
|
170
|
+
autoComplete: "current-password",
|
|
171
|
+
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"
|
|
172
|
+
}
|
|
173
|
+
) })
|
|
174
|
+
] }),
|
|
175
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
176
|
+
errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { role: "alert", className: "text-sm text-red-600", children: errorMessage }) : null,
|
|
177
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
178
|
+
"button",
|
|
179
|
+
{
|
|
180
|
+
type: "submit",
|
|
181
|
+
disabled: pending,
|
|
182
|
+
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",
|
|
183
|
+
children: pending ? "\u2026" : submitLabel
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
] })
|
|
187
|
+
] }) })
|
|
188
|
+
] }) });
|
|
189
|
+
}
|
|
103
190
|
// Annotate the CommonJS export names for ESM import in node:
|
|
104
191
|
0 && (module.exports = {
|
|
105
192
|
GtmPage,
|
|
106
193
|
JsonLd,
|
|
107
194
|
RouteProvider,
|
|
108
195
|
RouteSetter,
|
|
196
|
+
StageLogin,
|
|
109
197
|
gtmClick,
|
|
110
198
|
gtmFormSent,
|
|
111
199
|
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 } from 'react';\nimport { useSearchParams } 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 = { error?: 'missing_config' | 'invalid_credentials' | null };\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 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 <>\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 <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,20 @@ 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
|
+
};
|
|
49
|
+
type StageLoginAction = (prev: StageLoginState, formData: FormData) => Promise<StageLoginState>;
|
|
50
|
+
type StageLoginProps = {
|
|
51
|
+
action: StageLoginAction;
|
|
52
|
+
title?: string;
|
|
53
|
+
description?: string;
|
|
54
|
+
usernameLabel?: string;
|
|
55
|
+
passwordLabel?: string;
|
|
56
|
+
submitLabel?: string;
|
|
57
|
+
invalidCredentialsMessage?: string;
|
|
58
|
+
missingConfigMessage?: string;
|
|
59
|
+
};
|
|
60
|
+
declare function StageLogin({ action, title, description, usernameLabel, passwordLabel, submitLabel, invalidCredentialsMessage, missingConfigMessage, }: StageLoginProps): react_jsx_runtime.JSX.Element;
|
|
61
|
+
|
|
62
|
+
export { GtmPage, JsonLd, RouteProvider, RouteSetter, StageLogin, type StageLoginProps, gtmClick, gtmFormSent, gtmPageView, useRoute };
|
|
@@ -43,4 +43,20 @@ 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
|
+
};
|
|
49
|
+
type StageLoginAction = (prev: StageLoginState, formData: FormData) => Promise<StageLoginState>;
|
|
50
|
+
type StageLoginProps = {
|
|
51
|
+
action: StageLoginAction;
|
|
52
|
+
title?: string;
|
|
53
|
+
description?: string;
|
|
54
|
+
usernameLabel?: string;
|
|
55
|
+
passwordLabel?: string;
|
|
56
|
+
submitLabel?: string;
|
|
57
|
+
invalidCredentialsMessage?: string;
|
|
58
|
+
missingConfigMessage?: string;
|
|
59
|
+
};
|
|
60
|
+
declare function StageLogin({ action, title, description, usernameLabel, passwordLabel, submitLabel, invalidCredentialsMessage, missingConfigMessage, }: StageLoginProps): react_jsx_runtime.JSX.Element;
|
|
61
|
+
|
|
62
|
+
export { GtmPage, JsonLd, RouteProvider, RouteSetter, StageLogin, type StageLoginProps, gtmClick, gtmFormSent, gtmPageView, useRoute };
|
package/dist/components/index.js
CHANGED
|
@@ -68,11 +68,98 @@ 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 } from "react";
|
|
74
|
+
import { useSearchParams } 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 from = params.get("from") ?? "/";
|
|
101
|
+
const [state, formAction, pending] = useActionState(action, {});
|
|
102
|
+
const errorMessage = state.error === "invalid_credentials" ? invalidCredentialsMessage : state.error === "missing_config" ? missingConfigMessage : null;
|
|
103
|
+
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: [
|
|
104
|
+
/* @__PURE__ */ jsxs("div", { className: "sm:mx-auto sm:w-full sm:max-w-[384px]", children: [
|
|
105
|
+
/* @__PURE__ */ jsx4(OlmoLogo, { className: "mx-auto h-10 w-auto " }),
|
|
106
|
+
/* @__PURE__ */ jsxs("header", { className: "space-y-1", children: [
|
|
107
|
+
/* @__PURE__ */ jsx4("h1", { className: "text-xl text-center font-semibold text-neutral-900", children: title }),
|
|
108
|
+
/* @__PURE__ */ jsx4("p", { className: "text-sm text-center text-neutral-600", children: description })
|
|
109
|
+
] })
|
|
110
|
+
] }),
|
|
111
|
+
/* @__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: [
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
113
|
+
/* @__PURE__ */ jsx4("label", { htmlFor: "username", className: "block text-sm/6 font-medium text-gray-900", children: usernameLabel }),
|
|
114
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-2", children: /* @__PURE__ */ jsx4(
|
|
115
|
+
"input",
|
|
116
|
+
{
|
|
117
|
+
id: "username",
|
|
118
|
+
name: "username",
|
|
119
|
+
type: "username",
|
|
120
|
+
disabled: pending,
|
|
121
|
+
required: true,
|
|
122
|
+
autoComplete: "username",
|
|
123
|
+
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"
|
|
124
|
+
}
|
|
125
|
+
) })
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
128
|
+
/* @__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 }) }),
|
|
129
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-2", children: /* @__PURE__ */ jsx4(
|
|
130
|
+
"input",
|
|
131
|
+
{
|
|
132
|
+
id: "password",
|
|
133
|
+
name: "password",
|
|
134
|
+
type: "password",
|
|
135
|
+
disabled: pending,
|
|
136
|
+
required: true,
|
|
137
|
+
autoComplete: "current-password",
|
|
138
|
+
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"
|
|
139
|
+
}
|
|
140
|
+
) })
|
|
141
|
+
] }),
|
|
142
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
143
|
+
errorMessage ? /* @__PURE__ */ jsx4("p", { role: "alert", className: "text-sm text-red-600", children: errorMessage }) : null,
|
|
144
|
+
/* @__PURE__ */ jsx4(
|
|
145
|
+
"button",
|
|
146
|
+
{
|
|
147
|
+
type: "submit",
|
|
148
|
+
disabled: pending,
|
|
149
|
+
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",
|
|
150
|
+
children: pending ? "\u2026" : submitLabel
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
] })
|
|
154
|
+
] }) })
|
|
155
|
+
] }) });
|
|
156
|
+
}
|
|
71
157
|
export {
|
|
72
158
|
GtmPage,
|
|
73
159
|
JsonLd,
|
|
74
160
|
RouteProvider,
|
|
75
161
|
RouteSetter,
|
|
162
|
+
StageLogin,
|
|
76
163
|
gtmClick,
|
|
77
164
|
gtmFormSent,
|
|
78
165
|
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 } from 'react';\nimport { useSearchParams } 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 = { error?: 'missing_config' | 'invalid_credentials' | null };\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 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 <>\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 <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","Fragment","jsx","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,107 @@ 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
|
+
return withNoindex(import_server4.NextResponse.redirect(url, { status: 307 }));
|
|
380
|
+
};
|
|
381
|
+
};
|
|
382
|
+
|
|
280
383
|
// src/components/RouteContext.tsx
|
|
281
384
|
var import_react = require("react");
|
|
282
385
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -345,12 +448,99 @@ function gtmClick({ category, action, label }) {
|
|
|
345
448
|
label: cleanLabel[cleanLabel.length - 1]
|
|
346
449
|
});
|
|
347
450
|
}
|
|
451
|
+
|
|
452
|
+
// src/components/StageLogin.tsx
|
|
453
|
+
var import_react4 = require("react");
|
|
454
|
+
var import_navigation = require("next/navigation");
|
|
455
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
456
|
+
function OlmoLogo({ className }) {
|
|
457
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
458
|
+
"svg",
|
|
459
|
+
{
|
|
460
|
+
role: "img",
|
|
461
|
+
"aria-label": "Olmo",
|
|
462
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
463
|
+
viewBox: "0 0 225 232",
|
|
464
|
+
className,
|
|
465
|
+
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" })
|
|
466
|
+
}
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
function StageLogin({
|
|
470
|
+
action,
|
|
471
|
+
title = "Olmo Staging access",
|
|
472
|
+
description = "This environment is restricted. Please sign in to continue.",
|
|
473
|
+
usernameLabel = "Username",
|
|
474
|
+
passwordLabel = "Password",
|
|
475
|
+
submitLabel = "Sign in",
|
|
476
|
+
invalidCredentialsMessage = "Invalid username or password.",
|
|
477
|
+
missingConfigMessage = "Stage authentication is not configured."
|
|
478
|
+
}) {
|
|
479
|
+
const params = (0, import_navigation.useSearchParams)();
|
|
480
|
+
const from = params.get("from") ?? "/";
|
|
481
|
+
const [state, formAction, pending] = (0, import_react4.useActionState)(action, {});
|
|
482
|
+
const errorMessage = state.error === "invalid_credentials" ? invalidCredentialsMessage : state.error === "missing_config" ? missingConfigMessage : null;
|
|
483
|
+
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: [
|
|
484
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "sm:mx-auto sm:w-full sm:max-w-[384px]", children: [
|
|
485
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(OlmoLogo, { className: "mx-auto h-10 w-auto " }),
|
|
486
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "space-y-1", children: [
|
|
487
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { className: "text-xl text-center font-semibold text-neutral-900", children: title }),
|
|
488
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-sm text-center text-neutral-600", children: description })
|
|
489
|
+
] })
|
|
490
|
+
] }),
|
|
491
|
+
/* @__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: [
|
|
492
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
493
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { htmlFor: "username", className: "block text-sm/6 font-medium text-gray-900", children: usernameLabel }),
|
|
494
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
495
|
+
"input",
|
|
496
|
+
{
|
|
497
|
+
id: "username",
|
|
498
|
+
name: "username",
|
|
499
|
+
type: "username",
|
|
500
|
+
disabled: pending,
|
|
501
|
+
required: true,
|
|
502
|
+
autoComplete: "username",
|
|
503
|
+
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"
|
|
504
|
+
}
|
|
505
|
+
) })
|
|
506
|
+
] }),
|
|
507
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
508
|
+
/* @__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 }) }),
|
|
509
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
510
|
+
"input",
|
|
511
|
+
{
|
|
512
|
+
id: "password",
|
|
513
|
+
name: "password",
|
|
514
|
+
type: "password",
|
|
515
|
+
disabled: pending,
|
|
516
|
+
required: true,
|
|
517
|
+
autoComplete: "current-password",
|
|
518
|
+
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"
|
|
519
|
+
}
|
|
520
|
+
) })
|
|
521
|
+
] }),
|
|
522
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
523
|
+
errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { role: "alert", className: "text-sm text-red-600", children: errorMessage }) : null,
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
525
|
+
"button",
|
|
526
|
+
{
|
|
527
|
+
type: "submit",
|
|
528
|
+
disabled: pending,
|
|
529
|
+
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",
|
|
530
|
+
children: pending ? "\u2026" : submitLabel
|
|
531
|
+
}
|
|
532
|
+
)
|
|
533
|
+
] })
|
|
534
|
+
] }) })
|
|
535
|
+
] }) });
|
|
536
|
+
}
|
|
348
537
|
// Annotate the CommonJS export names for ESM import in node:
|
|
349
538
|
0 && (module.exports = {
|
|
350
539
|
GtmPage,
|
|
351
540
|
JsonLd,
|
|
352
541
|
RouteProvider,
|
|
353
542
|
RouteSetter,
|
|
543
|
+
StageLogin,
|
|
354
544
|
buildArticle,
|
|
355
545
|
buildBreadcrumb,
|
|
356
546
|
buildItemList,
|
|
@@ -365,6 +555,7 @@ function gtmClick({ category, action, label }) {
|
|
|
365
555
|
posting,
|
|
366
556
|
redirectmiddleware,
|
|
367
557
|
setSeoData,
|
|
558
|
+
stagegatemiddleware,
|
|
368
559
|
useRoute
|
|
369
560
|
});
|
|
370
561
|
//# sourceMappingURL=index.cjs.map
|