@playfast/reform-better-hub-ui-primitives 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,182 +1,175 @@
1
- // Adapted from better-hub by Better Auth — https://github.com/better-auth/better-hub
2
- // (apps/web/src/components/ui/input-group.tsx). Full credit to the Better Auth team.
3
-
4
- import type * as React from "react";
5
- import type { ComponentProps } from "react";
6
- import { cva, type VariantProps } from "class-variance-authority";
7
- import type { ClassProp } from "class-variance-authority/types";
8
-
9
- import { cn } from "../foundation/cn";
10
- import { Button } from "./button";
11
- import { Input } from "./input";
12
- import { Textarea } from "./textarea";
13
-
14
- function InputGroup({ className, ...props }: ComponentProps<"div">): React.JSX.Element {
15
- return (
16
- <div
17
- data-slot="input-group"
18
- role="group"
19
- className={cn(
20
- "group/input-group relative flex w-full items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none dark:bg-input/30",
21
- "h-9 min-w-0 has-[>textarea]:h-auto",
22
-
23
- // Variants based on alignment.
24
- "has-[>[data-align=inline-start]]:[&>input]:pl-2",
25
- "has-[>[data-align=inline-end]]:[&>input]:pr-2",
26
- "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
27
- "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
28
-
29
- // Focus state.
30
- "has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50",
31
-
32
- // Error state.
33
- "has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
34
-
35
- className,
36
- )}
37
- {...props}
38
- />
39
- );
1
+ import type * as React from 'react'
2
+ import type { ComponentProps } from 'react'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+ import type { ClassProp } from 'class-variance-authority/types'
5
+
6
+ import { cn } from '../foundation/cn'
7
+ import { Button } from './button'
8
+ import { Input } from './input'
9
+ import { Textarea } from './textarea'
10
+
11
+ function InputGroup({ className, ...props }: ComponentProps<'div'>): React.JSX.Element {
12
+ return (
13
+ <div
14
+ data-slot="input-group"
15
+ role="group"
16
+ className={cn(
17
+ 'group/input-group relative flex w-full items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none dark:bg-input/30',
18
+ 'h-9 min-w-0 has-[>textarea]:h-auto',
19
+ 'has-[>[data-align=inline-start]]:[&>input]:pl-2',
20
+ 'has-[>[data-align=inline-end]]:[&>input]:pr-2',
21
+ 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
22
+ 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
23
+ 'has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50',
24
+ 'has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40',
25
+
26
+ className,
27
+ )}
28
+ {...props}
29
+ />
30
+ )
40
31
  }
41
32
 
42
33
  type InputGroupAddonVariantsExternalApi = (
43
- props?:
44
- | ({
45
- align?: "inline-start" | "inline-end" | "block-start" | "block-end" | undefined;
46
- } & ClassProp)
47
- | undefined,
48
- ) => string;
34
+ props?:
35
+ | ({
36
+ align?: 'inline-start' | 'inline-end' | 'block-start' | 'block-end' | undefined
37
+ } & ClassProp)
38
+ | undefined,
39
+ ) => string
49
40
 
50
41
  const inputGroupAddonVariants: InputGroupAddonVariantsExternalApi = cva(
51
- "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
52
- {
53
- variants: {
54
- align: {
55
- "inline-start":
56
- "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
57
- "inline-end":
58
- "order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]",
59
- "block-start":
60
- "order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3",
61
- "block-end":
62
- "order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3",
63
- },
64
- },
65
- defaultVariants: {
66
- align: "inline-start",
67
- },
68
- },
69
- );
42
+ "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
43
+ {
44
+ variants: {
45
+ align: {
46
+ 'inline-start': 'order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]',
47
+ 'inline-end': 'order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]',
48
+ 'block-start':
49
+ 'order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3',
50
+ 'block-end':
51
+ 'order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3',
52
+ },
53
+ },
54
+ defaultVariants: {
55
+ align: 'inline-start',
56
+ },
57
+ },
58
+ )
70
59
 
71
60
  function InputGroupAddon({
72
- className,
73
- align = "inline-start",
74
- ...props
75
- }: ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>): React.JSX.Element {
76
- return (
77
- <div
78
- role="group"
79
- data-slot="input-group-addon"
80
- data-align={align}
81
- className={cn(inputGroupAddonVariants({ align }), className)}
82
- onClick={(event) => {
83
- const target = event.target;
84
- if (target instanceof HTMLElement && target.closest("button")) {
85
- return;
86
- }
87
- event.currentTarget.parentElement?.querySelector("input")?.focus();
88
- }}
89
- {...props}
90
- />
91
- );
61
+ className,
62
+ align = 'inline-start',
63
+ ...props
64
+ }: ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>): React.JSX.Element {
65
+ return (
66
+ <div
67
+ role="group"
68
+ data-slot="input-group-addon"
69
+ data-align={align}
70
+ className={cn(inputGroupAddonVariants({ align }), className)}
71
+ onClick={(event) => {
72
+ const target = event.target
73
+ if (target instanceof HTMLElement && target.closest('button')) {
74
+ return
75
+ }
76
+ event.currentTarget.parentElement?.querySelector('input')?.focus()
77
+ }}
78
+ {...props}
79
+ />
80
+ )
92
81
  }
93
82
 
94
83
  type InputGroupButtonVariantsExternalApi = (
95
- props?:
96
- | ({
97
- size?: "xs" | "sm" | "icon-xs" | "icon-sm" | undefined;
98
- } & ClassProp)
99
- | undefined,
100
- ) => string;
84
+ props?:
85
+ | ({
86
+ size?: 'xs' | 'sm' | 'icon-xs' | 'icon-sm' | undefined
87
+ } & ClassProp)
88
+ | undefined,
89
+ ) => string
101
90
 
102
91
  const inputGroupButtonVariants: InputGroupButtonVariantsExternalApi = cva(
103
- "flex items-center gap-2 text-sm shadow-none",
104
- {
105
- variants: {
106
- size: {
107
- xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
108
- sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
109
- "icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
110
- "icon-sm": "size-8 p-0 has-[>svg]:p-0",
111
- },
112
- },
113
- defaultVariants: {
114
- size: "xs",
115
- },
116
- });
92
+ 'flex items-center gap-2 text-sm shadow-none',
93
+ {
94
+ variants: {
95
+ size: {
96
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
97
+ sm: 'h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5',
98
+ 'icon-xs': 'size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
99
+ 'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
100
+ },
101
+ },
102
+ defaultVariants: {
103
+ size: 'xs',
104
+ },
105
+ },
106
+ )
117
107
 
118
108
  function InputGroupButton({
119
- className,
120
- type = "button",
121
- variant = "ghost",
122
- size = "xs",
123
- ...props
124
- }: Omit<ComponentProps<typeof Button>, "size"> &
125
- VariantProps<typeof inputGroupButtonVariants>): React.JSX.Element {
126
- return (
127
- <Button
128
- type={type}
129
- data-size={size}
130
- variant={variant}
131
- className={cn(inputGroupButtonVariants({ size }), className)}
132
- {...props}
133
- />
134
- );
109
+ className,
110
+ type = 'button',
111
+ variant = 'ghost',
112
+ size = 'xs',
113
+ ...props
114
+ }: Omit<ComponentProps<typeof Button>, 'size'> &
115
+ VariantProps<typeof inputGroupButtonVariants>): React.JSX.Element {
116
+ return (
117
+ <Button
118
+ type={type}
119
+ data-size={size}
120
+ variant={variant}
121
+ className={cn(inputGroupButtonVariants({ size }), className)}
122
+ {...props}
123
+ />
124
+ )
135
125
  }
136
126
 
137
- function InputGroupText({ className, ...props }: ComponentProps<"span">): React.JSX.Element {
138
- return (
139
- <span
140
- className={cn(
141
- "flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
142
- className,
143
- )}
144
- {...props}
145
- />
146
- );
127
+ function InputGroupText({ className, ...props }: ComponentProps<'span'>): React.JSX.Element {
128
+ return (
129
+ <span
130
+ className={cn(
131
+ "flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
132
+ className,
133
+ )}
134
+ {...props}
135
+ />
136
+ )
147
137
  }
148
138
 
149
- function InputGroupInput({ className, ...props }: ComponentProps<"input">): React.JSX.Element {
150
- return (
151
- <Input
152
- data-slot="input-group-control"
153
- className={cn(
154
- "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
155
- className,
156
- )}
157
- {...props}
158
- />
159
- );
139
+ function InputGroupInput({ className, ...props }: ComponentProps<'input'>): React.JSX.Element {
140
+ return (
141
+ <Input
142
+ data-slot="input-group-control"
143
+ className={cn(
144
+ 'flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',
145
+ className,
146
+ )}
147
+ {...props}
148
+ />
149
+ )
160
150
  }
161
151
 
162
- function InputGroupTextarea({ className, ...props }: ComponentProps<"textarea">): React.JSX.Element {
163
- return (
164
- <Textarea
165
- data-slot="input-group-control"
166
- className={cn(
167
- "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
168
- className,
169
- )}
170
- {...props}
171
- />
172
- );
152
+ function InputGroupTextarea({
153
+ className,
154
+ ...props
155
+ }: ComponentProps<'textarea'>): React.JSX.Element {
156
+ return (
157
+ <Textarea
158
+ data-slot="input-group-control"
159
+ className={cn(
160
+ 'flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent',
161
+ className,
162
+ )}
163
+ {...props}
164
+ />
165
+ )
173
166
  }
174
167
 
175
168
  export {
176
- InputGroup,
177
- InputGroupAddon,
178
- InputGroupButton,
179
- InputGroupText,
180
- InputGroupInput,
181
- InputGroupTextarea,
182
- };
169
+ InputGroup,
170
+ InputGroupAddon,
171
+ InputGroupButton,
172
+ InputGroupText,
173
+ InputGroupInput,
174
+ InputGroupTextarea,
175
+ }
@@ -1,25 +1,22 @@
1
- // Adapted from better-hub by Better Auth — https://github.com/better-auth/better-hub
2
- // (apps/web/src/components/ui/input.tsx). Full credit to the Better Auth team.
1
+ import type * as React from 'react'
2
+ import type { ComponentProps } from 'react'
3
3
 
4
- import type * as React from "react";
5
- import type { ComponentProps } from 'react';
6
-
7
- import { cn } from '../foundation/cn';
4
+ import { cn } from '../foundation/cn'
8
5
 
9
6
  function Input({ className, type, ...props }: ComponentProps<'input'>): React.JSX.Element {
10
- return (
11
- <input
12
- type={type}
13
- data-slot="input"
14
- className={cn(
15
- "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
16
- "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
17
- "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
18
- className,
19
- )}
20
- {...props}
21
- />
22
- );
7
+ return (
8
+ <input
9
+ type={type}
10
+ data-slot="input"
11
+ className={cn(
12
+ 'h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30',
13
+ 'focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
14
+ 'aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40',
15
+ className,
16
+ )}
17
+ {...props}
18
+ />
19
+ )
23
20
  }
24
21
 
25
- export { Input };
22
+ export { Input }
@@ -1,93 +1,92 @@
1
- // Adapted from better-hub by Better Auth — https://github.com/better-auth/better-hub
2
- // (apps/web/src/components/ui/live-duration.tsx). Full credit to the Better Auth team.
1
+ import { DateTime, Option } from 'effect'
2
+ import type * as React from 'react'
3
+ import { useState, useEffect } from 'react'
3
4
 
4
- import { DateTime, Option } from "effect";
5
- import type * as React from "react";
6
- import { useState, useEffect } from "react";
7
-
8
- const MS_PER_SECOND = 1000;
9
- const SECONDS_PER_HOUR = 3600;
10
- const SECONDS_PER_MINUTE = 60;
11
- const TICK_INTERVAL_MS = 1000;
5
+ const MS_PER_SECOND = 1000
6
+ const SECONDS_PER_HOUR = 3600
7
+ const SECONDS_PER_MINUTE = 60
8
+ const TICK_INTERVAL_MS = 1000
12
9
 
13
10
  interface FormatDurationInputExternalApi {
14
- startedAt: string | null;
15
- completedAt: string | null;
11
+ startedAt: string | null
12
+ completedAt: string | null
16
13
  }
17
14
 
18
- // Inlined from "@/lib/utils" (formatDuration) — only this helper is used here.
19
15
  function formatDuration({ startedAt, completedAt }: FormatDurationInputExternalApi): string {
20
- if (!startedAt) {
21
- return "";
22
- }
23
- const start = DateTime.unsafeMake(startedAt);
24
- const end = completedAt ? DateTime.unsafeMake(completedAt) : DateTime.unsafeNow();
25
- const elapsedMs = DateTime.toEpochMillis(end) - DateTime.toEpochMillis(start);
26
- const totalSeconds = Math.max(0, Math.floor(elapsedMs / MS_PER_SECOND));
27
- const hours = Math.floor(totalSeconds / SECONDS_PER_HOUR);
28
- const minutes = Math.floor((totalSeconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
29
- const seconds = totalSeconds % SECONDS_PER_MINUTE;
30
- if (hours > 0) {
31
- return `${hours}h ${minutes}m`;
32
- }
33
- if (minutes > 0) {
34
- return `${minutes}m ${seconds}s`;
35
- }
36
- return `${seconds}s`;
16
+ if (!startedAt) {
17
+ return ''
18
+ }
19
+ const start = DateTime.unsafeMake(startedAt)
20
+ const end = completedAt ? DateTime.unsafeMake(completedAt) : DateTime.unsafeNow()
21
+ const elapsedMs = DateTime.toEpochMillis(end) - DateTime.toEpochMillis(start)
22
+ const totalSeconds = Math.max(0, Math.floor(elapsedMs / MS_PER_SECOND))
23
+ const hours = Math.floor(totalSeconds / SECONDS_PER_HOUR)
24
+ const minutes = Math.floor((totalSeconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE)
25
+ const seconds = totalSeconds % SECONDS_PER_MINUTE
26
+ if (hours > 0) {
27
+ return `${hours}h ${minutes}m`
28
+ }
29
+ if (minutes > 0) {
30
+ return `${minutes}m ${seconds}s`
31
+ }
32
+ return `${seconds}s`
37
33
  }
38
34
 
39
- // Inlined from "@/lib/live-tick".
40
- // Shared tick for LiveDuration components. One interval drives all subscribers
41
- // instead of each component running its own 1s interval.
42
- const callbacks = new Set<() => void>();
35
+ // shared tick: one interval drives all LiveDuration subscribers
36
+ const callbacks = new Set<() => void>()
43
37
  const tickState: { intervalId: Option.Option<ReturnType<typeof setInterval>> } = {
44
- intervalId: Option.none(),
45
- };
38
+ intervalId: Option.none(),
39
+ }
46
40
 
47
41
  function subscribeLiveTick(callback: () => void): () => void {
48
- callbacks.add(callback);
49
- if (Option.isNone(tickState.intervalId)) {
50
- // oxlint-disable-next-line reform-rules/no-set-timeout-interval -- browser-timer seam: shared render ticker for React, no Effect runtime here
51
- tickState.intervalId = Option.some(setInterval(() => {
52
- callbacks.forEach((cb) => cb());
53
- }, TICK_INTERVAL_MS));
54
- }
55
- return () => {
56
- callbacks.delete(callback);
57
- if (callbacks.size === 0 && Option.isSome(tickState.intervalId)) {
58
- clearInterval(tickState.intervalId.value);
59
- tickState.intervalId = Option.none();
60
- }
61
- };
42
+ callbacks.add(callback)
43
+ if (Option.isNone(tickState.intervalId)) {
44
+ tickState.intervalId = Option.some(
45
+ // oxlint-disable-next-line reform-rules/no-set-timeout-interval -- browser-timer seam: shared render ticker for React, no Effect runtime here
46
+ setInterval(() => {
47
+ callbacks.forEach((cb) => cb())
48
+ }, TICK_INTERVAL_MS),
49
+ )
50
+ }
51
+ return () => {
52
+ callbacks.delete(callback)
53
+ if (callbacks.size === 0 && Option.isSome(tickState.intervalId)) {
54
+ clearInterval(tickState.intervalId.value)
55
+ tickState.intervalId = Option.none()
56
+ }
57
+ }
62
58
  }
63
59
 
64
60
  interface LiveDurationPropsExternalApi {
65
- startedAt: string | null;
66
- completedAt?: string | null;
67
- className?: string;
61
+ startedAt: string | null
62
+ completedAt?: string | null
63
+ className?: string
68
64
  }
69
65
 
70
- export function LiveDuration({ startedAt, completedAt, className }: LiveDurationPropsExternalApi): React.ReactNode {
71
- // tick forces re-renders when subscribeLiveTick fires; value is unused in render
72
- const [, setTick] = useState(0);
66
+ export function LiveDuration({
67
+ startedAt,
68
+ completedAt,
69
+ className,
70
+ }: LiveDurationPropsExternalApi): React.ReactNode {
71
+ const [, setTick] = useState(0)
73
72
 
74
- useEffect(() => {
75
- if (!startedAt || completedAt != null) {
76
- return;
77
- }
78
- setTick(0);
79
- return subscribeLiveTick(() => setTick((prev) => prev + 1));
80
- }, [startedAt, completedAt]);
73
+ useEffect(() => {
74
+ if (!startedAt || completedAt != null) {
75
+ return
76
+ }
77
+ setTick(0)
78
+ return subscribeLiveTick(() => setTick((prev) => prev + 1))
79
+ }, [startedAt, completedAt])
81
80
 
82
- if (!startedAt) {
83
- return null;
84
- }
81
+ if (!startedAt) {
82
+ return null
83
+ }
85
84
 
86
- const formatted = formatDuration({ startedAt, completedAt: completedAt ?? null });
85
+ const formatted = formatDuration({ startedAt, completedAt: completedAt ?? null })
87
86
 
88
- return (
89
- <span className={className} suppressHydrationWarning>
90
- {formatted}
91
- </span>
92
- );
87
+ return (
88
+ <span className={className} suppressHydrationWarning>
89
+ {formatted}
90
+ </span>
91
+ )
93
92
  }
@@ -1,24 +1,18 @@
1
- // Adapted from better-hub by Better Auth — https://github.com/better-auth/better-hub
2
- // (apps/web/src/components/ui/logo.tsx). Full credit to the Better Auth team.
3
- import type * as React from "react";
4
- import { cn } from '../foundation/cn';
1
+ import type * as React from 'react'
2
+ import { cn } from '../foundation/cn'
5
3
 
6
4
  interface LogoPropsExternalApi {
7
- className?: string;
5
+ className?: string
8
6
  }
9
7
 
10
8
  export function Logo({ className }: LogoPropsExternalApi): React.JSX.Element {
11
- return (
12
- <span className={cn("font-mono text-sm font-medium tracking-tight", className)}>
13
- BETTER-HUB.
14
- </span>
15
- );
9
+ return (
10
+ <span className={cn('font-mono text-sm font-medium tracking-tight', className)}>
11
+ BETTER-HUB.
12
+ </span>
13
+ )
16
14
  }
17
15
 
18
16
  export function LogoMark({ className }: LogoPropsExternalApi): React.JSX.Element {
19
- return (
20
- <span className={cn("font-mono text-sm font-bold tracking-tight", className)}>
21
- b.
22
- </span>
23
- );
17
+ return <span className={cn('font-mono text-sm font-bold tracking-tight', className)}>b.</span>
24
18
  }