@tetherto/dev-websites-core 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +72 -0
  2. package/dist/cms/google-oauth.d.mts +20 -0
  3. package/dist/cms/google-oauth.d.mts.map +1 -0
  4. package/dist/cms/google-oauth.mjs +130 -0
  5. package/dist/cms/google-oauth.mjs.map +1 -0
  6. package/dist/cms/index.d.mts +2 -2
  7. package/dist/cms/index.mjs +2 -2
  8. package/dist/cms.mjs +136 -5
  9. package/dist/cms.mjs.map +1 -1
  10. package/dist/index.d.mts +11 -2
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +4 -3
  13. package/dist/index5.d.mts +2 -2
  14. package/dist/seo/index.mjs +2 -1
  15. package/dist/seo.mjs +2 -13
  16. package/dist/seo.mjs.map +1 -1
  17. package/dist/site-url.mjs +16 -0
  18. package/dist/site-url.mjs.map +1 -0
  19. package/dist/ui/components/Button/Button.d.mts +1 -1
  20. package/dist/ui/components/GoogleOAuthButton/GoogleOAuthButton.d.mts +5 -0
  21. package/dist/ui/components/GoogleOAuthButton/GoogleOAuthButton.d.mts.map +1 -0
  22. package/dist/ui/components/GoogleOAuthButton/GoogleOAuthButton.mjs +72 -0
  23. package/dist/ui/components/GoogleOAuthButton/GoogleOAuthButton.mjs.map +1 -0
  24. package/dist/ui/components/GoogleOAuthButton/googleOAuthStartPath.d.mts +6 -0
  25. package/dist/ui/components/GoogleOAuthButton/googleOAuthStartPath.d.mts.map +1 -0
  26. package/dist/ui/components/GoogleOAuthButton/googleOAuthStartPath.mjs +7 -0
  27. package/dist/ui/components/GoogleOAuthButton/googleOAuthStartPath.mjs.map +1 -0
  28. package/dist/ui/components/GoogleOAuthButton/index.d.mts +2 -0
  29. package/dist/ui/components/GoogleOAuthButton/index.mjs +2 -0
  30. package/dist/ui/index.d.mts +3 -1
  31. package/dist/ui/index.mjs +1 -0
  32. package/package.json +18 -2
  33. package/src/ui/components/GoogleOAuthButton/GoogleOAuthButton.tsx +69 -0
  34. package/src/ui/components/GoogleOAuthButton/googleOAuthStartPath.ts +2 -0
  35. package/src/ui/components/GoogleOAuthButton/index.ts +1 -0
@@ -0,0 +1,16 @@
1
+ import { t as createLogger } from "./logger.mjs";
2
+ //#region src/seo/site-url.ts
3
+ const log = createLogger("siteUrl");
4
+ /** Resolve the public site origin from env (`NEXT_PUBLIC_SITE_URL` / `VERCEL_URL`). */
5
+ function getSiteUrl(options = {}) {
6
+ const fallback = options.fallback ?? "http://localhost:3000";
7
+ const fromEnv = process.env.NEXT_PUBLIC_SITE_URL;
8
+ if (fromEnv) return fromEnv.replace(/\/$/, "");
9
+ if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`.replace(/\/$/, "");
10
+ if (process.env.NODE_ENV === "production") log.warn(`NEXT_PUBLIC_SITE_URL and VERCEL_URL are unset — falling back to ${fallback}. Canonical and Open Graph URLs will be incorrect.`);
11
+ return fallback.replace(/\/$/, "");
12
+ }
13
+ //#endregion
14
+ export { getSiteUrl as t };
15
+
16
+ //# sourceMappingURL=site-url.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-url.mjs","names":[],"sources":["../src/seo/site-url.ts"],"sourcesContent":["import { createLogger } from '../utils/logger/logger.js'\n\nconst log = createLogger('siteUrl')\n\nexport type GetSiteUrlOptions = {\n /** Fallback when no env URL is set. Defaults to `http://localhost:3000`. */\n fallback?: string\n}\n\n/** Resolve the public site origin from env (`NEXT_PUBLIC_SITE_URL` / `VERCEL_URL`). */\nexport function getSiteUrl(options: GetSiteUrlOptions = {}): string {\n const fallback = options.fallback ?? 'http://localhost:3000'\n const fromEnv = process.env.NEXT_PUBLIC_SITE_URL\n if (fromEnv) return fromEnv.replace(/\\/$/, '')\n if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`.replace(/\\/$/, '')\n // A localhost origin in production means canonical/OG URLs will be wrong — surface it loudly.\n if (process.env.NODE_ENV === 'production') {\n log.warn(\n `NEXT_PUBLIC_SITE_URL and VERCEL_URL are unset — falling back to ${fallback}. Canonical and Open Graph URLs will be incorrect.`\n )\n }\n return fallback.replace(/\\/$/, '')\n}\n"],"mappings":";;AAEA,MAAM,MAAM,aAAa,SAAS;;AAQlC,SAAgB,WAAW,UAA6B,CAAC,GAAW;CAClE,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,UAAU,QAAQ,IAAI;CAC5B,IAAI,SAAS,OAAO,QAAQ,QAAQ,OAAO,EAAE;CAC7C,IAAI,QAAQ,IAAI,YAAY,OAAO,WAAW,QAAQ,IAAI,aAAa,QAAQ,OAAO,EAAE;CAExF,IAAI,QAAQ,IAAI,aAAa,cAC3B,IAAI,KACF,mEAAmE,SAAS,mDAC9E;CAEF,OAAO,SAAS,QAAQ,OAAO,EAAE;AACnC"}
@@ -3,7 +3,7 @@ import { VariantProps } from "class-variance-authority";
3
3
  //#region src/ui/components/Button/Button.d.ts
4
4
  declare const buttonVariants: (props?: ({
5
5
  variant?: "link" | "solid" | "outline" | "ghost" | "secondary" | "social" | "action" | "elevated-outline" | null | undefined;
6
- size?: "social" | "default" | "sm" | "cta" | "icon" | null | undefined;
6
+ size?: "sm" | "social" | "default" | "cta" | "icon" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  type ButtonProps = ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
9
9
  asChild?: boolean;
@@ -0,0 +1,5 @@
1
+ //#region src/ui/components/GoogleOAuthButton/GoogleOAuthButton.d.ts
2
+ declare function GoogleOAuthButton(): import("react").JSX.Element;
3
+ //#endregion
4
+ export { GoogleOAuthButton };
5
+ //# sourceMappingURL=GoogleOAuthButton.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GoogleOAuthButton.d.mts","names":[],"sources":["../../../../src/ui/components/GoogleOAuthButton/GoogleOAuthButton.tsx"],"mappings":";iBASgB,qCAAiB,IAAA"}
@@ -0,0 +1,72 @@
1
+ "use client";
2
+ import { Button } from "../Button/Button.mjs";
3
+ import { GOOGLE_OAUTH_START_PATH } from "./googleOAuthStartPath.mjs";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { useEffect } from "react";
6
+ import { useSearchParams } from "next/navigation";
7
+ //#region src/ui/components/GoogleOAuthButton/GoogleOAuthButton.tsx
8
+ function GoogleOAuthButton() {
9
+ const searchParams = useSearchParams();
10
+ useEffect(() => {
11
+ const error = searchParams.get("error");
12
+ if (error && process.env.NODE_ENV === "development") console.error("OAuth error:", error);
13
+ }, [searchParams]);
14
+ const handleGoogleLogin = () => {
15
+ window.location.href = GOOGLE_OAUTH_START_PATH;
16
+ };
17
+ return /* @__PURE__ */ jsx("form", {
18
+ className: "w-full",
19
+ children: /* @__PURE__ */ jsxs("div", {
20
+ className: "form-submit flex w-full flex-col items-stretch",
21
+ children: [/* @__PURE__ */ jsxs("div", {
22
+ className: "my-3 flex w-full items-center gap-3",
23
+ role: "separator",
24
+ children: [
25
+ /* @__PURE__ */ jsx("span", {
26
+ className: "block h-px min-w-0 flex-1 bg-[var(--theme-elevation-250,#cfcfcf)]",
27
+ "aria-hidden": "true"
28
+ }),
29
+ /* @__PURE__ */ jsx("span", {
30
+ className: "shrink-0 text-center text-[13px] leading-none font-normal tracking-normal whitespace-nowrap text-[var(--theme-elevation-500,#8c8c8c)]",
31
+ children: "Or"
32
+ }),
33
+ /* @__PURE__ */ jsx("span", {
34
+ className: "block h-px min-w-0 flex-1 bg-[var(--theme-elevation-250,#cfcfcf)]",
35
+ "aria-hidden": "true"
36
+ })
37
+ ]
38
+ }), /* @__PURE__ */ jsxs(Button, {
39
+ type: "button",
40
+ onClick: handleGoogleLogin,
41
+ className: "btn btn--icon-style-without-border btn--size-large btn--withoutPopup btn--style-primary !my-0",
42
+ children: [/* @__PURE__ */ jsxs("svg", {
43
+ className: "mr-2 size-[18px] shrink-0",
44
+ viewBox: "0 0 18 18",
45
+ "aria-hidden": "true",
46
+ children: [
47
+ /* @__PURE__ */ jsx("path", {
48
+ fill: "#4285F4",
49
+ d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z"
50
+ }),
51
+ /* @__PURE__ */ jsx("path", {
52
+ fill: "#34A853",
53
+ d: "M9.003 18c2.43 0 4.467-.806 5.956-2.184l-2.908-2.258c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332C2.44 15.983 5.485 18 9.003 18z"
54
+ }),
55
+ /* @__PURE__ */ jsx("path", {
56
+ fill: "#FBBC05",
57
+ d: "M3.964 10.712c-.18-.54-.282-1.117-.282-1.71 0-.593.102-1.17.282-1.71V4.96H.957C.347 6.175 0 7.55 0 9.002c0 1.452.348 2.827.957 4.042l3.007-2.332z"
58
+ }),
59
+ /* @__PURE__ */ jsx("path", {
60
+ fill: "#EA4335",
61
+ d: "M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.426 0 9.003 0 5.485 0 2.44 2.017.96 4.958L3.967 7.29c.708-2.127 2.692-3.71 5.036-3.71z"
62
+ })
63
+ ]
64
+ }), "Continue with Google"]
65
+ })]
66
+ })
67
+ });
68
+ }
69
+ //#endregion
70
+ export { GoogleOAuthButton };
71
+
72
+ //# sourceMappingURL=GoogleOAuthButton.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GoogleOAuthButton.mjs","names":[],"sources":["../../../../src/ui/components/GoogleOAuthButton/GoogleOAuthButton.tsx"],"sourcesContent":["'use client'\n\nimport { useSearchParams } from 'next/navigation'\nimport { useEffect } from 'react'\n\nimport { Button } from '../Button/Button.js'\n\nimport { GOOGLE_OAUTH_START_PATH } from './googleOAuthStartPath.js'\n\nexport function GoogleOAuthButton() {\n const searchParams = useSearchParams()\n\n useEffect(() => {\n const error = searchParams.get('error')\n if (error && process.env.NODE_ENV === 'development') {\n // eslint-disable-next-line no-console\n console.error('OAuth error:', error)\n }\n }, [searchParams])\n\n const handleGoogleLogin = () => {\n window.location.href = GOOGLE_OAUTH_START_PATH\n }\n\n return (\n <form className=\"w-full\">\n <div className=\"form-submit flex w-full flex-col items-stretch\">\n <div className=\"my-3 flex w-full items-center gap-3\" role=\"separator\">\n <span\n className=\"block h-px min-w-0 flex-1 bg-[var(--theme-elevation-250,#cfcfcf)]\"\n aria-hidden=\"true\"\n />\n <span className=\"shrink-0 text-center text-[13px] leading-none font-normal tracking-normal whitespace-nowrap text-[var(--theme-elevation-500,#8c8c8c)]\">\n Or\n </span>\n <span\n className=\"block h-px min-w-0 flex-1 bg-[var(--theme-elevation-250,#cfcfcf)]\"\n aria-hidden=\"true\"\n />\n </div>\n <Button\n type=\"button\"\n onClick={handleGoogleLogin}\n className=\"btn btn--icon-style-without-border btn--size-large btn--withoutPopup btn--style-primary !my-0\"\n >\n <svg className=\"mr-2 size-[18px] shrink-0\" viewBox=\"0 0 18 18\" aria-hidden=\"true\">\n <path\n fill=\"#4285F4\"\n d=\"M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z\"\n />\n <path\n fill=\"#34A853\"\n d=\"M9.003 18c2.43 0 4.467-.806 5.956-2.184l-2.908-2.258c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332C2.44 15.983 5.485 18 9.003 18z\"\n />\n <path\n fill=\"#FBBC05\"\n d=\"M3.964 10.712c-.18-.54-.282-1.117-.282-1.71 0-.593.102-1.17.282-1.71V4.96H.957C.347 6.175 0 7.55 0 9.002c0 1.452.348 2.827.957 4.042l3.007-2.332z\"\n />\n <path\n fill=\"#EA4335\"\n d=\"M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.426 0 9.003 0 5.485 0 2.44 2.017.96 4.958L3.967 7.29c.708-2.127 2.692-3.71 5.036-3.71z\"\n />\n </svg>\n Continue with Google\n </Button>\n </div>\n </form>\n )\n}\n"],"mappings":";;;;;;;AASA,SAAgB,oBAAoB;CAClC,MAAM,eAAe,gBAAgB;CAErC,gBAAgB;EACd,MAAM,QAAQ,aAAa,IAAI,OAAO;EACtC,IAAI,SAAS,QAAQ,IAAI,aAAa,eAEpC,QAAQ,MAAM,gBAAgB,KAAK;CAEvC,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,0BAA0B;EAC9B,OAAO,SAAS,OAAO;CACzB;CAEA,OACE,oBAAC,QAAD;EAAM,WAAU;EACd,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,qBAAC,OAAD;IAAK,WAAU;IAAsC,MAAK;IAA1D,UAAA;KACE,oBAAC,QAAD;MACE,WAAU;MACV,eAAY;KACb,CAAA;KACD,oBAAC,QAAD;MAAM,WAAU;MAAwI,UAAA;KAElJ,CAAA;KACN,oBAAC,QAAD;MACE,WAAU;MACV,eAAY;KACb,CAAA;IACE;GACL,CAAA,GAAA,qBAAC,QAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;IAHZ,UAAA,CAKE,qBAAC,OAAD;KAAK,WAAU;KAA4B,SAAQ;KAAY,eAAY;KAA3E,UAAA;MACE,oBAAC,QAAD;OACE,MAAK;OACL,GAAE;MACH,CAAA;MACD,oBAAC,QAAD;OACE,MAAK;OACL,GAAE;MACH,CAAA;MACD,oBAAC,QAAD;OACE,MAAK;OACL,GAAE;MACH,CAAA;MACD,oBAAC,QAAD;OACE,MAAK;OACL,GAAE;MACH,CAAA;KACE;IAAC,CAAA,GAAA,sBAEA;GACL,CAAA,CAAA;;CACD,CAAA;AAEV"}
@@ -0,0 +1,6 @@
1
+ //#region src/ui/components/GoogleOAuthButton/googleOAuthStartPath.d.ts
2
+ /** Site route that starts the Google OAuth redirect. */
3
+ declare const GOOGLE_OAUTH_START_PATH = "/api/auth/google";
4
+ //#endregion
5
+ export { GOOGLE_OAUTH_START_PATH };
6
+ //# sourceMappingURL=googleOAuthStartPath.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"googleOAuthStartPath.d.mts","names":[],"sources":["../../../../src/ui/components/GoogleOAuthButton/googleOAuthStartPath.ts"],"mappings":";;cACa"}
@@ -0,0 +1,7 @@
1
+ //#region src/ui/components/GoogleOAuthButton/googleOAuthStartPath.ts
2
+ /** Site route that starts the Google OAuth redirect. */
3
+ const GOOGLE_OAUTH_START_PATH = "/api/auth/google";
4
+ //#endregion
5
+ export { GOOGLE_OAUTH_START_PATH };
6
+
7
+ //# sourceMappingURL=googleOAuthStartPath.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"googleOAuthStartPath.mjs","names":[],"sources":["../../../../src/ui/components/GoogleOAuthButton/googleOAuthStartPath.ts"],"sourcesContent":["/** Site route that starts the Google OAuth redirect. */\nexport const GOOGLE_OAUTH_START_PATH = '/api/auth/google'\n"],"mappings":";;AACA,MAAa,0BAA0B"}
@@ -0,0 +1,2 @@
1
+ import { GoogleOAuthButton } from "./GoogleOAuthButton.mjs";
2
+ export { GoogleOAuthButton };
@@ -0,0 +1,2 @@
1
+ import { GoogleOAuthButton } from "./GoogleOAuthButton.mjs";
2
+ export { GoogleOAuthButton };
@@ -33,6 +33,8 @@ import { FieldError, FieldErrorProps } from "./components/FieldError/FieldError.
33
33
  import "./components/FieldError/index.mjs";
34
34
  import { FormatDateOptions, FormattedDate, FormattedDateProps, formatDate } from "./components/FormattedDate/FormattedDate.mjs";
35
35
  import "./components/FormattedDate/index.mjs";
36
+ import { GoogleOAuthButton } from "./components/GoogleOAuthButton/GoogleOAuthButton.mjs";
37
+ import "./components/GoogleOAuthButton/index.mjs";
36
38
  import "./components/IconButton/index.mjs";
37
39
  import { Input, InputProps } from "./components/Input/Input.mjs";
38
40
  import "./components/Input/index.mjs";
@@ -78,4 +80,4 @@ import { UseInViewOptions, useInView } from "./hooks/useInView.mjs";
78
80
  import "./hooks/index.mjs";
79
81
  import { cn } from "./utils/cn.mjs";
80
82
  import "./utils/index.mjs";
81
- export { Accordion, type AccordionItem, type AccordionProps, Avatar, type AvatarProps, BADGE_VERSION_RELEASE_TYPE_STYLES, Badge, type BadgeProps, BadgeVersion, type BadgeVersionProps, Button, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, CodeBlock, type CodeBlockProps, type CodeBlockTab, CodeBlockTabs, type CodeBlockTabsProps, type CodeBlockTabsTheme, type CodeBlockTheme, CollapsibleSection, type CollapsibleSectionProps, CopyButton, type CopyButtonProps, Dialog, DialogBody, DialogClose, DialogContent, type DialogContentProps, DialogDescription, type DialogDescriptionProps, DialogFooter, DialogHeader, DialogOverlay, type DialogOverlayProps, DialogPortal, DialogTitle, type DialogTitleProps, DialogTrigger, EmptyState, type EmptyStateProps, FieldError, type FieldErrorProps, type FormatDateOptions, FormattedDate, type FormattedDateProps, IconButton, type IconButtonProps, Input, type InputProps, Label, type LabelProps, LazyVideo, type LazyVideoProps, Pagination, PaginationItem, type PaginationItemProps, type PaginationLabels, type PaginationProps, PasswordInput, type PasswordInputProps, ProgressStepper, type ProgressStepperProps, Prose, type ProseProps, Radio, type RadioProps, type ReleaseType, Reveal, type RevealProps, SearchInput, type SearchInputProps, Select, type SelectOption, type SelectProps, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetOverlay, type SheetOverlayProps, SheetPortal, SheetTrigger, StaggerReveal, type StaggerRevealProps, Stepper, type StepperItem, type StepperProps, Switch, type SwitchProps, TextButton, type TextButtonProps, Textarea, type TextareaProps, ToastProvider, type ToastProviderProps, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, type UseInViewOptions, VisuallyHidden, type VisuallyHiddenProps, badgeVariants, buildPageItems, buttonVariants, cardVariants, cn, coerceBadgeReleaseType, dialogFullscreenOnMobile, emptyStateVariants, focusRingClassName, formatDate, segmentVariants, useInView, useToast };
83
+ export { Accordion, type AccordionItem, type AccordionProps, Avatar, type AvatarProps, BADGE_VERSION_RELEASE_TYPE_STYLES, Badge, type BadgeProps, BadgeVersion, type BadgeVersionProps, Button, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, CodeBlock, type CodeBlockProps, type CodeBlockTab, CodeBlockTabs, type CodeBlockTabsProps, type CodeBlockTabsTheme, type CodeBlockTheme, CollapsibleSection, type CollapsibleSectionProps, CopyButton, type CopyButtonProps, Dialog, DialogBody, DialogClose, DialogContent, type DialogContentProps, DialogDescription, type DialogDescriptionProps, DialogFooter, DialogHeader, DialogOverlay, type DialogOverlayProps, DialogPortal, DialogTitle, type DialogTitleProps, DialogTrigger, EmptyState, type EmptyStateProps, FieldError, type FieldErrorProps, type FormatDateOptions, FormattedDate, type FormattedDateProps, GoogleOAuthButton, IconButton, type IconButtonProps, Input, type InputProps, Label, type LabelProps, LazyVideo, type LazyVideoProps, Pagination, PaginationItem, type PaginationItemProps, type PaginationLabels, type PaginationProps, PasswordInput, type PasswordInputProps, ProgressStepper, type ProgressStepperProps, Prose, type ProseProps, Radio, type RadioProps, type ReleaseType, Reveal, type RevealProps, SearchInput, type SearchInputProps, Select, type SelectOption, type SelectProps, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetOverlay, type SheetOverlayProps, SheetPortal, SheetTrigger, StaggerReveal, type StaggerRevealProps, Stepper, type StepperItem, type StepperProps, Switch, type SwitchProps, TextButton, type TextButtonProps, Textarea, type TextareaProps, ToastProvider, type ToastProviderProps, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, type UseInViewOptions, VisuallyHidden, type VisuallyHiddenProps, badgeVariants, buildPageItems, buttonVariants, cardVariants, cn, coerceBadgeReleaseType, dialogFullscreenOnMobile, emptyStateVariants, focusRingClassName, formatDate, segmentVariants, useInView, useToast };
package/dist/ui/index.mjs CHANGED
@@ -38,3 +38,4 @@ export * from './components/PasswordInput/index.mjs'
38
38
  export * from './components/SearchInput/index.mjs'
39
39
  export * from './components/FieldError/index.mjs'
40
40
  export * from './components/CollapsibleSection/index.mjs'
41
+ export * from './components/GoogleOAuthButton/index.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tetherto/dev-websites-core",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Shared CMS, SEO, i18n, utils, UI, and analytics primitives for the WDK / QVAC / PEAR / MDK websites.",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -28,6 +28,11 @@
28
28
  "import": "./dist/cms/index.mjs",
29
29
  "default": "./dist/cms/index.mjs"
30
30
  },
31
+ "./cms/google-oauth": {
32
+ "types": "./dist/cms/google-oauth.d.mts",
33
+ "import": "./dist/cms/google-oauth.mjs",
34
+ "default": "./dist/cms/google-oauth.mjs"
35
+ },
31
36
  "./seo": {
32
37
  "types": "./dist/seo/index.d.mts",
33
38
  "import": "./dist/seo/index.mjs",
@@ -53,6 +58,11 @@
53
58
  "import": "./dist/ui/index.mjs",
54
59
  "default": "./dist/ui/index.mjs"
55
60
  },
61
+ "./ui/google-oauth": {
62
+ "types": "./dist/ui/components/GoogleOAuthButton/index.d.mts",
63
+ "import": "./dist/ui/components/GoogleOAuthButton/index.mjs",
64
+ "default": "./dist/ui/components/GoogleOAuthButton/index.mjs"
65
+ },
56
66
  "./ui/a11y": {
57
67
  "types": "./dist/ui/a11y/index.d.mts",
58
68
  "import": "./dist/ui/a11y/index.mjs",
@@ -71,7 +81,8 @@
71
81
  },
72
82
  "files": [
73
83
  "dist",
74
- "src/ui/theme"
84
+ "src/ui/theme",
85
+ "src/ui/components/GoogleOAuthButton"
75
86
  ],
76
87
  "scripts": {
77
88
  "build": "tsdown",
@@ -99,6 +110,7 @@
99
110
  "class-variance-authority": "^0.7.0",
100
111
  "clsx": "^2.1.0",
101
112
  "embla-carousel-react": "^8.0.0",
113
+ "google-auth-library": "^11.1.0",
102
114
  "next": ">=15",
103
115
  "payload": "^3.85.1",
104
116
  "react": ">=19",
@@ -113,6 +125,9 @@
113
125
  "embla-carousel-react": {
114
126
  "optional": true
115
127
  },
128
+ "google-auth-library": {
129
+ "optional": true
130
+ },
116
131
  "react-icons": {
117
132
  "optional": true
118
133
  }
@@ -139,6 +154,7 @@
139
154
  "eslint-plugin-import": "^2.32.0",
140
155
  "eslint-plugin-prettier": "^5.5.5",
141
156
  "eslint-plugin-react-hooks": "^5.2.0",
157
+ "google-auth-library": "^11.1.0",
142
158
  "next": "^16.2.6",
143
159
  "payload": "3.88.0",
144
160
  "prettier": "^3.8.1",
@@ -0,0 +1,69 @@
1
+ 'use client'
2
+
3
+ import { useSearchParams } from 'next/navigation'
4
+ import { useEffect } from 'react'
5
+
6
+ import { Button } from '../Button/Button.js'
7
+
8
+ import { GOOGLE_OAUTH_START_PATH } from './googleOAuthStartPath.js'
9
+
10
+ export function GoogleOAuthButton() {
11
+ const searchParams = useSearchParams()
12
+
13
+ useEffect(() => {
14
+ const error = searchParams.get('error')
15
+ if (error && process.env.NODE_ENV === 'development') {
16
+ // eslint-disable-next-line no-console
17
+ console.error('OAuth error:', error)
18
+ }
19
+ }, [searchParams])
20
+
21
+ const handleGoogleLogin = () => {
22
+ window.location.href = GOOGLE_OAUTH_START_PATH
23
+ }
24
+
25
+ return (
26
+ <form className="w-full">
27
+ <div className="form-submit flex w-full flex-col items-stretch">
28
+ <div className="my-3 flex w-full items-center gap-3" role="separator">
29
+ <span
30
+ className="block h-px min-w-0 flex-1 bg-[var(--theme-elevation-250,#cfcfcf)]"
31
+ aria-hidden="true"
32
+ />
33
+ <span className="shrink-0 text-center text-[13px] leading-none font-normal tracking-normal whitespace-nowrap text-[var(--theme-elevation-500,#8c8c8c)]">
34
+ Or
35
+ </span>
36
+ <span
37
+ className="block h-px min-w-0 flex-1 bg-[var(--theme-elevation-250,#cfcfcf)]"
38
+ aria-hidden="true"
39
+ />
40
+ </div>
41
+ <Button
42
+ type="button"
43
+ onClick={handleGoogleLogin}
44
+ className="btn btn--icon-style-without-border btn--size-large btn--withoutPopup btn--style-primary !my-0"
45
+ >
46
+ <svg className="mr-2 size-[18px] shrink-0" viewBox="0 0 18 18" aria-hidden="true">
47
+ <path
48
+ fill="#4285F4"
49
+ d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z"
50
+ />
51
+ <path
52
+ fill="#34A853"
53
+ d="M9.003 18c2.43 0 4.467-.806 5.956-2.184l-2.908-2.258c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332C2.44 15.983 5.485 18 9.003 18z"
54
+ />
55
+ <path
56
+ fill="#FBBC05"
57
+ d="M3.964 10.712c-.18-.54-.282-1.117-.282-1.71 0-.593.102-1.17.282-1.71V4.96H.957C.347 6.175 0 7.55 0 9.002c0 1.452.348 2.827.957 4.042l3.007-2.332z"
58
+ />
59
+ <path
60
+ fill="#EA4335"
61
+ d="M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.426 0 9.003 0 5.485 0 2.44 2.017.96 4.958L3.967 7.29c.708-2.127 2.692-3.71 5.036-3.71z"
62
+ />
63
+ </svg>
64
+ Continue with Google
65
+ </Button>
66
+ </div>
67
+ </form>
68
+ )
69
+ }
@@ -0,0 +1,2 @@
1
+ /** Site route that starts the Google OAuth redirect. */
2
+ export const GOOGLE_OAUTH_START_PATH = '/api/auth/google'
@@ -0,0 +1 @@
1
+ export { GoogleOAuthButton } from './GoogleOAuthButton.js'