feat(front): option popup

This commit is contained in:
Hexagonn
2024-11-02 09:04:38 +00:00
committed by GitHub
parent 26ba7d280b
commit 84c7be5689
14 changed files with 738 additions and 321 deletions

View File

@@ -16,6 +16,7 @@
"@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-popover": "^1.1.2", "@radix-ui/react-popover": "^1.1.2",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.3", "@radix-ui/react-tooltip": "^1.1.3",
"@types/escape-html": "^1.0.4", "@types/escape-html": "^1.0.4",

90
pnpm-lock.yaml generated
View File

@@ -26,6 +26,9 @@ importers:
'@radix-ui/react-popover': '@radix-ui/react-popover':
specifier: ^1.1.2 specifier: ^1.1.2
version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-select':
specifier: ^2.1.2
version: 2.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot': '@radix-ui/react-slot':
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0(@types/react@18.3.12)(react@18.3.1) version: 1.1.0(@types/react@18.3.12)(react@18.3.1)
@@ -456,6 +459,9 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'} engines: {node: '>=14'}
'@radix-ui/number@1.1.0':
resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==}
'@radix-ui/primitive@1.0.1': '@radix-ui/primitive@1.0.1':
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
@@ -488,6 +494,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-collection@1.1.0':
resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-compose-refs@1.0.1': '@radix-ui/react-compose-refs@1.0.1':
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
peerDependencies: peerDependencies:
@@ -559,6 +578,15 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-direction@1.1.0':
resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-dismissable-layer@1.0.5': '@radix-ui/react-dismissable-layer@1.0.5':
resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
peerDependencies: peerDependencies:
@@ -756,6 +784,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-select@2.1.2':
resolution: {integrity: sha512-rZJtWmorC7dFRi0owDmoijm6nSJH1tVw64QGiNIZ9PNLyBDtG+iAq+XGsya052At4BfarzY/Dhv9wrrUr6IMZA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-slot@1.0.2': '@radix-ui/react-slot@1.0.2':
resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
peerDependencies: peerDependencies:
@@ -2949,6 +2990,8 @@ snapshots:
'@pkgjs/parseargs@0.11.0': '@pkgjs/parseargs@0.11.0':
optional: true optional: true
'@radix-ui/number@1.1.0': {}
'@radix-ui/primitive@1.0.1': '@radix-ui/primitive@1.0.1':
dependencies: dependencies:
'@babel/runtime': 7.25.9 '@babel/runtime': 7.25.9
@@ -2980,6 +3023,18 @@ snapshots:
'@types/react': 18.3.12 '@types/react': 18.3.12
'@types/react-dom': 18.3.1 '@types/react-dom': 18.3.1
'@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-context': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot': 1.1.0(@types/react@18.3.12)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.12
'@types/react-dom': 18.3.1
'@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.12)(react@18.3.1)': '@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.12)(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.25.9 '@babel/runtime': 7.25.9
@@ -3057,6 +3112,12 @@ snapshots:
'@types/react': 18.3.12 '@types/react': 18.3.12
'@types/react-dom': 18.3.1 '@types/react-dom': 18.3.1
'@radix-ui/react-direction@1.1.0(@types/react@18.3.12)(react@18.3.1)':
dependencies:
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.12
'@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.25.9 '@babel/runtime': 7.25.9
@@ -3240,6 +3301,35 @@ snapshots:
'@types/react': 18.3.12 '@types/react': 18.3.12
'@types/react-dom': 18.3.1 '@types/react-dom': 18.3.1
'@radix-ui/react-select@2.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/number': 1.1.0
'@radix-ui/primitive': 1.1.0
'@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-direction': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-id': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-portal': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.12)(react@18.3.1)
'@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
aria-hidden: 1.2.4
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-remove-scroll: 2.6.0(@types/react@18.3.12)(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.12
'@types/react-dom': 18.3.1
'@radix-ui/react-slot@1.0.2(@types/react@18.3.12)(react@18.3.1)': '@radix-ui/react-slot@1.0.2(@types/react@18.3.12)(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.25.9 '@babel/runtime': 7.25.9

View File

@@ -115,3 +115,25 @@ body {
--radius: 0.5rem; --radius: 0.5rem;
} }
} }
/* width */
::-webkit-scrollbar {
width: 10px;
}
/* Track */
::-webkit-scrollbar-track {
background: #131313;
border-radius: 6px;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #525252;
border-radius: 6px;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #303030;
}

View File

@@ -4,6 +4,7 @@ import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogDescription, DialogDescription,
DialogFooter,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
@@ -17,12 +18,32 @@ import useSWR from "swr";
import { getUserCount, isUserMonitored } from "@/utils/actions"; import { getUserCount, isUserMonitored } from "@/utils/actions";
import { isSnowflake } from "@/utils/snowflake"; import { isSnowflake } from "@/utils/snowflake";
import Link from "next/link"; import Link from "next/link";
import { parameterInfo } from "@/utils/parameter";
import * as Icon from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Input } from "@/components/ui/input";
import { filterLetters } from "@/lib/utils";
import { Button } from "@/components/ui/button";
export default function Home() { export default function Home() {
const [userId, setUserId] = useState<null | string>(null); const [userId, setUserId] = useState<null | string>(null);
const [userError, setUserError] = useState<string | JSX.Element>(); const [userError, setUserError] = useState<string | JSX.Element>();
const [userData, setUserData] = useState<{ userId: string } | null>(null); const [userData, setUserData] = useState<{ userId: string } | null>(null);
const originUrl = useMemo(() => window.location.origin, []); const originUrl = useMemo(() => window.location?.origin, []);
const [copyState, setCopyState] = useState("Copy"); const [copyState, setCopyState] = useState("Copy");
const [outputType, setOutputType] = useState<"markdown" | "html" | "url">( const [outputType, setOutputType] = useState<"markdown" | "html" | "url">(
"markdown", "markdown",
@@ -30,6 +51,10 @@ export default function Home() {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [onImageLoaded, setOnImageLoaded] = useState(false); const [onImageLoaded, setOnImageLoaded] = useState(false);
const [option, setOption] = useState<
Array<{ name: string; value: string }>
>([]);
const userCount = useSWR("getUserCount", getUserCount); const userCount = useSWR("getUserCount", getUserCount);
const countRef = useRef<HTMLDivElement | null>(null); const countRef = useRef<HTMLDivElement | null>(null);
useSmoothCount({ useSmoothCount({
@@ -39,23 +64,26 @@ export default function Home() {
curve: [0, 1, 0, 1], curve: [0, 1, 0, 1],
}); });
const outputText = () => { const url = `${originUrl || "https://lanyard.cnrad.dev"}/api/${userData?.userId}${option.length > 0 ? `?${option.map((o) => `${o.name}=${o.value}`).join("&")}` : ""}`;
function outputText() {
if (outputType === "html") { if (outputType === "html") {
return `<a href="https://discord.com/users/${userData?.userId}"><img src="${originUrl || "https://lanyard.cnrad.dev"}/api/${userData?.userId}" /></a>`; return `<a href="https://discord.com/users/${userData?.userId}"><img src="${url}" /></a>`;
} else if (outputType === "url") { } else if (outputType === "url") {
return `${originUrl || "https://lanyard.cnrad.dev"}/api/${userData?.userId}`; return `${url}`;
} else { } else {
return `[![Discord Presence](${originUrl || "https://lanyard.cnrad.dev"}/api/${userData?.userId})](https://discord.com/users/${userData?.userId})`; return `[![Discord Presence](${url})](https://discord.com/users/${userData?.userId})`;
} }
}; }
const copy = () => {
function copy() {
navigator.clipboard.writeText(outputText()); navigator.clipboard.writeText(outputText());
setCopyState("Copied!"); setCopyState("Copied!");
setTimeout(() => setCopyState("Copy"), 1500); setTimeout(() => setCopyState("Copy"), 1500);
}; }
const submitDiscordId = async () => { async function submitDiscordId() {
setIsLoading(true); setIsLoading(true);
setOnImageLoaded(false); setOnImageLoaded(false);
setUserData(null); setUserData(null);
@@ -82,7 +110,115 @@ export default function Home() {
setUserData({ userId }); setUserData({ userId });
setIsLoading(false); setIsLoading(false);
}; }
function modifyOption(
data:
| {
type: "string";
name: string;
data: string;
event: React.ChangeEvent<HTMLInputElement>;
}
| {
type: "list";
name: string;
data: string;
}
| {
type: "boolean";
name: string;
data: string | boolean;
},
) {
if (data.type === "string") {
const filteredValue = filterLetters(
data.data,
(
parameterInfo.find(
(p) => p.type === "string" && p.parameter === data.name,
) as any
).options.omit,
);
setOption((prev) => {
if (data.data === "") {
return prev?.filter((o) => o.name !== data.name) || [];
} else {
if (prev?.find((o) => o.name === data.name)) {
return prev.map((o) => {
if (o.name === data.name) {
o.value = filteredValue;
}
return o;
});
} else {
return prev
? [
...prev,
{
name: data.name,
value: filteredValue,
},
]
: [
{
name: data.name,
value: filteredValue,
},
];
}
}
});
} else if (data.type === "list") {
setOption((prev) => {
if (prev?.find((o) => o.name === data.name)) {
return prev.map((o) => {
if (o.name === data.name) {
o.value = data.data;
}
return o;
});
} else {
return prev
? [...prev, { name: data.name, value: data.data }]
: [{ name: data.name, value: data.data }];
}
});
} else if (data.type === "boolean") {
setOption((prev) => {
if (prev?.find((o) => o.name === data.name)) {
return prev
.map((opt) => {
const options = parameterInfo.find(
(p) =>
p.type === "boolean" &&
p.parameter === data.name,
)?.options as { defaultBool?: boolean };
if (
data.data === (options?.defaultBool! || false)
) {
return null;
} else {
if (opt.name === data.name) {
opt.value = data.data.toString();
}
return opt;
}
})
.filter((opt) => opt !== null);
} else {
return prev
? [
...prev,
{ name: data.name, value: data.data.toString() },
]
: [{ name: data.name, value: data.data.toString() }];
}
});
}
}
return ( return (
<> <>
@@ -169,16 +305,165 @@ export default function Home() {
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle> <DialogTitle>Option</DialogTitle>
Are you absolutely sure?
</DialogTitle>
<DialogDescription> <DialogDescription>
This action cannot be undone. This Select an option to enable/disable
will permanently delete your account features to your Lanyard Profile
and remove your data from our
servers.
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
<div className="flex max-h-[75dvh] flex-col gap-4 overflow-x-hidden overflow-y-scroll rounded-xl bg-black/50 p-4 px-6 text-[#cecece]">
{parameterInfo.map((item, idx) => {
return (
<div
key={item.parameter}
className="flex flex-col gap-1"
>
<div className="flex items-center gap-1">
<p>{item.title}</p>
<TooltipProvider
delayDuration={100}
>
<Tooltip>
<TooltipTrigger
onFocus={(
e,
) => {
e.preventDefault();
}}
>
<Icon.HelpCircleIcon
size={
18
}
/>
</TooltipTrigger>
<TooltipContent>
<p>
{
item.description
}
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
{item.type === "string" && (
<Input
placeholder={
item.options
?.placeholder ||
"..."
}
onChange={(e) =>
modifyOption({
type: "string",
name: item.parameter,
data: e
.target
.value,
event: e,
})
}
value={
option?.find(
(o) =>
o.name ===
item.parameter,
)?.value || ""
}
/>
)}
{item.type ===
"boolean" && (
<Checkbox
onCheckedChange={(
bool,
) =>
modifyOption({
type: "boolean",
name: item.parameter,
data: bool,
})
}
checked={
option?.find(
(o) =>
o.name ===
item.parameter,
)?.value ===
"true"
? true
: option?.find(
(
o,
) =>
o.name ===
item.parameter,
)
?.value ===
"false"
? false
: item
.options
?.defaultBool ||
false
}
/>
)}
{item.type === "list" && (
<Select
onValueChange={(
val,
) =>
modifyOption({
type: "list",
name: item.parameter,
data: val,
})
}
value={
option?.find(
(o) =>
o.name ===
item.parameter,
)?.value || ""
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
{item.options.list.map(
(
option,
) => (
<SelectItem
value={
option.value
}
key={
option.value
}
>
{
option.name
}
</SelectItem>
),
)}
</SelectContent>
</Select>
)}
</div>
);
})}
</div>
<DialogFooter>
<Button onClick={() => setOption([])}>
Reset
</Button>
</DialogFooter>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</div> </div>
@@ -192,7 +477,7 @@ export default function Home() {
opacity: onImageLoaded ? 1 : 0, opacity: onImageLoaded ? 1 : 0,
}} }}
transition={{ duration: 0.5 }} transition={{ duration: 0.5 }}
src={`/api/${userData?.userId}`} src={url}
height={280} height={280}
width={500} width={500}
alt="Your Lanyard Banner" alt="Your Lanyard Banner"

View File

@@ -1,57 +1,57 @@
import * as React from "react" import * as React from "react";
import { Slot } from "@radix-ui/react-slot" import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority" import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-stone-950 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:focus-visible:ring-stone-300", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 focus-visible:ring-stone-300",
{ {
variants: { variants: {
variant: { variant: {
default: default:
"bg-stone-900 text-stone-50 shadow hover:bg-stone-900/90 dark:bg-stone-50 dark:text-stone-900 dark:hover:bg-stone-50/90", "shadow bg-stone-50 text-stone-900 hover:bg-stone-50/90",
destructive: destructive:
"bg-red-500 text-stone-50 shadow-sm hover:bg-red-500/90 dark:bg-red-900 dark:text-stone-50 dark:hover:bg-red-900/90", "shadow-sm bg-red-900 text-stone-50 hover:bg-red-900/90",
outline: outline:
"border border-stone-200 bg-white shadow-sm hover:bg-stone-100 hover:text-stone-900 dark:border-stone-800 dark:bg-stone-950 dark:hover:bg-stone-800 dark:hover:text-stone-50", "border shadow-sm text-stone-900 border-stone-800 bg-stone-950 hover:bg-stone-800 hover:text-stone-50",
secondary: secondary:
"bg-stone-100 text-stone-900 shadow-sm hover:bg-stone-100/80 dark:bg-stone-800 dark:text-stone-50 dark:hover:bg-stone-800/80", "shadow-sm bg-stone-800 text-stone-50 hover:bg-stone-800/80",
ghost: "hover:bg-stone-100 hover:text-stone-900 dark:hover:bg-stone-800 dark:hover:text-stone-50", ghost: "hover:bg-stone-800 hover:text-stone-50",
link: "text-stone-900 underline-offset-4 hover:underline dark:text-stone-50", link: "underline-offset-4 hover:underline text-stone-50",
}, },
size: { size: {
default: "h-9 px-4 py-2", default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs", sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8", lg: "h-10 rounded-md px-8",
icon: "h-9 w-9", icon: "h-9 w-9",
}, },
},
defaultVariants: {
variant: "default",
size: "default",
},
}, },
defaultVariants: { );
variant: "default",
size: "default",
},
}
)
export interface ButtonProps export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>, extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> { VariantProps<typeof buttonVariants> {
asChild?: boolean asChild?: boolean;
} }
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => { ({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button" const Comp = asChild ? Slot : "button";
return ( return (
<Comp <Comp
className={cn(buttonVariants({ variant, size, className }))} className={cn(buttonVariants({ variant, size, className }))}
ref={ref} ref={ref}
{...props} {...props}
/> />
) );
} },
) );
Button.displayName = "Button" Button.displayName = "Button";
export { Button, buttonVariants } export { Button, buttonVariants };

View File

@@ -1,30 +1,30 @@
"use client" "use client";
import * as React from "react" import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox" import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { CheckIcon } from "@radix-ui/react-icons" import { CheckIcon } from "@radix-ui/react-icons";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const Checkbox = React.forwardRef< const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>, React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<CheckboxPrimitive.Root <CheckboxPrimitive.Root
ref={ref} ref={ref}
className={cn( className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-stone-200 border-stone-900 shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-stone-950 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-stone-900 data-[state=checked]:text-stone-50 dark:border-stone-800 dark:border-stone-50 dark:focus-visible:ring-stone-300 dark:data-[state=checked]:bg-stone-50 dark:data-[state=checked]:text-stone-900", "peer h-4 w-4 shrink-0 rounded-sm border border-stone-50 border-stone-800 shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-stone-300 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-stone-50 data-[state=checked]:text-stone-900",
className className,
)} )}
{...props} {...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
> >
<CheckIcon className="h-4 w-4" /> <CheckboxPrimitive.Indicator
</CheckboxPrimitive.Indicator> className={cn("flex items-center justify-center text-current")}
</CheckboxPrimitive.Root> >
)) <CheckIcon className="h-4 w-4" />
Checkbox.displayName = CheckboxPrimitive.Root.displayName </CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
export { Checkbox } export { Checkbox };

View File

@@ -1,155 +0,0 @@
"use client"
import * as React from "react"
import { type DialogProps } from "@radix-ui/react-dialog"
import { MagnifyingGlassIcon } from "@radix-ui/react-icons"
import { Command as CommandPrimitive } from "cmdk"
import { cn } from "@/lib/utils"
import { Dialog, DialogContent } from "@/components/ui/dialog"
const Command = React.forwardRef<
React.ElementRef<typeof CommandPrimitive>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
>(({ className, ...props }, ref) => (
<CommandPrimitive
ref={ref}
className={cn(
"flex h-full w-full flex-col overflow-hidden rounded-md bg-white text-stone-950 dark:bg-stone-950 dark:text-stone-50",
className
)}
{...props}
/>
))
Command.displayName = CommandPrimitive.displayName
interface CommandDialogProps extends DialogProps {}
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0">
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-stone-500 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5 dark:[&_[cmdk-group-heading]]:text-stone-400">
{children}
</Command>
</DialogContent>
</Dialog>
)
}
const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
ref={ref}
className={cn(
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-stone-500 disabled:cursor-not-allowed disabled:opacity-50 dark:placeholder:text-stone-400",
className
)}
{...props}
/>
</div>
))
CommandInput.displayName = CommandPrimitive.Input.displayName
const CommandList = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.List>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, ...props }, ref) => (
<CommandPrimitive.List
ref={ref}
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
{...props}
/>
))
CommandList.displayName = CommandPrimitive.List.displayName
const CommandEmpty = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Empty>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
>((props, ref) => (
<CommandPrimitive.Empty
ref={ref}
className="py-6 text-center text-sm"
{...props}
/>
))
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
const CommandGroup = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Group
ref={ref}
className={cn(
"overflow-hidden p-1 text-stone-950 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-stone-500 dark:text-stone-50 dark:[&_[cmdk-group-heading]]:text-stone-400",
className
)}
{...props}
/>
))
CommandGroup.displayName = CommandPrimitive.Group.displayName
const CommandSeparator = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Separator
ref={ref}
className={cn("-mx-1 h-px bg-stone-200 dark:bg-stone-800", className)}
{...props}
/>
))
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
const CommandItem = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-stone-100 data-[selected=true]:text-stone-900 data-[disabled=true]:opacity-50 dark:data-[selected=true]:bg-stone-800 dark:data-[selected=true]:text-stone-50",
className
)}
{...props}
/>
))
CommandItem.displayName = CommandPrimitive.Item.displayName
const CommandShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-stone-500 dark:text-stone-400",
className
)}
{...props}
/>
)
}
CommandShortcut.displayName = "CommandShortcut"
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
}

View File

@@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
<DialogPrimitive.Overlay <DialogPrimitive.Overlay
ref={ref} ref={ref}
className={cn( className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80", "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className, className,
)} )}
{...props} {...props}
@@ -38,13 +38,16 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content <DialogPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-stone-800 bg-stone-950 p-6 shadow-lg duration-200 sm:rounded-lg", "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-stone-800 bg-stone-950 p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className, className,
)} )}
{...props} {...props}
> >
{children} {children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-stone-950 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-stone-300 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-stone-800 data-[state=open]:text-stone-400"> <DialogPrimitive.Close
tabIndex={1}
className="absolute right-4 top-4 rounded-sm text-stone-300 opacity-70 ring-offset-stone-950 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-stone-300 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-stone-800 data-[state=open]:text-stone-400"
>
<Cross2Icon className="h-4 w-4" /> <Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</DialogPrimitive.Close> </DialogPrimitive.Close>

View File

@@ -0,0 +1,25 @@
import * as React from "react";
import { cn } from "@/lib/utils";
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-stone-800 bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-stone-50 placeholder:text-stone-400 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-stone-300 disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
ref={ref}
{...props}
/>
);
},
);
Input.displayName = "Input";
export { Input };

View File

@@ -1,33 +0,0 @@
"use client"
import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"
import { cn } from "@/lib/utils"
const Popover = PopoverPrimitive.Root
const PopoverTrigger = PopoverPrimitive.Trigger
const PopoverAnchor = PopoverPrimitive.Anchor
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border border-stone-200 bg-white p-4 text-stone-950 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-stone-800 dark:bg-stone-950 dark:text-stone-50",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }

View File

@@ -0,0 +1,164 @@
"use client";
import * as React from "react";
import {
CaretSortIcon,
CheckIcon,
ChevronDownIcon,
ChevronUpIcon,
} from "@radix-ui/react-icons";
import * as SelectPrimitive from "@radix-ui/react-select";
import { cn } from "@/lib/utils";
const Select = SelectPrimitive.Root;
const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-stone-800 bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-stone-950 placeholder:text-stone-400 focus:outline-none focus:ring-1 focus:ring-stone-300 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className,
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<CaretSortIcon className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className,
)}
{...props}
>
<ChevronUpIcon />
</SelectPrimitive.ScrollUpButton>
));
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className,
)}
{...props}
>
<ChevronDownIcon />
</SelectPrimitive.ScrollDownButton>
));
SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-stone-800 bg-stone-950 text-stone-50 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className,
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
));
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
{...props}
/>
));
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-stone-800 focus:text-stone-50 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
>
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
));
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-stone-800", className)}
{...props}
/>
));
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
};

View File

@@ -1,32 +1,32 @@
"use client" "use client";
import * as React from "react" import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip" import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const TooltipProvider = TooltipPrimitive.Provider const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef< const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>, React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => ( >(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Portal> <TooltipPrimitive.Portal>
<TooltipPrimitive.Content <TooltipPrimitive.Content
ref={ref} ref={ref}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"z-50 overflow-hidden rounded-md bg-stone-900 px-3 py-1.5 text-xs text-stone-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:bg-stone-50 dark:text-stone-900", "z-50 overflow-hidden rounded-md bg-stone-900 px-3 py-1.5 text-xs text-stone-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className className,
)} )}
{...props} {...props}
/> />
</TooltipPrimitive.Portal> </TooltipPrimitive.Portal>
)) ));
TooltipContent.displayName = TooltipPrimitive.Content.displayName TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

View File

@@ -1,6 +1,13 @@
import { clsx, type ClassValue } from "clsx" import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge" import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs));
}
export function filterLetters(str: string, lettersToRemove: string[] = []) {
lettersToRemove.forEach((letter) => {
str = str.replaceAll(letter, "");
});
return str;
} }

View File

@@ -19,7 +19,7 @@ export type Parameters = {
idleMessage?: string; idleMessage?: string;
}; };
export const ParameterInfo: Array< export const parameterInfo: Array<
| { | {
parameter: string; parameter: string;
type: "boolean"; type: "boolean";
@@ -35,8 +35,8 @@ export const ParameterInfo: Array<
title: string; title: string;
description?: string; description?: string;
options?: { options?: {
prefix?: string; placeholder?: string;
suffix?: string; omit?: string[];
}; };
} }
| { | {
@@ -76,18 +76,20 @@ export const ParameterInfo: Array<
type: "string", type: "string",
title: "Background Color", title: "Background Color",
description: description:
"This will change the background color. Must be in hex format.", "This will change the background color. Must be in hex format. Omit the # symbol.",
options: { options: {
prefix: "#", placeholder: "1A1C1F",
omit: ["#"],
}, },
}, },
{ {
parameter: "borderRadius", parameter: "borderRadius",
type: "string", type: "string",
title: "Border Radius", title: "Border Radius",
description: "This will change the border radius of the card.", description:
"This will change the border radius of the card. Must have a size unit (px, rem, em, and more).",
options: { options: {
suffix: "px", placeholder: "10px",
}, },
}, },
{ {
@@ -106,20 +108,16 @@ export const ParameterInfo: Array<
title: "Idle Message", title: "Idle Message",
description: description:
"If you don't want the default \"I'm not currently doing anything!\" as your idle message, this is the right option.", "If you don't want the default \"I'm not currently doing anything!\" as your idle message, this is the right option.",
options: {
placeholder: "I'm not currently doing anything!",
},
}, },
{ {
parameter: "showDisplayName", parameter: "showDisplayName",
type: "boolean", type: "boolean",
title: "Show Display Name", title: "Show Display Name",
description: description:
"If you don't want to show your display name, this is the right option.", "If you'd like to show your global display name as well as your username, this is the right option.",
},
{
parameter: "hideDecoration",
type: "boolean",
title: "Hide Avatar Decoration",
description:
"If you don't want people seeing your Avatar Decoration, this is the right option.",
}, },
{ {
parameter: "animatedDecoration", parameter: "animatedDecoration",
@@ -131,6 +129,13 @@ export const ParameterInfo: Array<
defaultBool: true, defaultBool: true,
}, },
}, },
{
parameter: "hideDecoration",
type: "boolean",
title: "Hide Avatar Decoration",
description:
"If you don't want people seeing your Avatar Decoration, this is the right option.",
},
{ {
parameter: "hideStatus", parameter: "hideStatus",
type: "boolean", type: "boolean",
@@ -185,7 +190,10 @@ export const ParameterInfo: Array<
type: "string", type: "string",
title: "Hide App by ID", title: "Hide App by ID",
description: description:
"If you don't want display a specific application, this is the right option. IDs separate by `,`.", "If you don't want display a specific application, this is the right option. IDs separate by ','",
options: {
placeholder: "1302143410907648071, 1302132259368861759",
},
}, },
{ {
parameter: "hideDiscrim", parameter: "hideDiscrim",