Compare commits

...

3 Commits

Author SHA1 Message Date
dvelo
3a727aad98 fix: and this 2025-05-06 21:52:48 -05:00
dvelo
554bd0c5f3 fix: still work w/ no metadata 2025-05-06 21:45:58 -05:00
dvelo
4b05dc2149 fix: i hope these servers work 2025-05-06 17:20:18 -05:00
14 changed files with 230 additions and 40 deletions

@ -25,7 +25,7 @@
"@milkdown/plugin-listener": "^7.9.0", "@milkdown/plugin-listener": "^7.9.0",
"@milkdown/preset-commonmark": "^7.9.0", "@milkdown/preset-commonmark": "^7.9.0",
"@milkdown/react": "^7.9.0", "@milkdown/react": "^7.9.0",
"@milkdown/theme-nord": "^7.9.0", "@milkdown/theme-nord": "^7.9.1",
"@monaco-editor/react": "^4.6.0", "@monaco-editor/react": "^4.6.0",
"@number-flow/react": "^0.5.7", "@number-flow/react": "^0.5.7",
"@radix-ui/react-aspect-ratio": "1.1.1", "@radix-ui/react-aspect-ratio": "1.1.1",

@ -0,0 +1,29 @@
/*
* 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) 2025 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.
*/

@ -134,7 +134,7 @@ export default function ModificationPage({
modificationArray[modIndex] = newModObj; modificationArray[modIndex] = newModObj;
await user?.update({ await user?.update({
unsafeMetadata: { unsafeMetadata: {
...user.unsafeMetadata, ...(user.unsafeMetadata ?? {}),
activatedModifications: modificationArray, activatedModifications: modificationArray,
}, },
}); });
@ -165,7 +165,7 @@ export default function ModificationPage({
array.splice(modIndex, 1); array.splice(modIndex, 1);
await user?.update({ await user?.update({
unsafeMetadata: { unsafeMetadata: {
...user.unsafeMetadata, ...(user.unsafeMetadata ?? {}),
activatedModifications: array, activatedModifications: array,
}, },
}); });

@ -164,7 +164,7 @@ export default function CustomFilePage({
await user?.update({ await user?.update({
unsafeMetadata: { unsafeMetadata: {
...user.unsafeMetadata, ...(user.unsafeMetadata ?? {}),
customFiles: metadata, customFiles: metadata,
}, },
}); });

@ -119,7 +119,7 @@ export default function ServerListModificationFrame() {
files.splice(i, 1); files.splice(i, 1);
await user?.update({ await user?.update({
unsafeMetadata: { unsafeMetadata: {
...user.unsafeMetadata, ...(user.unsafeMetadata ?? {}),
customFiles: files, customFiles: files,
}, },
}); });

@ -133,7 +133,7 @@ export function CustomTestSuccess({
await user?.update({ await user?.update({
unsafeMetadata: { unsafeMetadata: {
...user.unsafeMetadata, ...(user.unsafeMetadata ?? {}),
activatedModifications: array, activatedModifications: array,
}, },
}); });

@ -83,13 +83,13 @@ export function ModificationAction({ value }: { value?: Action }) {
if (existing === -1) if (existing === -1)
await user.update({ await user.update({
unsafeMetadata: { unsafeMetadata: {
...user.unsafeMetadata, ...(user.unsafeMetadata ?? {}),
filters: [ filters: [
{ {
type: filter.getSpecificFilterId(), type: filter.getSpecificFilterId(),
metadata: filter.toIdentifier(), metadata: filter.toIdentifier(),
}, },
...previousFilters, ...(previousFilters ?? []),
] as Array<ClerkEmbeddedFilter<unknown>>, ] as Array<ClerkEmbeddedFilter<unknown>>,
}, },
}); });
@ -97,7 +97,7 @@ export function ModificationAction({ value }: { value?: Action }) {
existingArray.splice(existing, 1); existingArray.splice(existing, 1);
await user.update({ await user.update({
unsafeMetadata: { unsafeMetadata: {
...user.unsafeMetadata, ...(user.unsafeMetadata ?? {}),
filters: existingArray, filters: existingArray,
}, },
}); });

@ -111,7 +111,7 @@ export function ModificationFileCreationDialog({
if (!isSignedIn) return toast.error("Please login."); if (!isSignedIn) return toast.error("Please login.");
await user?.update({ await user?.update({
unsafeMetadata: { unsafeMetadata: {
...user.unsafeMetadata, ...(user.unsafeMetadata ?? {}),
customFiles: [ customFiles: [
...((user.unsafeMetadata ...((user.unsafeMetadata
.customFiles as Array<ClerkCustomModification>) ?? []), .customFiles as Array<ClerkCustomModification>) ?? []),

@ -45,7 +45,6 @@ import { useEmbedGenerator } from "@/lib/hooks/use-embed-generator";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { EllipsisVertical } from "lucide-react"; import { EllipsisVertical } from "lucide-react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { ShikiRenderer } from "./embed-shiki-renderer";
import { codeToHtml } from "shiki"; import { codeToHtml } from "shiki";
import { useTheme } from "@/lib/hooks/use-theme"; import { useTheme } from "@/lib/hooks/use-theme";
import useClipboard from "@/lib/useClipboard"; import useClipboard from "@/lib/useClipboard";

@ -0,0 +1,56 @@
/*
* 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) 2025 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 { listenerCtx } from '@milkdown/kit/plugin/listener';
import { Crepe } from '@milkdown/crepe';
import { Milkdown, useEditor } from '@milkdown/react';
import '@milkdown/crepe/theme/common/style.css';
import '@milkdown/crepe/theme/nord-dark.css';
export function ServerEditorDescription({ defaultMarkdown, onUpdate }: { defaultMarkdown: string, onUpdate?: (update: string) => void }) {
useEditor((root) => {
const crepe = new Crepe({
root,
defaultValue: defaultMarkdown,
});
crepe.editor.config(async (ctx) => {
ctx.get(listenerCtx).markdownUpdated((_, markdown) => {
if (onUpdate)
onUpdate(markdown);
});
});
return crepe;
}, []);
return (
<Milkdown />
);
}

@ -1,21 +1,65 @@
import { Dialog, DialogContent } from "@/components/ui/dialog"; import { Dialog, DialogContent } from "@/components/ui/dialog";
import { Drawer, DrawerContent, DrawerTitle } from "@/components/ui/drawer"; import { Drawer, DrawerContent, DrawerTitle } from "@/components/ui/drawer";
import { ReactNode, useEffect, useState } from "react"; import { type ReactNode, useEffect, useState } from "react";
import { ServerEditorDescription } from "./server-editor-description";
import type { useMHSFServer } from "@/lib/hooks/use-mhsf-server";
import { MilkdownProvider } from "@milkdown/react";
import { Material } from "@/components/ui/material";
import { Placeholder } from "@/components/ui/placeholder";
import { X } from "lucide-react";
export function ServerEditorProvider({children}: {children: ReactNode | ReactNode[]}) { export function ServerEditorProvider({
const [open, setOpen] = useState(false); children,
serverData,
}: {
children: ReactNode | ReactNode[];
serverData: ReturnType<typeof useMHSFServer>;
}) {
const [open, setOpen] = useState(false);
useEffect(() => { useEffect(() => {
window.addEventListener("open-server-editor", () => setOpen(true)); window.addEventListener("open-server-editor", () => setOpen(true));
}, []) }, []);
return <> return (
{children} <>
<Drawer open={open} onOpenChange={setOpen}> {children}
<DrawerContent> <MilkdownProvider>
<DrawerTitle>Server Settings</DrawerTitle> <Drawer open={open} onOpenChange={setOpen}>
<DrawerContent className="p-4 ">
</DrawerContent> {serverData.server?.customizationData.isOwnedByUser ? (
</Drawer> <div className="h-full overflow-y-scroll">
</> <DrawerTitle className="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-4xl mb-3">
Server Settings
</DrawerTitle>
<Material className="grid gap-1 max-h-[700px]">
<strong>Server Description</strong>
<p className="mb-3">
A markdown enabled, fancy description for your server!
Describe what players will expect from your server and why
they should join; don't worry, you have more space than
MOTD's.
</p>
{!serverData.loading && (
<ServerEditorDescription
defaultMarkdown={
serverData.server?.customizationData.description ?? ""
}
/>
)}
</Material>
</div>
) : (
<Placeholder
icon={<X />}
className="h-full justify-center flex items-center"
title="You don't own this server"
description="Unfortunately, that one ain't gonna work. Atleast not on my watch."
/>
)}
</DrawerContent>
</Drawer>
</MilkdownProvider>
</>
);
} }

@ -72,7 +72,7 @@ export function ServerProvider({ serverId }: { serverId: string }) {
</div> </div>
) : ( ) : (
<div className="px-10"> <div className="px-10">
<ServerEditorProvider> <ServerEditorProvider serverData={mhsf}>
<ReportingProvider server={mhsf}> <ReportingProvider server={mhsf}>
<ServerMainPage <ServerMainPage
server={server as ServerResponse} server={server as ServerResponse}

@ -83,24 +83,23 @@ export default async function handler(
try { try {
await mongo.connect(); await mongo.connect();
const db = mongo.db(process.env.CUSTOM_MONGO_DB ?? "mhsf"); const db = mongo.db(process.env.CUSTOM_MONGO_DB ?? "mhsf");
const stats = mongo.db("mhsf")
const {userId} = getAuth(req); const {userId} = getAuth(req);
// Run queries in parallel // Run queries in parallel
const [favoriteData, customizationData, playerData, achievements] = const [favoriteData, customizationData, playerData, achievements] =
await Promise.all([ await Promise.all([
findFavoriteData(serverData.name, userId ?? undefined, stats, { findFavoriteData(serverData.name, userId ?? undefined, db, {
maxFavoriteEntries, maxFavoriteEntries,
favoriteTimespanStart, favoriteTimespanStart,
favoriteTimespanEnd, favoriteTimespanEnd,
}), }),
findCustomizationData(serverData.name, userId ?? undefined, stats), findCustomizationData(serverData.name, userId ?? undefined, db),
findPlayerData(serverData.name, stats, { findPlayerData(serverData.name, db, {
maxPlayerEntries, maxPlayerEntries,
playerTimespanStart, playerTimespanStart,
playerTimespanEnd, playerTimespanEnd,
}), }),
findAchievements(serverData.name, stats, { findAchievements(serverData.name, db, {
maxAchievementEntries, maxAchievementEntries,
achievementTimespanStart, achievementTimespanStart,
achievementTimespanEnd, achievementTimespanEnd,

@ -2147,6 +2147,20 @@
tslib "^2.8.1" tslib "^2.8.1"
unified "^11.0.3" unified "^11.0.3"
"@milkdown/core@7.9.1":
version "7.9.1"
resolved "https://registry.yarnpkg.com/@milkdown/core/-/core-7.9.1.tgz#896df4c51f9739f05f5f780955130e7f8539fa64"
integrity sha512-5U9Wncb7YtLqxDFQpHKwa2smIfnmecYPx1D00tgzGqU0Mw9wa/b1bdqIUV1Mlmc5sXZcvoErrEP74AJoApgDUA==
dependencies:
"@milkdown/ctx" "7.9.1"
"@milkdown/exception" "7.9.1"
"@milkdown/prose" "7.9.1"
"@milkdown/transformer" "7.9.1"
remark-parse "^11.0.0"
remark-stringify "^11.0.0"
tslib "^2.8.1"
unified "^11.0.3"
"@milkdown/crepe@7.9.0": "@milkdown/crepe@7.9.0":
version "7.9.0" version "7.9.0"
resolved "https://registry.yarnpkg.com/@milkdown/crepe/-/crepe-7.9.0.tgz#f089439fe6add2dd56d68583533676162824d290" resolved "https://registry.yarnpkg.com/@milkdown/crepe/-/crepe-7.9.0.tgz#f089439fe6add2dd56d68583533676162824d290"
@ -2177,6 +2191,14 @@
"@milkdown/exception" "7.9.0" "@milkdown/exception" "7.9.0"
tslib "^2.8.1" tslib "^2.8.1"
"@milkdown/ctx@7.9.1":
version "7.9.1"
resolved "https://registry.yarnpkg.com/@milkdown/ctx/-/ctx-7.9.1.tgz#469858fe3fb7c4e2135f959eb29d0a0b611a1ae5"
integrity sha512-GGUvLYmOylzz8RhVkNFl3EpSfyOHY+87ggj49oIbiD7F8rAp9ZOCtR/FOJa4jw8tvLi/18vswffRbt150hsXCw==
dependencies:
"@milkdown/exception" "7.9.1"
tslib "^2.8.1"
"@milkdown/exception@7.9.0": "@milkdown/exception@7.9.0":
version "7.9.0" version "7.9.0"
resolved "https://registry.yarnpkg.com/@milkdown/exception/-/exception-7.9.0.tgz#eeeb18f7c675d8c1f2f0582af60e3530b2df94a8" resolved "https://registry.yarnpkg.com/@milkdown/exception/-/exception-7.9.0.tgz#eeeb18f7c675d8c1f2f0582af60e3530b2df94a8"
@ -2184,6 +2206,13 @@
dependencies: dependencies:
tslib "^2.8.1" tslib "^2.8.1"
"@milkdown/exception@7.9.1":
version "7.9.1"
resolved "https://registry.yarnpkg.com/@milkdown/exception/-/exception-7.9.1.tgz#72ef74b4f86ba19a30e212ea9b92d62dc7983629"
integrity sha512-AdEM7ahwHx1pLOgP0taIK52aizuwwQRGJ9KiABPbGDVWznhBAL9FlifUs9B1afh34GJytrtqa3jPLU7Qjotf8w==
dependencies:
tslib "^2.8.1"
"@milkdown/kit@7.9.0": "@milkdown/kit@7.9.0":
version "7.9.0" version "7.9.0"
resolved "https://registry.yarnpkg.com/@milkdown/kit/-/kit-7.9.0.tgz#68a0de3fae20f1a5c99aa69da05f754eabc630c7" resolved "https://registry.yarnpkg.com/@milkdown/kit/-/kit-7.9.0.tgz#68a0de3fae20f1a5c99aa69da05f754eabc630c7"
@ -2386,6 +2415,27 @@
prosemirror-view "^1.37.1" prosemirror-view "^1.37.1"
tslib "^2.8.1" tslib "^2.8.1"
"@milkdown/prose@7.9.1":
version "7.9.1"
resolved "https://registry.yarnpkg.com/@milkdown/prose/-/prose-7.9.1.tgz#9a9709c9a11a5f80613fe01f9df6e4a43b080b4c"
integrity sha512-NZaJtAqCtX8AHHXME80VGIFyeYk0E4UWFxO5TBoCf89WSnidvLjOcohD+w3sB1e6356dePr7p2RxYVOh3VvNMw==
dependencies:
"@milkdown/exception" "7.9.1"
prosemirror-changeset "^2.2.1"
prosemirror-commands "^1.6.2"
prosemirror-dropcursor "^1.8.1"
prosemirror-gapcursor "^1.3.2"
prosemirror-history "^1.4.1"
prosemirror-inputrules "^1.4.0"
prosemirror-keymap "^1.2.2"
prosemirror-model "^1.24.1"
prosemirror-schema-list "^1.5.0"
prosemirror-state "^1.4.3"
prosemirror-tables "^1.7.0"
prosemirror-transform "^1.10.2"
prosemirror-view "^1.37.1"
tslib "^2.8.1"
"@milkdown/react@^7.9.0": "@milkdown/react@^7.9.0":
version "7.9.0" version "7.9.0"
resolved "https://registry.yarnpkg.com/@milkdown/react/-/react-7.9.0.tgz#2527d767c6e498c97dc7fe1d88a3d6cf36470521" resolved "https://registry.yarnpkg.com/@milkdown/react/-/react-7.9.0.tgz#2527d767c6e498c97dc7fe1d88a3d6cf36470521"
@ -2395,14 +2445,14 @@
"@milkdown/kit" "7.9.0" "@milkdown/kit" "7.9.0"
tslib "^2.8.1" tslib "^2.8.1"
"@milkdown/theme-nord@^7.9.0": "@milkdown/theme-nord@^7.9.1":
version "7.9.0" version "7.9.1"
resolved "https://registry.yarnpkg.com/@milkdown/theme-nord/-/theme-nord-7.9.0.tgz#f50a8876f3c25e46018ab9e8d73288fed5aca639" resolved "https://registry.yarnpkg.com/@milkdown/theme-nord/-/theme-nord-7.9.1.tgz#7a24380a90c16ea72b9f3678422609cc34a1f8b2"
integrity sha512-t7w92bKU1lt6HJGKlA/EhQnN1VmQfsKdnchk7wPkxLIiOiiQlYDhYhqjHP1bdqm1wkROBQhfzsxtxcK6672FHA== integrity sha512-/IjyoANeUm6Ncs3Uaw1nQarnEZyYap8MFwHxuInZB9eftzU2roDNk/Hy9RL524C7fOPPGKDTdNl22DLuiyuFug==
dependencies: dependencies:
"@milkdown/core" "7.9.0" "@milkdown/core" "7.9.1"
"@milkdown/ctx" "7.9.0" "@milkdown/ctx" "7.9.1"
"@milkdown/prose" "7.9.0" "@milkdown/prose" "7.9.1"
clsx "^2.0.0" clsx "^2.0.0"
tslib "^2.8.1" tslib "^2.8.1"
@ -2419,6 +2469,19 @@
tslib "^2.8.1" tslib "^2.8.1"
unified "^11.0.3" unified "^11.0.3"
"@milkdown/transformer@7.9.1":
version "7.9.1"
resolved "https://registry.yarnpkg.com/@milkdown/transformer/-/transformer-7.9.1.tgz#fef822a752951bfca473006c79e9c4ae3215702d"
integrity sha512-9tN5xy/v/G8QY3kuMn4MkX5c4UlPdfbkq+5VlmofsbH0bPFJjEG7ityQ0muAMQopVqqqdugoU9pgya9FPJX4Cw==
dependencies:
"@milkdown/exception" "7.9.1"
"@milkdown/prose" "7.9.1"
remark "^15.0.1"
remark-parse "^11.0.0"
remark-stringify "^11.0.0"
tslib "^2.8.1"
unified "^11.0.3"
"@milkdown/utils@7.9.0": "@milkdown/utils@7.9.0":
version "7.9.0" version "7.9.0"
resolved "https://registry.yarnpkg.com/@milkdown/utils/-/utils-7.9.0.tgz#4d2162b9c1c9d80d6d63819ab421075e2cab3162" resolved "https://registry.yarnpkg.com/@milkdown/utils/-/utils-7.9.0.tgz#4d2162b9c1c9d80d6d63819ab421075e2cab3162"