@dub/ui 0.0.8 → 0.0.10
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 +11 -0
- package/dist/accordion.d.mts +9 -0
- package/dist/accordion.mjs +1 -1
- package/dist/avatar.d.mts +15 -0
- package/dist/avatar.mjs +1 -1
- package/dist/background.d.mts +5 -0
- package/dist/background.mjs +1 -1
- package/dist/badge.d.mts +12 -0
- package/dist/badge.mjs +1 -1
- package/dist/button.d.mts +13 -0
- package/dist/button.mjs +1 -1
- package/dist/chunk-2FLE5ENB.mjs +2 -0
- package/dist/chunk-2K4UXZ2O.mjs +2 -0
- package/dist/chunk-34KNHUS2.mjs +8 -0
- package/dist/chunk-3BKA5UEZ.mjs +2 -0
- package/dist/chunk-3P45QYZN.mjs +3 -0
- package/dist/chunk-3Y5WGFFC.mjs +2 -0
- package/dist/chunk-4GBYDO2W.mjs +2 -0
- package/dist/chunk-4SI5X5GP.mjs +2 -0
- package/dist/chunk-4Y22ZONT.mjs +2 -0
- package/dist/chunk-ALFYYHAX.mjs +2 -0
- package/dist/chunk-AYEBTJIP.mjs +2 -0
- package/dist/chunk-B7YPSVHM.mjs +2 -0
- package/dist/chunk-BCILXFZH.mjs +2 -0
- package/dist/chunk-BPS3E7K6.mjs +2 -0
- package/dist/chunk-BZY4AURF.mjs +2 -0
- package/dist/chunk-C36I25XS.mjs +2 -0
- package/dist/chunk-DL45ZZDE.mjs +2 -0
- package/dist/chunk-FO6VIUXZ.mjs +2 -0
- package/dist/chunk-FRGZUJQA.mjs +2 -0
- package/dist/chunk-HVUZJJ5O.mjs +2 -0
- package/dist/chunk-HZBYDQAF.mjs +2 -0
- package/dist/chunk-IMRGY4OW.mjs +2 -0
- package/dist/chunk-J2NIO4NV.mjs +2 -0
- package/dist/chunk-JF4XLNZS.mjs +2 -0
- package/dist/chunk-KPHCANWX.mjs +2 -0
- package/dist/chunk-LMXROOMK.mjs +2 -0
- package/dist/chunk-MQPIKWNS.mjs +2 -0
- package/dist/chunk-N3JNQNDM.mjs +2 -0
- package/dist/chunk-NKUXJNX4.mjs +2 -0
- package/dist/chunk-OIIHWZYP.mjs +2 -0
- package/dist/chunk-OYLESSIG.mjs +2 -0
- package/dist/chunk-PG4Y6KIL.mjs +2 -0
- package/dist/chunk-PKQIORD7.mjs +2 -0
- package/dist/chunk-PRHSFG2M.mjs +2 -0
- package/dist/chunk-RNKR6YN2.mjs +2 -0
- package/dist/chunk-S32PKYSI.mjs +8 -0
- package/dist/chunk-TL4MBWLU.mjs +2 -0
- package/dist/chunk-WPUTXRJH.mjs +2 -0
- package/dist/chunk-WRYK2ZBF.mjs +2 -0
- package/dist/chunk-X4ANTLIN.mjs +2 -0
- package/dist/chunk-XG3NPZVV.mjs +2 -0
- package/dist/chunk-XQPGNFHA.mjs +2 -0
- package/dist/chunk-XRF5F4ZR.mjs +2 -0
- package/dist/chunk-XW75EZ3L.mjs +2 -0
- package/dist/copy-button.d.mts +8 -0
- package/dist/copy-button.mjs +1 -1
- package/dist/footer.d.mts +5 -0
- package/dist/footer.mjs +1 -1
- package/dist/form.d.mts +14 -0
- package/dist/form.mjs +1 -1
- package/dist/icon-menu.d.mts +10 -0
- package/dist/icon-menu.mjs +1 -1
- package/dist/icons/copy.d.mts +7 -0
- package/dist/icons/copy.mjs +1 -1
- package/dist/icons/expanding-arrow.d.mts +7 -0
- package/dist/icons/expanding-arrow.mjs +1 -1
- package/dist/icons/facebook.d.mts +8 -0
- package/dist/icons/facebook.mjs +1 -1
- package/dist/icons/github.d.mts +7 -0
- package/dist/icons/github.mjs +1 -1
- package/dist/icons/google.d.mts +7 -0
- package/dist/icons/google.mjs +1 -1
- package/dist/icons/index.d.mts +17 -0
- package/dist/icons/index.mjs +1 -1
- package/dist/icons/linkedin.d.mts +8 -0
- package/dist/icons/linkedin.mjs +1 -1
- package/dist/icons/loading-circle.d.mts +7 -0
- package/dist/icons/loading-circle.mjs +1 -1
- package/dist/icons/loading-dots.d.mts +5 -0
- package/dist/icons/loading-dots.mjs +1 -1
- package/dist/icons/loading-spinner.d.mts +7 -0
- package/dist/icons/loading-spinner.mjs +1 -1
- package/dist/icons/logo.d.mts +7 -0
- package/dist/icons/logo.mjs +1 -1
- package/dist/icons/logotype.d.mts +7 -0
- package/dist/icons/logotype.mjs +1 -1
- package/dist/icons/magic.d.mts +7 -0
- package/dist/icons/magic.mjs +1 -1
- package/dist/icons/photo.d.mts +7 -0
- package/dist/icons/photo.mjs +1 -1
- package/dist/icons/tick.d.mts +7 -0
- package/dist/icons/tick.mjs +1 -1
- package/dist/icons/twitter.d.mts +7 -0
- package/dist/icons/twitter.mjs +1 -1
- package/dist/icons/unsplash.d.mts +7 -0
- package/dist/icons/unsplash.mjs +1 -1
- package/dist/index.d.mts +69 -0
- package/dist/index.mjs +1 -1
- package/dist/link-preview.d.mts +7 -0
- package/dist/link-preview.mjs +1 -1
- package/dist/max-width-wrapper.d.mts +9 -0
- package/dist/max-width-wrapper.mjs +1 -1
- package/dist/modal.d.mts +14 -0
- package/dist/modal.mjs +1 -1
- package/dist/nav-mobile.d.mts +5 -0
- package/dist/nav-mobile.mjs +1 -1
- package/dist/nav.d.mts +9 -0
- package/dist/nav.mjs +1 -1
- package/dist/popover.d.mts +13 -0
- package/dist/popover.mjs +1 -1
- package/dist/switch.d.mts +14 -0
- package/dist/switch.mjs +1 -1
- package/dist/tab-select.d.mts +9 -0
- package/dist/tab-select.mjs +1 -1
- package/dist/tooltip.d.mts +32 -0
- package/dist/tooltip.mjs +1 -1
- package/package.json +13 -14
- package/.turbo/turbo-build.log +0 -123
- package/postcss.config.js +0 -9
- package/src/accordion.tsx +0 -60
- package/src/avatar.tsx +0 -47
- package/src/background.tsx +0 -71
- package/src/badge.tsx +0 -33
- package/src/button.tsx +0 -60
- package/src/content.ts +0 -34
- package/src/copy-button.tsx +0 -39
- package/src/footer.tsx +0 -204
- package/src/form.tsx +0 -77
- package/src/hooks/index.ts +0 -5
- package/src/hooks/use-current-anchor.ts +0 -65
- package/src/hooks/use-intersection-observer.ts +0 -41
- package/src/hooks/use-local-storage.ts +0 -24
- package/src/hooks/use-media-query.ts +0 -46
- package/src/hooks/use-scroll.ts +0 -21
- package/src/icon-menu.tsx +0 -15
- package/src/icons/copy.tsx +0 -18
- package/src/icons/expanding-arrow.tsx +0 -39
- package/src/icons/facebook.tsx +0 -23
- package/src/icons/github.tsx +0 -14
- package/src/icons/google.tsx +0 -12
- package/src/icons/index.tsx +0 -23
- package/src/icons/linkedin.tsx +0 -22
- package/src/icons/loading-circle.tsx +0 -25
- package/src/icons/loading-dots.tsx +0 -21
- package/src/icons/loading-spinner.tsx +0 -34
- package/src/icons/logo.tsx +0 -29
- package/src/icons/logotype.tsx +0 -51
- package/src/icons/magic.tsx +0 -30
- package/src/icons/photo.tsx +0 -20
- package/src/icons/tick.tsx +0 -18
- package/src/icons/twitter.tsx +0 -31
- package/src/icons/unsplash.tsx +0 -17
- package/src/index.tsx +0 -35
- package/src/link-preview.tsx +0 -111
- package/src/max-width-wrapper.tsx +0 -21
- package/src/modal.tsx +0 -102
- package/src/nav-mobile.tsx +0 -108
- package/src/nav.tsx +0 -205
- package/src/popover.tsx +0 -61
- package/src/styles.css +0 -3
- package/src/switch.tsx +0 -60
- package/src/tab-select.tsx +0 -27
- package/src/tooltip.tsx +0 -184
- package/tailwind.config.ts +0 -9
- package/tsconfig.json +0 -5
- package/tsup.config.ts +0 -15
package/src/footer.tsx
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { ALL_TOOLS } from "@dub/utils";
|
|
4
|
-
import va from "@vercel/analytics";
|
|
5
|
-
import Link from "next/link";
|
|
6
|
-
import { useParams } from "next/navigation";
|
|
7
|
-
import { FEATURES_LIST } from "./content";
|
|
8
|
-
import { Github, LinkedIn, LogoType, Twitter } from "./icons";
|
|
9
|
-
import { MaxWidthWrapper } from "./max-width-wrapper";
|
|
10
|
-
|
|
11
|
-
const navigation = {
|
|
12
|
-
features: FEATURES_LIST.map(({ shortTitle, slug }) => ({
|
|
13
|
-
name: shortTitle,
|
|
14
|
-
href: `/features/${slug}`,
|
|
15
|
-
})),
|
|
16
|
-
product: [
|
|
17
|
-
{ name: "Blog", href: "/blog" },
|
|
18
|
-
{ name: "Changelog", href: "/changelog" },
|
|
19
|
-
{ name: "Customer Stories", href: "/customers" },
|
|
20
|
-
{ name: "Help Center", href: "/help" },
|
|
21
|
-
{ name: "Pricing", href: "/pricing" },
|
|
22
|
-
],
|
|
23
|
-
tools: ALL_TOOLS.map(({ name, slug }) => ({
|
|
24
|
-
name,
|
|
25
|
-
href: `/tools/${slug}`,
|
|
26
|
-
})),
|
|
27
|
-
legal: [
|
|
28
|
-
{ name: "Privacy", href: "/privacy" },
|
|
29
|
-
{ name: "Terms", href: "/terms" },
|
|
30
|
-
{ name: "Abuse", href: "/abuse" },
|
|
31
|
-
],
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export function Footer() {
|
|
35
|
-
const { domain = "dub.co" } = useParams() as { domain: string };
|
|
36
|
-
|
|
37
|
-
const createHref = (href: string) =>
|
|
38
|
-
domain === "dub.co" ? href : `https://dub.co${href}`;
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<footer className="z-10 border-t border-gray-200 bg-white/50 py-8 backdrop-blur-lg">
|
|
42
|
-
<MaxWidthWrapper className="pt-10">
|
|
43
|
-
<div className="xl:grid xl:grid-cols-5 xl:gap-8">
|
|
44
|
-
<div className="space-y-8 xl:col-span-2">
|
|
45
|
-
<Link
|
|
46
|
-
href={createHref("/")}
|
|
47
|
-
{...(domain !== "dub.co" && {
|
|
48
|
-
onClick: () => {
|
|
49
|
-
va.track("Referred from custom domain", {
|
|
50
|
-
domain,
|
|
51
|
-
medium: `footer item (logo)`,
|
|
52
|
-
});
|
|
53
|
-
},
|
|
54
|
-
})}
|
|
55
|
-
>
|
|
56
|
-
<span className="sr-only">Dub.co Logo</span>
|
|
57
|
-
<LogoType className="h-7 text-gray-600" />
|
|
58
|
-
</Link>
|
|
59
|
-
<p className="max-w-xs text-sm text-gray-500">
|
|
60
|
-
Giving modern marketing teams superpowers with short links that
|
|
61
|
-
stand out.
|
|
62
|
-
</p>
|
|
63
|
-
<div className="flex items-center space-x-2">
|
|
64
|
-
<a
|
|
65
|
-
href="https://twitter.com/dubdotco"
|
|
66
|
-
target="_blank"
|
|
67
|
-
rel="noreferrer"
|
|
68
|
-
className="group rounded-md p-2 transition-colors hover:bg-gray-100 active:bg-gray-200"
|
|
69
|
-
>
|
|
70
|
-
<span className="sr-only">Twitter</span>
|
|
71
|
-
<Twitter className="h-5 w-5 text-gray-600" />
|
|
72
|
-
</a>
|
|
73
|
-
<div className="h-8 border-l border-gray-200" />
|
|
74
|
-
<a
|
|
75
|
-
href="https://github.com/steven-tey/dub"
|
|
76
|
-
target="_blank"
|
|
77
|
-
rel="noreferrer"
|
|
78
|
-
className="rounded-md p-2 transition-colors hover:bg-gray-100 active:bg-gray-200"
|
|
79
|
-
>
|
|
80
|
-
<span className="sr-only">Github</span>
|
|
81
|
-
<Github className="h-5 w-5 text-gray-600" />
|
|
82
|
-
</a>
|
|
83
|
-
<div className="h-8 border-l border-gray-200" />
|
|
84
|
-
<a
|
|
85
|
-
href="https://www.linkedin.com/company/dubhq/"
|
|
86
|
-
target="_blank"
|
|
87
|
-
rel="noreferrer"
|
|
88
|
-
className="rounded-md p-2 transition-colors hover:bg-gray-100 active:bg-gray-200"
|
|
89
|
-
>
|
|
90
|
-
<span className="sr-only">LinkedIn</span>
|
|
91
|
-
<LinkedIn className="h-5 w-5" fill="#52525B" />
|
|
92
|
-
</a>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
<div className="mt-16 grid grid-cols-2 gap-8 xl:col-span-3 xl:mt-0">
|
|
96
|
-
<div className="md:grid md:grid-cols-2 md:gap-8">
|
|
97
|
-
<div>
|
|
98
|
-
<h3 className="text-sm font-semibold text-gray-900">
|
|
99
|
-
Features
|
|
100
|
-
</h3>
|
|
101
|
-
<ul role="list" className="mt-4 space-y-4">
|
|
102
|
-
{navigation.features.map((item) => (
|
|
103
|
-
<li key={item.name}>
|
|
104
|
-
<Link
|
|
105
|
-
href={createHref(item.href)}
|
|
106
|
-
{...(domain !== "dub.co" && {
|
|
107
|
-
onClick: () => {
|
|
108
|
-
va.track("Referred from custom domain", {
|
|
109
|
-
domain,
|
|
110
|
-
medium: `footer item (${item.name})`,
|
|
111
|
-
});
|
|
112
|
-
},
|
|
113
|
-
})}
|
|
114
|
-
className="text-sm text-gray-500 hover:text-gray-900"
|
|
115
|
-
>
|
|
116
|
-
{item.name}
|
|
117
|
-
</Link>
|
|
118
|
-
</li>
|
|
119
|
-
))}
|
|
120
|
-
</ul>
|
|
121
|
-
</div>
|
|
122
|
-
<div className="mt-10 md:mt-0">
|
|
123
|
-
<h3 className="text-sm font-semibold text-gray-600">Product</h3>
|
|
124
|
-
<ul role="list" className="mt-4 space-y-4">
|
|
125
|
-
{navigation.product.map((item) => (
|
|
126
|
-
<li key={item.name}>
|
|
127
|
-
<Link
|
|
128
|
-
href={createHref(item.href)}
|
|
129
|
-
{...(domain !== "dub.co" && {
|
|
130
|
-
onClick: () => {
|
|
131
|
-
va.track("Referred from custom domain", {
|
|
132
|
-
domain,
|
|
133
|
-
medium: `footer item (${item.name})`,
|
|
134
|
-
});
|
|
135
|
-
},
|
|
136
|
-
})}
|
|
137
|
-
className="text-sm text-gray-500 hover:text-gray-900"
|
|
138
|
-
>
|
|
139
|
-
{item.name}
|
|
140
|
-
</Link>
|
|
141
|
-
</li>
|
|
142
|
-
))}
|
|
143
|
-
</ul>
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
<div className="md:grid md:grid-cols-2 md:gap-8">
|
|
147
|
-
<div>
|
|
148
|
-
<h3 className="text-sm font-semibold text-gray-600">Tools</h3>
|
|
149
|
-
<ul role="list" className="mt-4 space-y-4">
|
|
150
|
-
{navigation.tools.map((item) => (
|
|
151
|
-
<li key={item.name}>
|
|
152
|
-
<Link
|
|
153
|
-
href={createHref(item.href)}
|
|
154
|
-
{...(domain !== "dub.co" && {
|
|
155
|
-
onClick: () => {
|
|
156
|
-
va.track("Referred from custom domain", {
|
|
157
|
-
domain,
|
|
158
|
-
medium: `footer item (${item.name})`,
|
|
159
|
-
});
|
|
160
|
-
},
|
|
161
|
-
})}
|
|
162
|
-
className="text-sm text-gray-500 hover:text-gray-900"
|
|
163
|
-
>
|
|
164
|
-
{item.name}
|
|
165
|
-
</Link>
|
|
166
|
-
</li>
|
|
167
|
-
))}
|
|
168
|
-
</ul>
|
|
169
|
-
</div>
|
|
170
|
-
<div className="mt-10 md:mt-0">
|
|
171
|
-
<h3 className="text-sm font-semibold text-gray-600">Legal</h3>
|
|
172
|
-
<ul role="list" className="mt-4 space-y-4">
|
|
173
|
-
{navigation.legal.map((item) => (
|
|
174
|
-
<li key={item.name}>
|
|
175
|
-
<Link
|
|
176
|
-
href={createHref(item.href)}
|
|
177
|
-
{...(domain !== "dub.co" && {
|
|
178
|
-
onClick: () => {
|
|
179
|
-
va.track("Referred from custom domain", {
|
|
180
|
-
domain,
|
|
181
|
-
medium: `footer item (${item.name})`,
|
|
182
|
-
});
|
|
183
|
-
},
|
|
184
|
-
})}
|
|
185
|
-
className="text-sm text-gray-500 hover:text-gray-900"
|
|
186
|
-
>
|
|
187
|
-
{item.name}
|
|
188
|
-
</Link>
|
|
189
|
-
</li>
|
|
190
|
-
))}
|
|
191
|
-
</ul>
|
|
192
|
-
</div>
|
|
193
|
-
</div>
|
|
194
|
-
</div>
|
|
195
|
-
</div>
|
|
196
|
-
<div className="mt-16 border-t border-gray-900/10 pt-8 sm:mt-20 lg:mt-24">
|
|
197
|
-
<p className="text-sm leading-5 text-gray-500">
|
|
198
|
-
© {new Date().getFullYear()} Dub.co
|
|
199
|
-
</p>
|
|
200
|
-
</div>
|
|
201
|
-
</MaxWidthWrapper>
|
|
202
|
-
</footer>
|
|
203
|
-
);
|
|
204
|
-
}
|
package/src/form.tsx
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { cn } from "@dub/utils";
|
|
2
|
-
import { InputHTMLAttributes, ReactNode, useMemo, useState } from "react";
|
|
3
|
-
import { Button } from "./button";
|
|
4
|
-
|
|
5
|
-
export function Form({
|
|
6
|
-
title,
|
|
7
|
-
description,
|
|
8
|
-
inputData,
|
|
9
|
-
helpText,
|
|
10
|
-
buttonText = "Save Changes",
|
|
11
|
-
disabledTooltip,
|
|
12
|
-
handleSubmit,
|
|
13
|
-
}: {
|
|
14
|
-
title: string;
|
|
15
|
-
description: string;
|
|
16
|
-
inputData: InputHTMLAttributes<HTMLInputElement>;
|
|
17
|
-
helpText?: string;
|
|
18
|
-
buttonText?: string;
|
|
19
|
-
disabledTooltip?: string | ReactNode;
|
|
20
|
-
handleSubmit: (data: any) => Promise<any>;
|
|
21
|
-
}) {
|
|
22
|
-
const [value, setValue] = useState(inputData.defaultValue);
|
|
23
|
-
const [saving, setSaving] = useState(false);
|
|
24
|
-
const saveDisabled = useMemo(() => {
|
|
25
|
-
return saving || !value || value === inputData.defaultValue;
|
|
26
|
-
}, [saving, value, inputData.defaultValue]);
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<form
|
|
30
|
-
onSubmit={async (e) => {
|
|
31
|
-
e.preventDefault();
|
|
32
|
-
setSaving(true);
|
|
33
|
-
await handleSubmit({
|
|
34
|
-
[inputData.name as string]: value,
|
|
35
|
-
});
|
|
36
|
-
setSaving(false);
|
|
37
|
-
}}
|
|
38
|
-
className="rounded-lg border border-gray-200 bg-white"
|
|
39
|
-
>
|
|
40
|
-
<div className="relative flex flex-col space-y-6 p-5 sm:p-10">
|
|
41
|
-
<div className="flex flex-col space-y-3">
|
|
42
|
-
<h2 className="text-xl font-medium">{title}</h2>
|
|
43
|
-
<p className="text-sm text-gray-500">{description}</p>
|
|
44
|
-
</div>
|
|
45
|
-
{typeof inputData.defaultValue === "string" ? (
|
|
46
|
-
<input
|
|
47
|
-
{...inputData}
|
|
48
|
-
type="text"
|
|
49
|
-
required
|
|
50
|
-
disabled={disabledTooltip ? true : false}
|
|
51
|
-
onChange={(e) => setValue(e.target.value)}
|
|
52
|
-
className={cn(
|
|
53
|
-
"w-full max-w-md rounded-md border border-gray-300 text-gray-900 placeholder-gray-300 focus:border-gray-500 focus:outline-none focus:ring-gray-500 sm:text-sm",
|
|
54
|
-
{
|
|
55
|
-
"cursor-not-allowed bg-gray-100 text-gray-400": disabledTooltip,
|
|
56
|
-
},
|
|
57
|
-
)}
|
|
58
|
-
/>
|
|
59
|
-
) : (
|
|
60
|
-
<div className="h-[2.35rem] w-full max-w-md animate-pulse rounded-md bg-gray-200" />
|
|
61
|
-
)}
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
<div className="flex items-center justify-between rounded-b-lg border-t border-gray-200 bg-gray-50 p-3 sm:px-10">
|
|
65
|
-
<p className="text-sm text-gray-500">{helpText}</p>
|
|
66
|
-
<div>
|
|
67
|
-
<Button
|
|
68
|
-
text={buttonText}
|
|
69
|
-
loading={saving}
|
|
70
|
-
disabled={saveDisabled}
|
|
71
|
-
disabledTooltip={disabledTooltip}
|
|
72
|
-
/>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</form>
|
|
76
|
-
);
|
|
77
|
-
}
|
package/src/hooks/index.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { default as useCurrentAnchor } from "./use-current-anchor";
|
|
2
|
-
export { default as useIntersectionObserver } from "./use-intersection-observer";
|
|
3
|
-
export { default as useLocalStorage } from "./use-local-storage";
|
|
4
|
-
export { default as useMediaQuery } from "./use-media-query";
|
|
5
|
-
export { default as useScroll } from "./use-scroll";
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export default function useCurrentAnchor() {
|
|
4
|
-
const [currentAnchor, setCurrentAnchor] = useState<string | null>(null);
|
|
5
|
-
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
const mdxContainer: HTMLElement | null = document.querySelector(
|
|
8
|
-
"[data-mdx-container]",
|
|
9
|
-
);
|
|
10
|
-
if (!mdxContainer) return;
|
|
11
|
-
|
|
12
|
-
const offsetTop = mdxContainer.offsetTop - 1;
|
|
13
|
-
|
|
14
|
-
const observer = new IntersectionObserver(
|
|
15
|
-
(entries) => {
|
|
16
|
-
let currentEntry = entries[0];
|
|
17
|
-
if (!currentEntry) return;
|
|
18
|
-
|
|
19
|
-
const offsetBottom =
|
|
20
|
-
(currentEntry.rootBounds?.height || 0) * 0.3 + offsetTop;
|
|
21
|
-
|
|
22
|
-
for (let i = 1; i < entries.length; i++) {
|
|
23
|
-
const entry = entries[i];
|
|
24
|
-
if (!entry) break;
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
entry.boundingClientRect.top <
|
|
28
|
-
currentEntry.boundingClientRect.top ||
|
|
29
|
-
currentEntry.boundingClientRect.bottom < offsetTop
|
|
30
|
-
) {
|
|
31
|
-
currentEntry = entry;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let target: Element | undefined = currentEntry.target;
|
|
36
|
-
|
|
37
|
-
// if the target is too high up, we need to find the next sibling
|
|
38
|
-
while (target && target.getBoundingClientRect().bottom < offsetTop) {
|
|
39
|
-
target = siblings.get(target)?.next;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// if the target is too low, we need to find the previous sibling
|
|
43
|
-
while (target && target.getBoundingClientRect().top > offsetBottom) {
|
|
44
|
-
target = siblings.get(target)?.prev;
|
|
45
|
-
}
|
|
46
|
-
if (target) setCurrentAnchor(target.getAttribute("href"));
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
threshold: 1,
|
|
50
|
-
rootMargin: `-${offsetTop}px 0px 0px 0px`,
|
|
51
|
-
},
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
const siblings = new Map();
|
|
55
|
-
|
|
56
|
-
const anchors = mdxContainer?.querySelectorAll("[data-mdx-heading]");
|
|
57
|
-
anchors.forEach((anchor) => observer.observe(anchor));
|
|
58
|
-
|
|
59
|
-
return () => {
|
|
60
|
-
observer.disconnect();
|
|
61
|
-
};
|
|
62
|
-
}, []);
|
|
63
|
-
|
|
64
|
-
return currentAnchor?.replace("#", "");
|
|
65
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { RefObject, useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
interface Args extends IntersectionObserverInit {
|
|
4
|
-
freezeOnceVisible?: boolean;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export default function useIntersectionObserver(
|
|
8
|
-
elementRef: RefObject<Element>,
|
|
9
|
-
{
|
|
10
|
-
threshold = 0,
|
|
11
|
-
root = null,
|
|
12
|
-
rootMargin = "0%",
|
|
13
|
-
freezeOnceVisible = false,
|
|
14
|
-
}: Args,
|
|
15
|
-
): IntersectionObserverEntry | undefined {
|
|
16
|
-
const [entry, setEntry] = useState<IntersectionObserverEntry>();
|
|
17
|
-
|
|
18
|
-
const frozen = entry?.isIntersecting && freezeOnceVisible;
|
|
19
|
-
|
|
20
|
-
const updateEntry = ([entry]: IntersectionObserverEntry[]): void => {
|
|
21
|
-
setEntry(entry);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
const node = elementRef?.current; // DOM Ref
|
|
26
|
-
const hasIOSupport = !!window.IntersectionObserver;
|
|
27
|
-
|
|
28
|
-
if (!hasIOSupport || frozen || !node) return;
|
|
29
|
-
|
|
30
|
-
const observerParams = { threshold, root, rootMargin };
|
|
31
|
-
const observer = new IntersectionObserver(updateEntry, observerParams);
|
|
32
|
-
|
|
33
|
-
observer.observe(node);
|
|
34
|
-
|
|
35
|
-
return () => observer.disconnect();
|
|
36
|
-
|
|
37
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
38
|
-
}, [elementRef, JSON.stringify(threshold), root, rootMargin, frozen]);
|
|
39
|
-
|
|
40
|
-
return entry;
|
|
41
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export default function useLocalStorage<T>(
|
|
4
|
-
key: string,
|
|
5
|
-
initialValue: T,
|
|
6
|
-
): [T, (value: T) => void] {
|
|
7
|
-
const [storedValue, setStoredValue] = useState(initialValue);
|
|
8
|
-
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
// Retrieve from localStorage
|
|
11
|
-
const item = window.localStorage.getItem(key);
|
|
12
|
-
if (item) {
|
|
13
|
-
setStoredValue(JSON.parse(item));
|
|
14
|
-
}
|
|
15
|
-
}, [key]);
|
|
16
|
-
|
|
17
|
-
const setValue = (value: T) => {
|
|
18
|
-
// Save state
|
|
19
|
-
setStoredValue(value);
|
|
20
|
-
// Save to localStorage
|
|
21
|
-
window.localStorage.setItem(key, JSON.stringify(value));
|
|
22
|
-
};
|
|
23
|
-
return [storedValue, setValue];
|
|
24
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export default function useMediaQuery() {
|
|
4
|
-
const [device, setDevice] = useState<"mobile" | "tablet" | "desktop" | null>(
|
|
5
|
-
null,
|
|
6
|
-
);
|
|
7
|
-
const [dimensions, setDimensions] = useState<{
|
|
8
|
-
width: number;
|
|
9
|
-
height: number;
|
|
10
|
-
} | null>(null);
|
|
11
|
-
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
const checkDevice = () => {
|
|
14
|
-
if (window.matchMedia("(max-width: 640px)").matches) {
|
|
15
|
-
setDevice("mobile");
|
|
16
|
-
} else if (
|
|
17
|
-
window.matchMedia("(min-width: 641px) and (max-width: 1024px)").matches
|
|
18
|
-
) {
|
|
19
|
-
setDevice("tablet");
|
|
20
|
-
} else {
|
|
21
|
-
setDevice("desktop");
|
|
22
|
-
}
|
|
23
|
-
setDimensions({ width: window.innerWidth, height: window.innerHeight });
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// Initial detection
|
|
27
|
-
checkDevice();
|
|
28
|
-
|
|
29
|
-
// Listener for windows resize
|
|
30
|
-
window.addEventListener("resize", checkDevice);
|
|
31
|
-
|
|
32
|
-
// Cleanup listener
|
|
33
|
-
return () => {
|
|
34
|
-
window.removeEventListener("resize", checkDevice);
|
|
35
|
-
};
|
|
36
|
-
}, []);
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
device,
|
|
40
|
-
width: dimensions?.width,
|
|
41
|
-
height: dimensions?.height,
|
|
42
|
-
isMobile: device === "mobile",
|
|
43
|
-
isTablet: device === "tablet",
|
|
44
|
-
isDesktop: device === "desktop",
|
|
45
|
-
};
|
|
46
|
-
}
|
package/src/hooks/use-scroll.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export default function useScroll(threshold: number) {
|
|
4
|
-
const [scrolled, setScrolled] = useState(false);
|
|
5
|
-
|
|
6
|
-
const onScroll = useCallback(() => {
|
|
7
|
-
setScrolled(window.scrollY > threshold);
|
|
8
|
-
}, [threshold]);
|
|
9
|
-
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
window.addEventListener("scroll", onScroll);
|
|
12
|
-
return () => window.removeEventListener("scroll", onScroll);
|
|
13
|
-
}, [onScroll]);
|
|
14
|
-
|
|
15
|
-
// also check on first load
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
onScroll();
|
|
18
|
-
}, [onScroll]);
|
|
19
|
-
|
|
20
|
-
return scrolled;
|
|
21
|
-
}
|
package/src/icon-menu.tsx
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
interface MenuIconProps {
|
|
4
|
-
icon: ReactNode;
|
|
5
|
-
text: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function IconMenu({ icon, text }: MenuIconProps) {
|
|
9
|
-
return (
|
|
10
|
-
<div className="flex items-center justify-start space-x-2">
|
|
11
|
-
{icon}
|
|
12
|
-
<p className="text-sm">{text}</p>
|
|
13
|
-
</div>
|
|
14
|
-
);
|
|
15
|
-
}
|
package/src/icons/copy.tsx
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export default function Copy({ className }: { className?: string }) {
|
|
2
|
-
return (
|
|
3
|
-
<svg
|
|
4
|
-
fill="none"
|
|
5
|
-
shapeRendering="geometricPrecision"
|
|
6
|
-
stroke="currentColor"
|
|
7
|
-
strokeLinecap="round"
|
|
8
|
-
strokeLinejoin="round"
|
|
9
|
-
strokeWidth="1.5"
|
|
10
|
-
viewBox="0 0 24 24"
|
|
11
|
-
width="14"
|
|
12
|
-
height="14"
|
|
13
|
-
className={className}
|
|
14
|
-
>
|
|
15
|
-
<path d="M8 17.929H6c-1.105 0-2-.912-2-2.036V5.036C4 3.91 4.895 3 6 3h8c1.105 0 2 .911 2 2.036v1.866m-6 .17h8c1.105 0 2 .91 2 2.035v10.857C20 21.09 19.105 22 18 22h-8c-1.105 0-2-.911-2-2.036V9.107c0-1.124.895-2.036 2-2.036z" />
|
|
16
|
-
</svg>
|
|
17
|
-
);
|
|
18
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { cn } from "@dub/utils";
|
|
2
|
-
|
|
3
|
-
export default function ExpandingArrow({ className }: { className?: string }) {
|
|
4
|
-
return (
|
|
5
|
-
<div className="group relative flex items-center">
|
|
6
|
-
<svg
|
|
7
|
-
className={cn(
|
|
8
|
-
"absolute h-4 w-4 transition-all group-hover:translate-x-1 group-hover:opacity-0",
|
|
9
|
-
className,
|
|
10
|
-
)}
|
|
11
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
12
|
-
fill="currentColor"
|
|
13
|
-
viewBox="0 0 16 16"
|
|
14
|
-
width="16"
|
|
15
|
-
height="16"
|
|
16
|
-
>
|
|
17
|
-
<path
|
|
18
|
-
fillRule="evenodd"
|
|
19
|
-
d="M6.22 3.22a.75.75 0 011.06 0l4.25 4.25a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06-1.06L9.94 8 6.22 4.28a.75.75 0 010-1.06z"
|
|
20
|
-
></path>
|
|
21
|
-
</svg>
|
|
22
|
-
<svg
|
|
23
|
-
className={`${
|
|
24
|
-
className ? className : "h-4 w-4"
|
|
25
|
-
} absolute opacity-0 transition-all group-hover:translate-x-1 group-hover:opacity-100`}
|
|
26
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
27
|
-
fill="currentColor"
|
|
28
|
-
viewBox="0 0 16 16"
|
|
29
|
-
width="16"
|
|
30
|
-
height="16"
|
|
31
|
-
>
|
|
32
|
-
<path
|
|
33
|
-
fillRule="evenodd"
|
|
34
|
-
d="M8.22 2.97a.75.75 0 011.06 0l4.25 4.25a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06-1.06l2.97-2.97H3.75a.75.75 0 010-1.5h7.44L8.22 4.03a.75.75 0 010-1.06z"
|
|
35
|
-
></path>
|
|
36
|
-
</svg>
|
|
37
|
-
</div>
|
|
38
|
-
);
|
|
39
|
-
}
|
package/src/icons/facebook.tsx
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export default function Facebook({
|
|
2
|
-
className,
|
|
3
|
-
fill = "#1977f3",
|
|
4
|
-
}: {
|
|
5
|
-
className?: string;
|
|
6
|
-
fill?: string;
|
|
7
|
-
}) {
|
|
8
|
-
return (
|
|
9
|
-
<svg
|
|
10
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
-
width="1365.12"
|
|
12
|
-
height="1365.12"
|
|
13
|
-
viewBox="0 0 14222 14222"
|
|
14
|
-
className={className}
|
|
15
|
-
>
|
|
16
|
-
<circle cx="7111" cy="7112" r="7111" fill={fill} />
|
|
17
|
-
<path
|
|
18
|
-
d="M9879 9168l315-2056H8222V5778c0-562 275-1111 1159-1111h897V2917s-814-139-1592-139c-1624 0-2686 984-2686 2767v1567H4194v2056h1806v4969c362 57 733 86 1111 86s749-30 1111-86V9168z"
|
|
19
|
-
fill="#fff"
|
|
20
|
-
/>
|
|
21
|
-
</svg>
|
|
22
|
-
);
|
|
23
|
-
}
|
package/src/icons/github.tsx
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export default function Github({ className }: { className?: string }) {
|
|
2
|
-
return (
|
|
3
|
-
<svg
|
|
4
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
5
|
-
width="20"
|
|
6
|
-
height="20"
|
|
7
|
-
fill="currentColor"
|
|
8
|
-
viewBox="0 0 24 24"
|
|
9
|
-
className={className}
|
|
10
|
-
>
|
|
11
|
-
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
|
|
12
|
-
</svg>
|
|
13
|
-
);
|
|
14
|
-
}
|
package/src/icons/google.tsx
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export default function Google({ className }: { className?: string }) {
|
|
2
|
-
return (
|
|
3
|
-
<svg
|
|
4
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
5
|
-
viewBox="0 0 488 512"
|
|
6
|
-
fill="currentColor"
|
|
7
|
-
className={className}
|
|
8
|
-
>
|
|
9
|
-
<path d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z" />
|
|
10
|
-
</svg>
|
|
11
|
-
);
|
|
12
|
-
}
|
package/src/icons/index.tsx
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// custom icons
|
|
2
|
-
export { default as Copy } from "./copy";
|
|
3
|
-
export { default as ExpandingArrow } from "./expanding-arrow";
|
|
4
|
-
export { default as Magic } from "./magic";
|
|
5
|
-
export { default as Photo } from "./photo";
|
|
6
|
-
export { default as Tick } from "./tick";
|
|
7
|
-
|
|
8
|
-
// loaders
|
|
9
|
-
export { default as LoadingCircle } from "./loading-circle";
|
|
10
|
-
export { default as LoadingDots } from "./loading-dots";
|
|
11
|
-
export { default as LoadingSpinner } from "./loading-spinner";
|
|
12
|
-
|
|
13
|
-
// dub logos
|
|
14
|
-
export { default as Logo } from "./logo";
|
|
15
|
-
export { default as LogoType } from "./logotype";
|
|
16
|
-
|
|
17
|
-
// brand logos
|
|
18
|
-
export { default as Facebook } from "./facebook";
|
|
19
|
-
export { default as Github } from "./github";
|
|
20
|
-
export { default as Google } from "./google";
|
|
21
|
-
export { default as LinkedIn } from "./linkedin";
|
|
22
|
-
export { default as Twitter } from "./twitter";
|
|
23
|
-
export { default as Unsplash } from "./unsplash";
|
package/src/icons/linkedin.tsx
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export default function LinkedIn({
|
|
2
|
-
className,
|
|
3
|
-
fill = "#027ab5",
|
|
4
|
-
}: {
|
|
5
|
-
className?: string;
|
|
6
|
-
fill?: string;
|
|
7
|
-
}) {
|
|
8
|
-
return (
|
|
9
|
-
<svg
|
|
10
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
-
width="24"
|
|
12
|
-
height="24"
|
|
13
|
-
viewBox="0 0 24 24"
|
|
14
|
-
className={className}
|
|
15
|
-
>
|
|
16
|
-
<path
|
|
17
|
-
fill={fill}
|
|
18
|
-
d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"
|
|
19
|
-
/>
|
|
20
|
-
</svg>
|
|
21
|
-
);
|
|
22
|
-
}
|