feat: add new embeds

This commit is contained in:
dvelo 2024-11-16 15:01:14 -06:00
parent bdf5b9b52e
commit ddea87ccf8
21 changed files with 1789 additions and 930 deletions

8
.idea/.gitignore generated vendored Normal file

@ -0,0 +1,8 @@
# Ignore everything for IntelliJ except for project essential code-styles
*
!copyright/*
!codeStyles/*
!.gitignore
!*/

7
.idea/codeStyles/Project.xml generated Normal file

@ -0,0 +1,7 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JSCodeStyleSettings version="0">
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</JSCodeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

6
.vscode/.gitignore vendored Normal file

@ -0,0 +1,6 @@
# Ignore everything for VSCode except for project essential code-styles
*
!extensions.json
!settings.json
!.gitignore

5
.vscode/extensions.json vendored Normal file

@ -0,0 +1,5 @@
{
"recommendations": [
"sarfrajansari.copyright-header-injector"
]
}

3
.vscode/settings.json vendored Normal file

@ -0,0 +1,3 @@
{
"copyright-header-injector.copyrightText": "/*\n * MHSF, Minehut Server List\n * All external content is rather licensed under the ECA Agreement\n * located here: https://mhsf.app/docs/legal/external-content-agreement\n *\n * All code under MHSF is licensed under the MIT License\n * by open source contributors\n *\n * Copyright (c) 2024 dvelo\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n */"
}

@ -25,6 +25,7 @@
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-menubar": "^1.1.1", "@radix-ui/react-menubar": "^1.1.1",
"@radix-ui/react-primitive": "^2.0.0", "@radix-ui/react-primitive": "^2.0.0",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-switch": "^1.1.0",
"@unocss/eslint-plugin": "^0.61.5", "@unocss/eslint-plugin": "^0.61.5",
"@unocss/postcss": "^0.61.5", "@unocss/postcss": "^0.61.5",
@ -105,7 +106,7 @@
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-resizable-panels": "^2.0.23", "react-resizable-panels": "^2.0.23",
"recharts": "^2.12.7", "recharts": "^2.12.7",
"shiki": "^1.22.2", "shiki": "^1.23.0",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^5", "typescript": "^5",
"vaul": "^0.9.1", "vaul": "^0.9.1",

@ -0,0 +1,39 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2024 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
import Embed from "@/components/feat/Embed";
export default function EmbedPage({
params,
}: {
params: { server: string };
}) {
return <Embed params={params} />;
}

@ -0,0 +1,58 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2024 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
"use client";
import { TooltipProvider } from "@/components/ui/tooltip";
import "../globals.css";
import { ThemeProvider } from "@/components/ThemeProvider";
import { useSearchParams } from "next/navigation";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const searchParams = useSearchParams();
const search = searchParams?.get("theme") || "light";
return (
<html lang="en">
<body>
<ThemeProvider
attribute="class"
disableTransitionOnChange
forcedTheme={search}
>
<TooltipProvider>{children}</TooltipProvider>
</ThemeProvider>
</body>
</html>
);
}

@ -33,11 +33,8 @@ import Banner from "@/components/Banner";
import ColorProvider from "@/components/ColorProvider"; import ColorProvider from "@/components/ColorProvider";
import ServerView from "@/components/ServerView"; import ServerView from "@/components/ServerView";
import TabServer from "@/components/misc/TabServer"; import TabServer from "@/components/misc/TabServer";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { CornerDownLeft } from "lucide-react";
import type { Metadata, ResolvingMetadata } from "next"; import type { Metadata, ResolvingMetadata } from "next";
import Link from "next/link";
type Props = { type Props = {
params: { server: string }; params: { server: string };
@ -45,7 +42,7 @@ type Props = {
export async function generateMetadata( export async function generateMetadata(
{ params }: Props, { params }: Props,
parent: ResolvingMetadata, parent: ResolvingMetadata
): Promise<Metadata> { ): Promise<Metadata> {
// read route params // read route params
const { server } = params; const { server } = params;
@ -135,12 +132,6 @@ export default function ServerPage({ params }: { params: { server: string } }) {
<ColorProvider server={params.server}> <ColorProvider server={params.server}>
<div className={"pt-16"}> <div className={"pt-16"}>
<Banner server={params.server} /> <Banner server={params.server} />
<Link href="/">
<Button variant="link" className="text-muted-foreground text-sm">
<CornerDownLeft size={16} className="mr-2" /> Go back to the
server list
</Button>
</Link>
<TabServer server={params.server} tabDef="general" /> <TabServer server={params.server} tabDef="general" />
<div className="pt-8"> <div className="pt-8">
<ServerView server={params.server} /> <ServerView server={params.server} />

@ -36,9 +36,8 @@ import {
MinehutIcon, MinehutIcon,
getIndexFromRarity, getIndexFromRarity,
getMinehutIcons, getMinehutIcons,
rarityIndex,
} from "@/lib/types/server-icon"; } from "@/lib/types/server-icon";
import { Copy, Info } from "lucide-react"; import { Copy, ExternalLink, Info } from "lucide-react";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import FadeIn from "react-fade-in/lib/FadeIn"; import FadeIn from "react-fade-in/lib/FadeIn";
@ -55,6 +54,8 @@ import {
CardTitle, CardTitle,
} from "./ui/card"; } from "./ui/card";
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from "./ui/drawer";
import EmbedSelector from "./feat/EmbedSelector";
export default function AfterServerView({ server }: { server: string }) { export default function AfterServerView({ server }: { server: string }) {
const [description, setDescription] = useState(""); const [description, setDescription] = useState("");
@ -64,11 +65,12 @@ export default function AfterServerView({ server }: { server: string }) {
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [view, setView] = useState( const [view, setView] = useState(
description !== "" || discord !== "" ? "desc" : "extra", description !== "" || discord !== "" ? "desc" : "extra"
); );
const [serverObject, setServerObject] = useState<ServerResponse | undefined>( const [serverObject, setServerObject] = useState<ServerResponse | undefined>(
undefined, undefined
); );
const [embedOpened, setEmbedOpened] = useState(false);
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
useEffect(() => { useEffect(() => {
@ -82,7 +84,7 @@ export default function AfterServerView({ server }: { server: string }) {
}); });
} }
fetch("https://api.minehut.com/server/" + server + "?byName=true").then( fetch("https://api.minehut.com/server/" + server + "?byName=true").then(
(c) => c.json().then((n) => setServerObject(n.server)), (c) => c.json().then((n) => setServerObject(n.server))
); );
getMinehutIcons().then((i) => { getMinehutIcons().then((i) => {
setIcons(i); setIcons(i);
@ -94,9 +96,17 @@ export default function AfterServerView({ server }: { server: string }) {
return ( return (
<> <>
<Drawer open={embedOpened} onOpenChange={setEmbedOpened}>
<DrawerContent className="max-w-md w-full mx-auto rounded-t-[10px]">
<DrawerHeader>
<DrawerTitle>Embed Creator</DrawerTitle>
</DrawerHeader>
<EmbedSelector server={server} />
</DrawerContent>
</Drawer>
<FadeIn> <FadeIn>
<div className="grid sm:grid-cols-6 h-full pl-4 pr-4"> <div className="grid sm:grid-cols-6 h-full pl-4 pr-4 ">
<div className="ml-5 mb-2 flex items-center sm:hidden"> <div className="ml-5 mb-2 flex items-center sm:hidden overflow-auto w-[calc(100vw-5rem)]">
{(description != "" || discord != "") && ( {(description != "" || discord != "") && (
<Button <Button
variant={view == "desc" ? undefined : "ghost"} variant={view == "desc" ? undefined : "ghost"}
@ -125,6 +135,10 @@ export default function AfterServerView({ server }: { server: string }) {
> >
Purchased Icons Purchased Icons
</Button> </Button>
<Button variant="ghost" onClick={() => setEmbedOpened(true)}>
Embed Creator
<ExternalLink className="h-[1.2rem] w-[1.2rem] ml-1" />
</Button>
</div> </div>
<div className="max-sm:hidden"> <div className="max-sm:hidden">
<div className="grid"> <div className="grid">
@ -154,6 +168,10 @@ export default function AfterServerView({ server }: { server: string }) {
> >
Purchased Icons Purchased Icons
</Button> </Button>
<Button variant="ghost" onClick={() => setEmbedOpened(true)}>
Embed Creator
<ExternalLink className="h-[1.2rem] w-[1.2rem] ml-1" />
</Button>
</div> </div>
</div> </div>
@ -349,11 +367,11 @@ export default function AfterServerView({ server }: { server: string }) {
JSON.stringify({ JSON.stringify({
minehut: serverObject, minehut: serverObject,
mhsf: mhsf.getMHSF(), mhsf: mhsf.getMHSF(),
}), })
); );
} catch { } catch {
toast.error( toast.error(
"Clipboard is inaccessible. Cannot copy", "Clipboard is inaccessible. Cannot copy"
); );
} }
toast.success( toast.success(
@ -366,7 +384,7 @@ export default function AfterServerView({ server }: { server: string }) {
}).substring(0, 36)} }).substring(0, 36)}
... ...
</code> </code>
</div>, </div>
); );
setTimeout(() => setCopied(false), 1000); setTimeout(() => setCopied(false), 1000);
}} }}
@ -438,9 +456,7 @@ export default function AfterServerView({ server }: { server: string }) {
className="pt-4" className="pt-4"
style={{ style={{
color: getIndexFromRarity( color: getIndexFromRarity(
icons icons?.find((c) => c._id === icon)?.rank.toLowerCase()
?.find((c) => c._id === icon)
?.rank.toLowerCase(),
).text, ).text,
}} }}
> >
@ -457,7 +473,7 @@ export default function AfterServerView({ server }: { server: string }) {
backgroundColor: getIndexFromRarity( backgroundColor: getIndexFromRarity(
icons icons
?.find((c) => c._id === icon) ?.find((c) => c._id === icon)
?.rank.toLowerCase(), ?.rank.toLowerCase()
).bg, ).bg,
}} }}
> >

@ -430,7 +430,6 @@ export function ServerCommandBar() {
)} )}
</span> </span>
</h2> </h2>
{owned && ( {owned && (
<h2 className="flex items-center text-muted-foreground"> <h2 className="flex items-center text-muted-foreground">
<CheckIcon /> <CheckIcon />

@ -30,7 +30,6 @@
"use client"; "use client";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Spinner } from "./ui/spinner";
import { import {
Card, Card,
CardContent, CardContent,
@ -108,7 +107,7 @@ export default function ServerView(props: { server: string }) {
} }
return ( return (
<> <>
{single.grabOnline() == undefined && ( {single.grabOnline() == undefined && !single.grabOffline()?.online && (
<div className="grid pl-4 pr-4"> <div className="grid pl-4 pr-4">
<div <div
className=" rounded p-2" className=" rounded p-2"
@ -130,7 +129,8 @@ export default function ServerView(props: { server: string }) {
<Card className="sm:col-span-2"> <Card className="sm:col-span-2">
<BetterHeader> <BetterHeader>
<CardTitle className="flex items-center"> <CardTitle className="flex items-center">
{single.grabOnline() == undefined ? ( {single.grabOnline() == undefined &&
!single.grabOffline()?.online ? (
<div <div
className="items-center mr-1" className="items-center mr-1"
style={{ style={{

@ -0,0 +1,168 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2024 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
"use client";
import IconDisplay from "@/components/IconDisplay";
import { Badge } from "@/components/ui/badge";
import { Spinner } from "@/components/ui/spinner";
import type { ServerResponse } from "@/lib/types/mh-server";
import { Copy, ExternalLink, ServerCrash } from "lucide-react";
import { notFound, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import { Button } from "../ui/button";
import { CheckmarkIcon } from "react-hot-toast";
import useClipboard from "@/lib/useClipboard";
import { Tooltip, TooltipTrigger, TooltipContent } from "../ui/tooltip";
export default function Embed({ params }: { params: { server: string } }) {
const [serverFound, setServerFound] = useState(true);
const [loading, setLoading] = useState(true);
const [copied, setCopied] = useState(false);
const [serverObject, setServerObject] = useState<ServerResponse | null>(null);
const searchParams = useSearchParams();
const staticMode = searchParams?.get("static") === "true";
const noShowBranding = searchParams?.get("branding") === "false";
const clipboard = useClipboard();
useEffect(() => {
(async () => {
const serverFoundResponse = await fetch(
"https://api.minehut.com/server/" + params.server + "?byName=true"
);
const stream = await serverFoundResponse.json();
if (stream.server == null) setServerFound(false);
else setServerObject(stream.server);
setLoading(false);
})();
}, [params]);
if (loading) {
return <Spinner />;
}
if (!serverFound) {
notFound();
}
return (
<div className="rounded w-[390px] h-[145px] bg-muted">
<div
className={
"flex items-center text-sm cursor-pointer border-b p-2" +
(staticMode ? "" : " group")
}
onClick={() =>
window.open("/server/" + params.server, "_blank")?.focus()
}
>
<ServerCrash
size={16}
className="group-hover:text-white p-[4px] group-hover:p-[3px] w-[24px] h-[24px] transition-all bg-gradient-to-r group-hover:from-blue-600 group-hover:to-purple-500 group-hover:rounded"
/>
<span className="transition-colors ml-2 group-hover:bg-clip-text group-hover:text-transparent bg-gradient-to-r group-hover:from-blue-600 group-hover:to-purple-500">
Powered by MHSF
</span>
</div>
<div className="px-4 pt-2 flex items-center group overflow-hidden">
<div className={staticMode ? "block" : "group-hover:block hidden"}>
<Tooltip>
<TooltipTrigger>
<Button
variant="outline"
size="sm"
className="mb-1"
onClick={() => {
setCopied(true);
clipboard.writeText(params.server + ".mhsf.minehut.gg");
setTimeout(() => setCopied(false), 1000);
}}
>
{copied ? <CheckmarkIcon /> : <Copy size={16} />}
</Button>
</TooltipTrigger>
<TooltipContent>Copy this server IP</TooltipContent>
</Tooltip>{" "}
<br />
<Button
variant="outline"
size="sm"
onClick={() => {
window.open("/server/" + params.server, "_blank")?.focus();
}}
>
<ExternalLink size={16} />
</Button>
</div>
<IconDisplay
server={serverObject}
className={
"flex items-center mr-2" +
(staticMode ? " mb-1 ml-1" : " group-hover:mb-1 group-hover:ml-1")
}
/>
<div className={"block" + (staticMode ? " mb-1" : " group-hover:mb-1")}>
<strong className="text-lg">{params.server}</strong>{" "}
{!noShowBranding && <Badge variant="blue">on Minehut</Badge>}
<br />
<span className="text-sm">Joined {serverObject?.joins} times</span>
<br />
{serverObject?.online && (
<span className="flex items-center">
{serverObject.playerCount === 0 ? (
<div
className="items-center border"
style={{
width: ".5rem",
height: ".5rem",
borderRadius: "9999px",
}}
/>
) : (
<div
className="items-center"
style={{
backgroundColor: "#0cce6b",
width: ".5rem",
height: ".5rem",
borderRadius: "9999px",
}}
/>
)}
<span className="text-sm ml-1">
{serverObject.playerCount} player(s) online
</span>
</span>
)}
</div>
</div>
</div>
);
}

@ -0,0 +1,306 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2024 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
"use client";
import { TabsContent } from "@radix-ui/react-tabs";
import { Button } from "../ui/button";
import { DrawerFooter, DrawerTrigger } from "../ui/drawer";
import { Tabs, TabsList, TabsTrigger } from "../ui/tabs";
import { useEffect, useState } from "react";
import { codeToHtml } from "shiki";
import { useTheme } from "next-themes";
import { Asterisk, Copy } from "lucide-react";
import useClipboard from "@/lib/useClipboard";
import toast from "react-hot-toast";
import { Checkbox } from "../ui/checkbox";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
export default function EmbedSelector({ server }: { server: string }) {
const { theme, systemTheme, resolvedTheme } = useTheme();
const [embedTheme, setEmbedTheme] = useState("");
const [embedStatic, setEmbedStatic] = useState(false);
const [highlightedHtml, setHighlightedHtml] = useState("");
const [highlightedJsx, setHighlightedJsx] = useState("");
const [selectedCodeType, setSelectedCodeType] = useState("jsx");
const [noMinehutBranding, setNoMinehutBranding] = useState(false);
const clipboard = useClipboard();
const [url, setURL] = useState(`https://mhsf.app/embed/${server}?`);
const [jsxCode, setJsxCode] = useState(`<iframe
src="${url}"
width={390}
height={145}
style={{ borderRadius: 0.25 }}
allow="clipboard-write"
frameBorder={0}
sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"
/>`);
const [htmlCode, setHtmlCode] = useState(`<iframe
src="${url}"
width="390"
height="145"
style="border-radius: 0.25rem;"
allow="clipboard-write"
frameborder="0"
sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"
></iframe>`);
useEffect(() => {
setHtmlCode(`<iframe
src="${url}"
width="390"
height="145"
style="border-radius: 0.25rem;"
allow="clipboard-write"
frameborder="0"
sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"
></iframe>`);
setJsxCode(`<iframe
src="${url}"
width={390}
height={145}
style={{ borderRadius: 0.25 }}
allow="clipboard-write"
frameBorder={0}
sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"
/>`);
const currentTheme = theme === "system" ? systemTheme : theme;
const selectedTheme =
currentTheme === "dark" ? "vitesse-dark" : "vitesse-light";
async function highlightCode() {
const jsx = await codeToHtml(jsxCode, {
lang: "jsx",
theme: selectedTheme,
});
const html = await codeToHtml(htmlCode, {
lang: "html",
theme: selectedTheme,
});
setHighlightedHtml(html);
setHighlightedJsx(jsx);
}
highlightCode();
}, [
theme,
systemTheme,
jsxCode,
htmlCode,
embedStatic,
noMinehutBranding,
url,
]);
const renderCode = (code: string, highlighted: string) => {
if (highlighted) {
return (
<div
className="h-full overflow-auto bg-background font-mono text-xs [&>pre]:h-full [&>pre]:!bg-transparent [&>pre]:p-4 [&_code]:break-all"
dangerouslySetInnerHTML={{ __html: highlighted }}
/>
);
} else {
return (
<pre className="h-full overflow-auto break-all bg-background p-4 font-mono text-xs text-foreground">
{code}
</pre>
);
}
};
return (
<>
<div className="p-4">
<div className="px-2 pb-8">
<div className="items-top flex space-x-2">
<Checkbox
id="static"
checked={embedStatic}
onCheckedChange={(c) => {
setEmbedStatic(c == "indeterminate" ? true : c);
setURL(
`https://mhsf.app/embed/${server}?${c ? "&static=true" : ""}${
noMinehutBranding ? "&branding=false" : ""
}&theme=${embedTheme}`
);
}}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="static"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Make embed static
</label>
<p className="text-sm text-muted-foreground">
Interactions with the embed take less resources but will be less
interactive.
</p>
</div>
</div>
<br />
<div className="items-top flex space-x-2">
<Checkbox
id="static"
checked={noMinehutBranding}
onCheckedChange={(c) => {
setNoMinehutBranding(c == "indeterminate" ? true : c);
setURL(
`https://mhsf.app/embed/${server}?${embedStatic ? "&static=true" : ""}${
c ? "&branding=false" : ""
}&theme=${embedTheme}`
);
}}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="static"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Remove Minehut branding
</label>
<p className="text-sm text-muted-foreground">
Enabling this will remove the "on Minehut" tag on the embed.
</p>
</div>
</div>
<br />
<div>
<label
htmlFor="theme"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Theme
</label>
<Select
name="theme"
value={embedTheme}
onValueChange={(c) => {
setEmbedTheme(c);
setURL(
`https://mhsf.app/embed/${server}?${embedStatic ? "&static=true" : ""}${
noMinehutBranding ? "&branding=false" : ""
}&theme=${c}`
);
}}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Light" />
</SelectTrigger>
<SelectContent>
<SelectItem value="light">Light</SelectItem>
<SelectItem value="dark">Dark</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<Tabs defaultValue="preview" className="relative mr-auto w-full">
<TabsList className="w-full justify-start rounded-none border-b bg-transparent p-0">
<TabsTrigger
value="preview"
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
Preview
</TabsTrigger>
<TabsTrigger
value="code"
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
Code
</TabsTrigger>
</TabsList>
<TabsContent value="preview">
<iframe
src={`/embed/${server}?${embedStatic ? "&static=true" : ""}${
noMinehutBranding ? "&branding=false" : ""
}&theme=${embedTheme}`}
width={390}
height={145}
className="justify-center m-1"
style={{ borderRadius: "0.25rem" }}
allow="clipboard-write"
frameBorder={0}
sandbox="allow-forms allow-scripts"
/>
</TabsContent>
<TabsContent value="code">
<div className="bg-secondary h-[43px] px-3 py-1 rounded-b">
<div className="w-[130px] grid grid-cols-2">
<Button
size="icon"
className="h-8 w-16 justify-end"
variant="ghost"
onClick={() => {
if (selectedCodeType === "jsx") setSelectedCodeType("html");
else setSelectedCodeType("jsx");
}}
>
<Asterisk size={16} className="mr-1" />
{selectedCodeType === "jsx" ? <>JSX</> : <>HTML</>}
</Button>
<Button
size="icon"
className="h-8 w-8 justify-end"
variant="ghost"
onClick={() => {
clipboard.writeText(
selectedCodeType === "jsx" ? jsxCode : htmlCode
);
toast.success("Copied!");
}}
>
<Copy size={16} />
</Button>
</div>
</div>
{renderCode(
selectedCodeType === "jsx" ? jsxCode : htmlCode,
selectedCodeType === "jsx" ? highlightedJsx : highlightedHtml
)}
</TabsContent>
</Tabs>
</div>
<DrawerFooter>
<DrawerTrigger asChild>
<Button>Close</Button>
</DrawerTrigger>
</DrawerFooter>
</>
);
}

@ -32,7 +32,7 @@
import { useState } from "react"; import { useState } from "react";
import { Tabs, TabsList, TabsTrigger } from "../ui/tabs"; import { Tabs, TabsList, TabsTrigger } from "../ui/tabs";
import { useRouter } from "@/lib/useRouter"; import { useRouter } from "@/lib/useRouter";
import { Database, Home, Paintbrush } from "lucide-react"; import { CornerDownLeft, Database, Home, Paintbrush } from "lucide-react";
export default function TabServer({ export default function TabServer({
server, server,
@ -45,7 +45,7 @@ export default function TabServer({
const router = useRouter(); const router = useRouter();
return ( return (
<div className="w-full flex justify-center"> <div className="w-full px-4">
<Tabs <Tabs
value={tab} value={tab}
onValueChange={(tac) => { onValueChange={(tac) => {
@ -53,23 +53,40 @@ export default function TabServer({
if (tac == "customize") router.push(`/server/${server}/customize`); if (tac == "customize") router.push(`/server/${server}/customize`);
if (tac == "statistics") router.push(`/server/${server}/statistics`); if (tac == "statistics") router.push(`/server/${server}/statistics`);
if (tac == "general") router.push(`/server/${server}`); if (tac == "general") router.push(`/server/${server}`);
if (tac == "server-list") router.push("/");
}} }}
className="sm:w-[500px] max-sm:w-[200px]"
> >
<TabsList className="grid w-full grid-cols-3 max-sm:min-h-[50px]"> <TabsList className="border-b bg-transparent p-0 rounded-none w-full justify-start">
<TabsTrigger value="general" className=""> <TabsTrigger
value="general"
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
{" "} {" "}
<div className="max-sm:hidden">General Information</div> <div className="max-sm:hidden">General Information</div>
<Home className="sm:hidden" size={18} /> <Home className="sm:hidden" size={18} />
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="statistics"> <TabsTrigger
value="statistics"
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
<div className="max-sm:hidden">Statistics</div> <div className="max-sm:hidden">Statistics</div>
<Database className="sm:hidden" size={18} /> <Database className="sm:hidden" size={18} />
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="customize"> <TabsTrigger
value="customize"
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
<div className="max-sm:hidden">Customization</div> <div className="max-sm:hidden">Customization</div>
<Paintbrush className="sm:hidden" size={18} /> <Paintbrush className="sm:hidden" size={18} />
</TabsTrigger> </TabsTrigger>
<TabsTrigger
value="server-list"
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
<CornerDownLeft size={16} className="mr-2" />
<div className="max-sm:hidden">Back to server list</div>
</TabsTrigger>
</TabsList> </TabsList>
</Tabs> </Tabs>
</div> </div>

@ -0,0 +1,158 @@
"use client"
import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { cn } from "@/lib/utils"
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "@radix-ui/react-icons"
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-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDownIcon 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 className="h-4 w-4" />
</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 className="h-4 w-4" />
</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 bg-popover text-popover-foreground 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-accent focus:text-accent-foreground 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-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
}

@ -73,6 +73,7 @@ export const allFolders: DocsFolder[] = [
name: "Legal", name: "Legal",
docs: [ docs: [
{ title: "ECA Agreement", url: "/docs/legal/external-content-agreement" }, { title: "ECA Agreement", url: "/docs/legal/external-content-agreement" },
{ title: "Email List", url: "/docs/legal/email-list" },
], ],
}, },
]; ];

@ -41,7 +41,10 @@ const User = ({ user }: { user: string }) => (
const FeatureList = ({ const FeatureList = ({
features, features,
title, title,
}: { features: (string | ReactNode)[]; title: ReactNode }) => { }: {
features: (string | ReactNode)[];
title: ReactNode;
}) => {
return ( return (
<ul> <ul>
{title} {title}
@ -54,6 +57,25 @@ const FeatureList = ({
export const version = "1.4.0"; export const version = "1.4.0";
export const changelog: { name: string; id: string; changelog: ReactNode }[] = [ export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
{
id: "r9swempc7kaqd2j84nutv5",
name: "v1.5.0",
changelog: (
<FeatureList
features={[
"New embeds",
"More mobile friendly elements",
"Better tabs in the server",
"Fixed issue where some servers due to their age were not loading",
]}
title={
<strong className="flex items-center">
Version 1.5.0 (November 16th 2024)
</strong>
}
/>
),
},
{ {
id: "ywvhtcs4k9rqjfp57x", id: "ywvhtcs4k9rqjfp57x",
name: "v1.4.5", name: "v1.4.5",

@ -60,6 +60,9 @@ export default class ServerSingle {
if (this.online == true && skipOnline != true) { if (this.online == true && skipOnline != true) {
fetch("https://api.minehut.com/servers").then((l) => fetch("https://api.minehut.com/servers").then((l) =>
l.json().then((o) => { l.json().then((o) => {
if (o.servers.find((j: OnlineServer) => j.name == this.name) == undefined) {
g(true);
}
o.servers.forEach((j: OnlineServer) => { o.servers.forEach((j: OnlineServer) => {
if (j.name == this.name) { if (j.name == this.name) {
this.onlineObj = j; this.onlineObj = j;

118
yarn.lock

@ -1747,6 +1747,33 @@
"@radix-ui/react-use-callback-ref" "1.1.0" "@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0" "@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-select@^2.1.2":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-2.1.2.tgz#2346e118966db793940f6a866fd4cc5db2cc275e"
integrity sha512-rZJtWmorC7dFRi0owDmoijm6nSJH1tVw64QGiNIZ9PNLyBDtG+iAq+XGsya052At4BfarzY/Dhv9wrrUr6IMZA==
dependencies:
"@radix-ui/number" "1.1.0"
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-collection" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.1"
"@radix-ui/react-direction" "1.1.0"
"@radix-ui/react-dismissable-layer" "1.1.1"
"@radix-ui/react-focus-guards" "1.1.1"
"@radix-ui/react-focus-scope" "1.1.0"
"@radix-ui/react-id" "1.1.0"
"@radix-ui/react-popper" "1.2.0"
"@radix-ui/react-portal" "1.1.2"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-slot" "1.1.0"
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-use-previous" "1.1.0"
"@radix-ui/react-visually-hidden" "1.1.0"
aria-hidden "^1.1.1"
react-remove-scroll "2.6.0"
"@radix-ui/react-separator@^1.1.0": "@radix-ui/react-separator@^1.1.0":
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.0.tgz#ee0f4d86003b0e3ea7bc6ccab01ea0adee32663e" resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.0.tgz#ee0f4d86003b0e3ea7bc6ccab01ea0adee32663e"
@ -1969,39 +1996,39 @@
resolved "https://registry.yarnpkg.com/@sapphire/snowflake/-/snowflake-3.5.3.tgz#0c102aa2ec5b34f806e9bc8625fc6a5e1d0a0c6a" resolved "https://registry.yarnpkg.com/@sapphire/snowflake/-/snowflake-3.5.3.tgz#0c102aa2ec5b34f806e9bc8625fc6a5e1d0a0c6a"
integrity sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ== integrity sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==
"@shikijs/core@1.22.2": "@shikijs/core@1.23.0":
version "1.22.2" version "1.23.0"
resolved "https://registry.yarnpkg.com/@shikijs/core/-/core-1.22.2.tgz#9c22bd4cc8a4d6c062461cfd35e1faa6c617ca25" resolved "https://registry.yarnpkg.com/@shikijs/core/-/core-1.23.0.tgz#6504882c7cafc1176b2443e87609b68fbdf10096"
integrity sha512-bvIQcd8BEeR1yFvOYv6HDiyta2FFVePbzeowf5pPS1avczrPK+cjmaxxh0nx5QzbON7+Sv0sQfQVciO7bN72sg== integrity sha512-J4Fo22oBlfRHAXec+1AEzcowv+Qdf4ZQkuP/X/UHYH9+KA9LvyFXSXyS+HxuBRFfon+u7bsmKdRBjoZlbDVRkQ==
dependencies: dependencies:
"@shikijs/engine-javascript" "1.22.2" "@shikijs/engine-javascript" "1.23.0"
"@shikijs/engine-oniguruma" "1.22.2" "@shikijs/engine-oniguruma" "1.23.0"
"@shikijs/types" "1.22.2" "@shikijs/types" "1.23.0"
"@shikijs/vscode-textmate" "^9.3.0" "@shikijs/vscode-textmate" "^9.3.0"
"@types/hast" "^3.0.4" "@types/hast" "^3.0.4"
hast-util-to-html "^9.0.3" hast-util-to-html "^9.0.3"
"@shikijs/engine-javascript@1.22.2": "@shikijs/engine-javascript@1.23.0":
version "1.22.2" version "1.23.0"
resolved "https://registry.yarnpkg.com/@shikijs/engine-javascript/-/engine-javascript-1.22.2.tgz#62e90dbd2ed1d78b972ad7d0a1f8ffaaf5e43279" resolved "https://registry.yarnpkg.com/@shikijs/engine-javascript/-/engine-javascript-1.23.0.tgz#51728dd9d68e4ddc123734f816874aded38a1f11"
integrity sha512-iOvql09ql6m+3d1vtvP8fLCVCK7BQD1pJFmHIECsujB0V32BJ0Ab6hxk1ewVSMFA58FI0pR2Had9BKZdyQrxTw== integrity sha512-CcrppseWShG+8Efp1iil9divltuXVdCaU4iu+CKvzTGZO5RmXyAiSx668M7VbX8+s/vt1ZKu75Vn/jWi8O3G/Q==
dependencies: dependencies:
"@shikijs/types" "1.22.2" "@shikijs/types" "1.23.0"
"@shikijs/vscode-textmate" "^9.3.0" "@shikijs/vscode-textmate" "^9.3.0"
oniguruma-to-js "0.4.3" oniguruma-to-es "0.1.2"
"@shikijs/engine-oniguruma@1.22.2": "@shikijs/engine-oniguruma@1.23.0":
version "1.22.2" version "1.23.0"
resolved "https://registry.yarnpkg.com/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.2.tgz#b12a44e3faf486e19fbcf8952f4b56b9b9b8d9b8" resolved "https://registry.yarnpkg.com/@shikijs/engine-oniguruma/-/engine-oniguruma-1.23.0.tgz#c32610bdfe0850e54b10d9e1f5a689f63e681c91"
integrity sha512-GIZPAGzQOy56mGvWMoZRPggn0dTlBf1gutV5TdceLCZlFNqWmuc7u+CzD0Gd9vQUTgLbrt0KLzz6FNprqYAxlA== integrity sha512-gS8bZLqVvmZXX+E5JUMJICsBp+kx6gj79MH/UEpKHKIqnUzppgbmEn6zLa6mB5D+sHse2gFei3YYJxQe1EzZXQ==
dependencies: dependencies:
"@shikijs/types" "1.22.2" "@shikijs/types" "1.23.0"
"@shikijs/vscode-textmate" "^9.3.0" "@shikijs/vscode-textmate" "^9.3.0"
"@shikijs/types@1.22.2": "@shikijs/types@1.23.0":
version "1.22.2" version "1.23.0"
resolved "https://registry.yarnpkg.com/@shikijs/types/-/types-1.22.2.tgz#695a283f19963fe0638fc2646862ba5cfc4623a8" resolved "https://registry.yarnpkg.com/@shikijs/types/-/types-1.23.0.tgz#860635725176d8b0cd07cda418fb319fc7a068da"
integrity sha512-NCWDa6LGZqTuzjsGfXOBWfjS/fDIbDdmVDug+7ykVe1IKT4c1gakrvlfFYp5NhAXH/lyqLM8wsAPo5wNy73Feg== integrity sha512-HiwzsihRao+IbPk7FER/EQT/D0dEEK3n5LAtHDzL5iRT+JMblA7y9uitUnjEnHeLkKigNM+ZplrP7MuEyyc5kA==
dependencies: dependencies:
"@shikijs/vscode-textmate" "^9.3.0" "@shikijs/vscode-textmate" "^9.3.0"
"@types/hast" "^3.0.4" "@types/hast" "^3.0.4"
@ -3460,6 +3487,11 @@ eastasianwidth@^0.2.0:
resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz"
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
emoji-regex-xs@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz#e8af22e5d9dbd7f7f22d280af3d19d2aab5b0724"
integrity sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
@ -6506,12 +6538,14 @@ onetime@^6.0.0:
dependencies: dependencies:
mimic-fn "^4.0.0" mimic-fn "^4.0.0"
oniguruma-to-js@0.4.3: oniguruma-to-es@0.1.2:
version "0.4.3" version "0.1.2"
resolved "https://registry.yarnpkg.com/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz#8d899714c21f5c7d59a3c0008ca50e848086d740" resolved "https://registry.yarnpkg.com/oniguruma-to-es/-/oniguruma-to-es-0.1.2.tgz#157a34f2c6a469c053a5deecf3065f4163279cd4"
integrity sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ== integrity sha512-sBYKVJlIMB0WPO+tSu/NNB1ytSFeHyyJZ3Ayxfx3f/QUuXu0lvZk0VB4K7npmdlHSC0ldqanzh/sUSlAbgCTfw==
dependencies: dependencies:
regex "^4.3.2" emoji-regex-xs "^1.0.0"
regex "^4.4.0"
regex-recursion "^4.1.0"
oo-ascii-tree@^1.84.0: oo-ascii-tree@^1.84.0:
version "1.102.0" version "1.102.0"
@ -7028,7 +7062,19 @@ regenerator-runtime@^0.14.0:
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
regex@^4.3.2: regex-recursion@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/regex-recursion/-/regex-recursion-4.2.1.tgz#024ee28593b8158e568307b99bf1b7a3d5ea31e9"
integrity sha512-QHNZyZAeKdndD1G3bKAbBEKOSSK4KOHQrAJ01N1LJeb0SoH4DJIeFhp0uUpETgONifS4+P3sOgoA1dhzgrQvhA==
dependencies:
regex-utilities "^2.3.0"
regex-utilities@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/regex-utilities/-/regex-utilities-2.3.0.tgz#87163512a15dce2908cf079c8960d5158ff43280"
integrity sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==
regex@^4.4.0:
version "4.4.0" version "4.4.0"
resolved "https://registry.yarnpkg.com/regex/-/regex-4.4.0.tgz#cb731e2819f230fad69089e1bd854fef7569e90a" resolved "https://registry.yarnpkg.com/regex/-/regex-4.4.0.tgz#cb731e2819f230fad69089e1bd854fef7569e90a"
integrity sha512-uCUSuobNVeqUupowbdZub6ggI5/JZkYyJdDogddJr60L764oxC2pMZov1fQ3wM9bdyzUILDG+Sqx6NAKAz9rKQ== integrity sha512-uCUSuobNVeqUupowbdZub6ggI5/JZkYyJdDogddJr60L764oxC2pMZov1fQ3wM9bdyzUILDG+Sqx6NAKAz9rKQ==
@ -7314,15 +7360,15 @@ shebang-regex@^3.0.0:
resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shiki@^1.22.2: shiki@^1.23.0:
version "1.22.2" version "1.23.0"
resolved "https://registry.yarnpkg.com/shiki/-/shiki-1.22.2.tgz#ed109a3d0850504ad5a1edf8496470a2121c5b7b" resolved "https://registry.yarnpkg.com/shiki/-/shiki-1.23.0.tgz#83e6a2b71d0faf9fa1679b045266ba5de711b4c6"
integrity sha512-3IZau0NdGKXhH2bBlUk4w1IHNxPh6A5B2sUpyY+8utLu2j/h1QpFkAaUA1bAMxOWWGtTWcAh531vnS4NJKS/lA== integrity sha512-xfdu9DqPkIpExH29cmiTlgo0/jBki5la1Tkfhsv+Wu5TT3APLNHslR1acxuKJOCWqVdSc+pIbs/2ozjVRGppdg==
dependencies: dependencies:
"@shikijs/core" "1.22.2" "@shikijs/core" "1.23.0"
"@shikijs/engine-javascript" "1.22.2" "@shikijs/engine-javascript" "1.23.0"
"@shikijs/engine-oniguruma" "1.22.2" "@shikijs/engine-oniguruma" "1.23.0"
"@shikijs/types" "1.22.2" "@shikijs/types" "1.23.0"
"@shikijs/vscode-textmate" "^9.3.0" "@shikijs/vscode-textmate" "^9.3.0"
"@types/hast" "^3.0.4" "@types/hast" "^3.0.4"