mirror of
https://github.com/NohamR/lanyard-profile-readme.git
synced 2026-05-26 04:17:19 +00:00
feat(front): option popup
This commit is contained in:
321
src/app/page.tsx
321
src/app/page.tsx
@@ -4,6 +4,7 @@ import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
@@ -17,12 +18,32 @@ import useSWR from "swr";
|
||||
import { getUserCount, isUserMonitored } from "@/utils/actions";
|
||||
import { isSnowflake } from "@/utils/snowflake";
|
||||
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() {
|
||||
const [userId, setUserId] = useState<null | string>(null);
|
||||
const [userError, setUserError] = useState<string | JSX.Element>();
|
||||
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 [outputType, setOutputType] = useState<"markdown" | "html" | "url">(
|
||||
"markdown",
|
||||
@@ -30,6 +51,10 @@ export default function Home() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [onImageLoaded, setOnImageLoaded] = useState(false);
|
||||
|
||||
const [option, setOption] = useState<
|
||||
Array<{ name: string; value: string }>
|
||||
>([]);
|
||||
|
||||
const userCount = useSWR("getUserCount", getUserCount);
|
||||
const countRef = useRef<HTMLDivElement | null>(null);
|
||||
useSmoothCount({
|
||||
@@ -39,23 +64,26 @@ export default function Home() {
|
||||
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") {
|
||||
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") {
|
||||
return `${originUrl || "https://lanyard.cnrad.dev"}/api/${userData?.userId}`;
|
||||
return `${url}`;
|
||||
} else {
|
||||
return `[](https://discord.com/users/${userData?.userId})`;
|
||||
return `[](https://discord.com/users/${userData?.userId})`;
|
||||
}
|
||||
};
|
||||
const copy = () => {
|
||||
}
|
||||
|
||||
function copy() {
|
||||
navigator.clipboard.writeText(outputText());
|
||||
setCopyState("Copied!");
|
||||
|
||||
setTimeout(() => setCopyState("Copy"), 1500);
|
||||
};
|
||||
}
|
||||
|
||||
const submitDiscordId = async () => {
|
||||
async function submitDiscordId() {
|
||||
setIsLoading(true);
|
||||
setOnImageLoaded(false);
|
||||
setUserData(null);
|
||||
@@ -82,7 +110,115 @@ export default function Home() {
|
||||
|
||||
setUserData({ userId });
|
||||
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 (
|
||||
<>
|
||||
@@ -169,16 +305,165 @@ export default function Home() {
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
Are you absolutely sure?
|
||||
</DialogTitle>
|
||||
<DialogTitle>Option</DialogTitle>
|
||||
<DialogDescription>
|
||||
This action cannot be undone. This
|
||||
will permanently delete your account
|
||||
and remove your data from our
|
||||
servers.
|
||||
Select an option to enable/disable
|
||||
features to your Lanyard Profile
|
||||
</DialogDescription>
|
||||
</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>
|
||||
</Dialog>
|
||||
</div>
|
||||
@@ -192,7 +477,7 @@ export default function Home() {
|
||||
opacity: onImageLoaded ? 1 : 0,
|
||||
}}
|
||||
transition={{ duration: 0.5 }}
|
||||
src={`/api/${userData?.userId}`}
|
||||
src={url}
|
||||
height={280}
|
||||
width={500}
|
||||
alt="Your Lanyard Banner"
|
||||
|
||||
Reference in New Issue
Block a user