-
-
-
+
+ <>
+ {(!isSignedIn || hero) && (
+
+
= 3200
- ? "bg-clip-text text-transparent bg-gradient-to-r from-cyan-500 to-blue-500"
- : ""
- }
+ style={{
+ backgroundImage:
+ "radial-gradient(at 27% 37%,#3a8bfd 0,transparent 0),radial-gradient(at 97% 21%,#ff6 0,transparent 50%),radial-gradient(at 52% 99%,#6ff 0,transparent 50%),radial-gradient(at 10% 29%,#f6f 0,transparent 50%),radial-gradient(at 97% 96%,#f96 0,transparent 50%),radial-gradient(at 33% 50%,#69f 0,transparent 50%),radial-gradient(at 79% 53%,#f69 0,transparent 50%)",
+ opacity: 0.3,
+ filter: "blur(100px) saturate(150%)",
+ top: 80,
+ }}
+ />
+
+ <>
+ Meet MHSF, the modern
+ server finder
+ >
+
+
+ MHSF is the next generation server list for Minehut, with
+ interactive filters, {" "}
+ intuitive keyboard shortcuts, and everything between.
+
+
+
+
+ Look and see
+
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
- Servers online{" "}
+
+
+
+
+
+
- }
- className="relative z-0"
- desc={
-
+
+
+
+ For players
+
+
+
+
+ Find what you want now, not later
+
+
+ Use interactive filters and customization modes to find the
+ server of your choice
+ in less than 10 minutes.
+
+
+
+ {serverList.currentServers.slice(0, 20).map((server) => (
+ router.push(`/server/${server.name}`)}
+ >
+
+
+
+
+ {server.name}
+
+ {server.author && (
+
+ by {server.author}
+
+ )}
+
+
+
+ ))}
+
+
+ {serverList.currentServers.slice(0, 20).map((server) => (
+ router.push(`/server/${server.name}`)}
+ >
+
+
+
+
+ {server.name}
+
+ {server.author && (
+
+ by {server.author}
+
+ )}
+
+
+
+ ))}
+
+
+
+
+
+
+
+ For server owners
+
+
+
+
+ Make your server stand out
+
+
+ Servers can have custom banners, Discord widgets, color schemes,
+ and descriptions, making your server stand out with information
+ that can be shown to players.
+
+
+ {features.map((feature, idx) => (
+
+ ))}
+
+
+ )}
+
+
+
+ >
+
+
+
+
+
+ = 3200
- ? "bg-clip-text text-transparent bg-gradient-to-r from-cyan-500 to-blue-500 "
+ ? "bg-clip-text text-transparent bg-gradient-to-r from-cyan-500 to-blue-500"
: ""
}
>
- {serverList.getExtraData().total_servers.toString()}
+ Servers online{" "}
- {serverList.getExtraData().total_servers >= 3200 && (
-
-
-
-
-
- The server amount is over 3.2k, meaning that new servers
- have to go into a queue before being able to be online.{" "}
-
- (the server count isn't entirely accurate, so sometimes
- you might not go into a queue even when the server count
- is at 3.2k)
-
-
- )}
-
- }
- icon={Network}
- >
- {serverList.getExtraData().total_servers >= 3200 && (
-
- )}
-
-
- {serverList.currentServers[0] != undefined
- ? serverList.currentServers[0].name
- : "None"}{" "}
- {serverList.currentServers[0] != undefined && (
-
- )}
- >
- }
- icon={Sun}
- />
-
-
-
-
-
-
-
- Servers
-
- events.emit("search-request-event")}>
- Search Servers
-
-
- +Shift+K
-
-
- {
- setRandomData(serverList.getRandomServer());
- setRandom(true);
- }}
- >
- Pick Random Server
-
-
- {
- toast.promise(
- new Promise((s, e) => {
- setLoading(true);
- serverList
- .fetchDataAndFilter()
- .then(() => {
- serverList.moveListDown();
-
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
-
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
-
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- setLoading(false);
- s(false);
- });
- })
- .catch(() => {
- e();
- });
- }),
- {
- success: "Succesfully refreshed servers",
- loading: "Refreshing...",
- error: "Error while refreshing",
- }
- );
- }}
- >
- Refresh
-
-
-
-
- Filter
-
- {
- toast.promise(
- new Promise((g, b) => {
- if (v == "smaller") {
- setTemplateFilter(true);
- var filt = nameFilters;
- filt["smaller-tf"] = true;
- filt["bigger-tf"] = false;
- setNameFilters(filt);
-
- var filt2 = filters;
- filt2.push(smaller);
- if (filt2.includes(bigger)) {
- filt2.splice(filt2.indexOf(bigger), 1);
- }
- setFilters(filt2);
- serverList.editFilters(filters);
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
-
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
-
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
-
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- g(undefined);
- });
- });
- } else if (v == "bigger") {
- setTemplateFilter(true);
- var filt = nameFilters;
- filt["smaller-tf"] = false;
- filt["bigger-tf"] = true;
- setNameFilters(filt);
- var filt2 = filters;
- filt2.push(bigger);
-
- filt2.splice(filt2.indexOf(smaller), 1);
-
- setFilters(filt2);
- serverList.editFilters(filters);
-
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
-
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
-
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
-
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- g(undefined);
- });
- });
- } else {
- var filt = nameFilters;
- filt["smaller-tf"] = false;
- filt["bigger-tf"] = false;
- setNameFilters(filt);
- setTemplateFilter(false);
-
- var filt2 = filters;
- filt2.splice(filt2.indexOf(smaller), 1);
- filt2.splice(filt2.indexOf(bigger), 1);
- setFilters(filt2);
- console.log(filters, filters.includes(smaller));
- serverList.editFilters(filters);
-
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
-
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
-
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
-
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- g(undefined);
- });
- });
- }
- }),
- {
- error: "Error while changing filters",
- loading: "Changing filters...",
- success: "Changed filters!",
- }
- );
- }}
- value={(() => {
- if (nameFilters["smaller-tf"]) {
- return "smaller";
- } else if (nameFilters["bigger-tf"]) {
- return "bigger";
- } else {
- return "none";
- }
- })()}
- >
-
-
- Only allow smaller servers
-
-
- Only allow servers that have the player range 7-15, and
- cannot
- be Always Online.
-
-
-
-
-
- Only allow bigger servers
-
-
- Only allow servers with more than 15 players.
-
-
-
-
- No/custom requirements
-
-
-
-
- Tags
-
- {allTags.map((tag) => (
-
- {tag.docsName && tag.__filter == undefined && (
- {
- return nameFilters["t-" + tag.docsName];
- })()}
- onCheckedChange={async (b) => {
- var filt = nameFilters;
- filt["t-" + tag.docsName] = b;
- setNameFilters(filt);
- if (b) {
- var filt2 = filters;
- filt2.push(tag.condition);
- setFilters(filt2);
- } else {
- var filt2 = filters;
- filt2.splice(filt2.indexOf(tag.condition), 1);
- setFilters(filt2);
- }
- serverList.editFilters(filters);
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
-
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
-
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
-
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- });
- });
- }}
- >
-
- {tag.docsName}
-
-
- )}
-
- ))}
-
-
-
- Categories
-
-
- {allCategories.map((categorie) => (
- {
- var filt = nameFilters;
- filt["c-" + categorie.name] = b;
- setNameFilters(filt);
- if (b) {
- var filt2 = filters;
- filt2.push(categorie.condition);
- setFilters(filt2);
- } else {
- var filt2 = filters;
- filt2.splice(filt2.indexOf(categorie.condition), 1);
- setFilters(filt2);
- }
- serverList.editFilters(filters);
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
-
- let stringList: Array<{ server: string; motd: string }> =
- [];
- let obj: any = {};
-
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
-
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- });
- });
- }}
- checked={(() => {
- return nameFilters["c-" + categorie.name];
- })()}
- >
-
- {categorie.name}
-
-
- ))}
-
-
-
- View
-
-
- Grid
-
-
-
- 4 items per row
-
-
- 5 items per row
-
-
- 6 items per row
-
-
-
-
-
- Sort
-
-
- c == "favorites" && router.push("/sort/favorites")
+ }
+ className="relative z-0"
+ desc={
+
+
= 3200
+ ? "bg-clip-text text-transparent bg-gradient-to-r from-cyan-500 to-blue-500 "
+ : ""
}
>
-
- Players Online
-
-
- Favorites
-
-
-
-
-
-
-
-
-
-
-
- {randomData == undefined && <>No data to randomize>}
- {randomData != undefined && (
-
-
- {randomData.name}
- {randomData.author != undefined ? (
-
- by {randomData.author}
+ {serverList.getExtraData().total_servers.toString()}
- ) : (
-
- )}
-
-
-
-
- {randomData.playerData.playerCount == 0 ? (
-
- ) : (
-
+ {serverList.getExtraData().total_servers >= 3200 && (
+
+
+
+
+
+ The server amount is over 3.2k, meaning that new servers
+ have to go into a queue before being able to be online.{" "}
+
+ (the server count isn't entirely accurate, so sometimes
+ you might not go into a queue even when the server count
+ is at 3.2k)
+
+
)}
-
-
- {randomData.playerData.playerCount}{" "}
- {randomData.playerData.playerCount == 1
- ? "player"
- : "players"}{" "}
- currently online
-
-
-
- Server IP
-
-
-
- {randomData.name}.minehut.gg{" "}
- {
- setTextCopied(true);
- clipboard.writeText(randomData.name + ".mshf.minehut.gg");
- toast.success("Copied!");
- setTimeout(() => setTextCopied(false), 1000);
- }}
- >
- {textCopied ? (
-
- ) : (
- Copy
- )}
-
-
-
-
- )}
-
-
-
-
-
{
- serverList.moveListDown();
- let stringList: Array<{ server: string; motd: string }> = [];
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
-
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- setLoading(false);
- });
- }}
- loader={ }
- endMessage={
-
You've seen it all ",
- }}
- />
- }
- style={{ overflow: "hidden !important", paddingLeft: 6 }}
- >
-
-
- {servers.map((b: any) => (
- <>
-
- >
- ))}
+
+ }
+ icon={Network}
+ >
+ {serverList.getExtraData().total_servers >= 3200 && (
+
+ )}
+
+
+ {serverList.currentServers[0] != undefined
+ ? serverList.currentServers[0].name
+ : "None"}{" "}
+ {serverList.currentServers[0] != undefined && (
+
+ )}
+ >
+ }
+ icon={Sun}
+ />
-
- >
+
+
+
+
+
+ Servers
+
+ events.emit("search-request-event")}
+ >
+ Search Servers
+
+
+ +Shift+K
+
+
+ {
+ setRandomData(serverList.getRandomServer());
+ setRandom(true);
+ }}
+ >
+ Pick Random Server
+
+
+ {
+ toast.promise(
+ new Promise((s, e) => {
+ setLoading(true);
+ serverList
+ .fetchDataAndFilter()
+ .then(() => {
+ serverList.moveListDown();
+
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
+
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
+
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ setLoading(false);
+ s(false);
+ });
+ })
+ .catch(() => {
+ e();
+ });
+ }),
+ {
+ success: "Succesfully refreshed servers",
+ loading: "Refreshing...",
+ error: "Error while refreshing",
+ }
+ );
+ }}
+ >
+ Refresh
+
+
+
+
+ Filter
+
+ {
+ toast.promise(
+ new Promise((g, b) => {
+ if (v == "smaller") {
+ setTemplateFilter(true);
+ var filt = nameFilters;
+ filt["smaller-tf"] = true;
+ filt["bigger-tf"] = false;
+ setNameFilters(filt);
+
+ var filt2 = filters;
+ filt2.push(smaller);
+ if (filt2.includes(bigger)) {
+ filt2.splice(filt2.indexOf(bigger), 1);
+ }
+ setFilters(filt2);
+ serverList.editFilters(filters);
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
+
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
+
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
+
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ g(undefined);
+ });
+ });
+ } else if (v == "bigger") {
+ setTemplateFilter(true);
+ var filt = nameFilters;
+ filt["smaller-tf"] = false;
+ filt["bigger-tf"] = true;
+ setNameFilters(filt);
+ var filt2 = filters;
+ filt2.push(bigger);
+
+ filt2.splice(filt2.indexOf(smaller), 1);
+
+ setFilters(filt2);
+ serverList.editFilters(filters);
+
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
+
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
+
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
+
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ g(undefined);
+ });
+ });
+ } else {
+ var filt = nameFilters;
+ filt["smaller-tf"] = false;
+ filt["bigger-tf"] = false;
+ setNameFilters(filt);
+ setTemplateFilter(false);
+
+ var filt2 = filters;
+ filt2.splice(filt2.indexOf(smaller), 1);
+ filt2.splice(filt2.indexOf(bigger), 1);
+ setFilters(filt2);
+ console.log(filters, filters.includes(smaller));
+ serverList.editFilters(filters);
+
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
+
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
+
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
+
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ g(undefined);
+ });
+ });
+ }
+ }),
+ {
+ error: "Error while changing filters",
+ loading: "Changing filters...",
+ success: "Changed filters!",
+ }
+ );
+ }}
+ value={(() => {
+ if (nameFilters["smaller-tf"]) {
+ return "smaller";
+ } else if (nameFilters["bigger-tf"]) {
+ return "bigger";
+ } else {
+ return "none";
+ }
+ })()}
+ >
+
+
+ Only allow smaller servers
+
+
+ Only allow servers that have the player range 7-15, and
+ cannot
+ be Always Online.
+
+
+
+
+
+ Only allow bigger servers
+
+
+ Only allow servers with more than 15 players.
+
+
+
+
+ No/custom requirements
+
+
+
+
+
+ Tags
+
+
+ {allTags.map((tag) => (
+
+ {tag.docsName && tag.__filter == undefined && (
+ {
+ return nameFilters["t-" + tag.docsName];
+ })()}
+ onCheckedChange={async (b) => {
+ var filt = nameFilters;
+ filt["t-" + tag.docsName] = b;
+ setNameFilters(filt);
+ if (b) {
+ var filt2 = filters;
+ filt2.push(tag.condition);
+ setFilters(filt2);
+ } else {
+ var filt2 = filters;
+ filt2.splice(filt2.indexOf(tag.condition), 1);
+ setFilters(filt2);
+ }
+ serverList.editFilters(filters);
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
+
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
+
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
+
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ });
+ });
+ }}
+ >
+
+ {tag.docsName}
+
+
+ )}
+
+ ))}
+
+
+
+ Categories
+
+
+ {allCategories.map((categorie) => (
+ {
+ var filt = nameFilters;
+ filt["c-" + categorie.name] = b;
+ setNameFilters(filt);
+ if (b) {
+ var filt2 = filters;
+ filt2.push(categorie.condition);
+ setFilters(filt2);
+ } else {
+ var filt2 = filters;
+ filt2.splice(filt2.indexOf(categorie.condition), 1);
+ setFilters(filt2);
+ }
+ serverList.editFilters(filters);
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
+
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
+
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
+
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach((b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ });
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ });
+ });
+ }}
+ checked={(() => {
+ return nameFilters["c-" + categorie.name];
+ })()}
+ >
+
+ {categorie.name}
+
+
+ ))}
+
+
+
+ View
+
+
+ Grid
+
+
+
+ 4 items per row
+
+
+ 5 items per row
+
+
+ 6 items per row
+
+
+
+
+
+ Padding
+
+ setPadding(Number(v))}
+ >
+ Default
+
+ 15px
+ 30px
+ 40px
+ 60px
+ 100px
+ 200px
+
+
+
+ Only use padding on servers
+
+
+
+
+ Sort
+
+
+ c == "favorites" && router.push("/sort/favorites")
+ }
+ >
+
+ Players Online
+
+
+ Favorites
+
+
+
+
+
+
+
+ Show Hero
+
+
+
+
+
+
+
+
+
+ {randomData == undefined && <>No data to randomize>}
+ {randomData != undefined && (
+
+
+ {randomData.name}
+ {randomData.author != undefined ? (
+
+ by {randomData.author}
+
+ ) : (
+
+ )}
+
+
+
+
+ {randomData.playerData.playerCount == 0 ? (
+
+ ) : (
+
+ )}
+
+
+ {randomData.playerData.playerCount}{" "}
+ {randomData.playerData.playerCount == 1
+ ? "player"
+ : "players"}{" "}
+ currently online
+
+
+
+ Server IP
+
+
+
+ {randomData.name}.minehut.gg{" "}
+ {
+ setTextCopied(true);
+ clipboard.writeText(
+ randomData.name + ".mshf.minehut.gg"
+ );
+ toast.success("Copied!");
+ setTimeout(() => setTextCopied(false), 1000);
+ }}
+ >
+ {textCopied ? (
+
+ ) : (
+ Copy
+ )}
+
+
+
+
+ )}
+
+
+
+
+
{
+ serverList.moveListDown();
+ let stringList: Array<{ server: string; motd: string }> = [];
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
+
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach((b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ });
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ setLoading(false);
+ });
+ }}
+ loader={ }
+ endMessage={
+
You've seen it all ",
+ }}
+ />
+ }
+ style={{
+ overflow: "hidden !important",
+ paddingLeft: pOS ? padding : 6,
+ paddingRight: pOS ? padding : 6,
+ }}
+ >
+
+ {/** This looks stupid, but its the only way that works */}
+
+ {servers.map((b: any) => (
+ <>
+
+ >
+ ))}
+
+
+
+
+
);
}
diff --git a/src/components/clerk/SignInPopoverButton.tsx b/src/components/clerk/SignInPopoverButton.tsx
index 47ebde7..fec0616 100644
--- a/src/components/clerk/SignInPopoverButton.tsx
+++ b/src/components/clerk/SignInPopoverButton.tsx
@@ -21,8 +21,6 @@ export default function SignInPopoverButton({
| "ghost"
| "link";
}) {
- const clerk = useClerk();
-
return (
@@ -31,22 +29,29 @@ export default function SignInPopoverButton({
-
-
Login
-
- Make comments about servers and favorite servers. Secured by Clerk
-
-
-
clerk.openSignIn()}>
-
- Login
-
-
clerk.openSignUp()}>
-
- Sign-up
-
-
+
);
}
+
+export function SignInPopover() {
+ const clerk = useClerk();
+ return (
+
+
Login
+
+ Customize your own servers and favorite other servers. Secured by Clerk
+
+
+
clerk.openSignIn()}>
+
+ Login
+
+
clerk.openSignUp()}>
+
+ Sign-up
+
+
+ );
+}
diff --git a/src/components/effects/bento-grid.tsx b/src/components/effects/bento-grid.tsx
new file mode 100644
index 0000000..866558b
--- /dev/null
+++ b/src/components/effects/bento-grid.tsx
@@ -0,0 +1,79 @@
+import { ReactNode } from "react";
+import { ArrowRightIcon } from "@radix-ui/react-icons";
+
+import { cn } from "@/lib/utils";
+import { Button } from "@/components/ui/button";
+
+const BentoGrid = ({
+ children,
+ className,
+}: {
+ children: ReactNode;
+ className?: string;
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const BentoCard = ({
+ name,
+ className,
+ background,
+ Icon,
+ description,
+ href,
+ cta,
+}: {
+ name: string;
+ className: string;
+ background: ReactNode;
+ Icon: any;
+ description: string;
+ href: string;
+ cta: string;
+}) => (
+
+
{background}
+
+
+
+ {name}
+
+
{description}
+
+
+
+
+
+);
+
+export { BentoCard, BentoGrid };
diff --git a/src/components/effects/marquee.tsx b/src/components/effects/marquee.tsx
new file mode 100644
index 0000000..6f50a86
--- /dev/null
+++ b/src/components/effects/marquee.tsx
@@ -0,0 +1,51 @@
+import { cn } from "@/lib/utils";
+
+interface MarqueeProps {
+ className?: string;
+ reverse?: boolean;
+ pauseOnHover?: boolean;
+ children?: React.ReactNode;
+ vertical?: boolean;
+ repeat?: number;
+ [key: string]: any;
+}
+
+export default function Marquee({
+ className,
+ reverse,
+ pauseOnHover = false,
+ children,
+ vertical = false,
+ repeat = 4,
+ ...props
+}: MarqueeProps) {
+ return (
+
+ {Array(repeat)
+ .fill(0)
+ .map((_, i) => (
+
+ {children}
+
+ ))}
+
+ );
+}
diff --git a/src/components/effects/particles.tsx b/src/components/effects/particles.tsx
new file mode 100644
index 0000000..d08df37
--- /dev/null
+++ b/src/components/effects/particles.tsx
@@ -0,0 +1,278 @@
+"use client";
+
+import React, { useEffect, useRef, useState } from "react";
+
+interface MousePosition {
+ x: number;
+ y: number;
+}
+
+function MousePosition(): MousePosition {
+ const [mousePosition, setMousePosition] = useState({
+ x: 0,
+ y: 0,
+ });
+
+ useEffect(() => {
+ const handleMouseMove = (event: MouseEvent) => {
+ setMousePosition({ x: event.clientX, y: event.clientY });
+ };
+
+ window.addEventListener("mousemove", handleMouseMove);
+
+ return () => {
+ window.removeEventListener("mousemove", handleMouseMove);
+ };
+ }, []);
+
+ return mousePosition;
+}
+
+interface ParticlesProps {
+ className?: string;
+ quantity?: number;
+ staticity?: number;
+ ease?: number;
+ size?: number;
+ refresh?: boolean;
+ color?: string;
+ vx?: number;
+ vy?: number;
+}
+function hexToRgb(hex: string): number[] {
+ hex = hex.replace("#", "");
+
+ if (hex.length === 3) {
+ hex = hex
+ .split("")
+ .map((char) => char + char)
+ .join("");
+ }
+
+ const hexInt = parseInt(hex, 16);
+ const red = (hexInt >> 16) & 255;
+ const green = (hexInt >> 8) & 255;
+ const blue = hexInt & 255;
+ return [red, green, blue];
+}
+
+const Particles: React.FC = ({
+ className = "",
+ quantity = 100,
+ staticity = 50,
+ ease = 50,
+ size = 0.4,
+ refresh = false,
+ color = "#ffffff",
+ vx = 0,
+ vy = 0,
+}) => {
+ const canvasRef = useRef(null);
+ const canvasContainerRef = useRef(null);
+ const context = useRef(null);
+ const circles = useRef([]);
+ const mousePosition = MousePosition();
+ const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
+ const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });
+ const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1;
+
+ useEffect(() => {
+ if (canvasRef.current) {
+ context.current = canvasRef.current.getContext("2d");
+ }
+ initCanvas();
+ animate();
+ window.addEventListener("resize", initCanvas);
+
+ return () => {
+ window.removeEventListener("resize", initCanvas);
+ };
+ }, [color]);
+
+ useEffect(() => {
+ onMouseMove();
+ }, [mousePosition.x, mousePosition.y]);
+
+ useEffect(() => {
+ initCanvas();
+ }, [refresh]);
+
+ const initCanvas = () => {
+ resizeCanvas();
+ drawParticles();
+ };
+
+ const onMouseMove = () => {
+ if (canvasRef.current) {
+ const rect = canvasRef.current.getBoundingClientRect();
+ const { w, h } = canvasSize.current;
+ const x = mousePosition.x - rect.left - w / 2;
+ const y = mousePosition.y - rect.top - h / 2;
+ const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2;
+ if (inside) {
+ mouse.current.x = x;
+ mouse.current.y = y;
+ }
+ }
+ };
+
+ type Circle = {
+ x: number;
+ y: number;
+ translateX: number;
+ translateY: number;
+ size: number;
+ alpha: number;
+ targetAlpha: number;
+ dx: number;
+ dy: number;
+ magnetism: number;
+ };
+
+ const resizeCanvas = () => {
+ if (canvasContainerRef.current && canvasRef.current && context.current) {
+ circles.current.length = 0;
+ canvasSize.current.w = canvasContainerRef.current.offsetWidth;
+ canvasSize.current.h = canvasContainerRef.current.offsetHeight;
+ canvasRef.current.width = canvasSize.current.w * dpr;
+ canvasRef.current.height = canvasSize.current.h * dpr;
+ canvasRef.current.style.width = `${canvasSize.current.w}px`;
+ canvasRef.current.style.height = `${canvasSize.current.h}px`;
+ context.current.scale(dpr, dpr);
+ }
+ };
+
+ const circleParams = (): Circle => {
+ const x = Math.floor(Math.random() * canvasSize.current.w);
+ const y = Math.floor(Math.random() * canvasSize.current.h);
+ const translateX = 0;
+ const translateY = 0;
+ const pSize = Math.floor(Math.random() * 2) + size;
+ const alpha = 0;
+ const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1));
+ const dx = (Math.random() - 0.5) * 0.1;
+ const dy = (Math.random() - 0.5) * 0.1;
+ const magnetism = 0.1 + Math.random() * 4;
+ return {
+ x,
+ y,
+ translateX,
+ translateY,
+ size: pSize,
+ alpha,
+ targetAlpha,
+ dx,
+ dy,
+ magnetism,
+ };
+ };
+
+ const rgb = hexToRgb(color);
+
+ const drawCircle = (circle: Circle, update = false) => {
+ if (context.current) {
+ const { x, y, translateX, translateY, size, alpha } = circle;
+ context.current.translate(translateX, translateY);
+ context.current.beginPath();
+ context.current.arc(x, y, size, 0, 2 * Math.PI);
+ context.current.fillStyle = `rgba(${rgb.join(", ")}, ${alpha})`;
+ context.current.fill();
+ context.current.setTransform(dpr, 0, 0, dpr, 0, 0);
+
+ if (!update) {
+ circles.current.push(circle);
+ }
+ }
+ };
+
+ const clearContext = () => {
+ if (context.current) {
+ context.current.clearRect(
+ 0,
+ 0,
+ canvasSize.current.w,
+ canvasSize.current.h,
+ );
+ }
+ };
+
+ const drawParticles = () => {
+ clearContext();
+ const particleCount = quantity;
+ for (let i = 0; i < particleCount; i++) {
+ const circle = circleParams();
+ drawCircle(circle);
+ }
+ };
+
+ const remapValue = (
+ value: number,
+ start1: number,
+ end1: number,
+ start2: number,
+ end2: number,
+ ): number => {
+ const remapped =
+ ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
+ return remapped > 0 ? remapped : 0;
+ };
+
+ const animate = () => {
+ clearContext();
+ circles.current.forEach((circle: Circle, i: number) => {
+ // Handle the alpha value
+ const edge = [
+ circle.x + circle.translateX - circle.size, // distance from left edge
+ canvasSize.current.w - circle.x - circle.translateX - circle.size, // distance from right edge
+ circle.y + circle.translateY - circle.size, // distance from top edge
+ canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
+ ];
+ const closestEdge = edge.reduce((a, b) => Math.min(a, b));
+ const remapClosestEdge = parseFloat(
+ remapValue(closestEdge, 0, 20, 0, 1).toFixed(2),
+ );
+ if (remapClosestEdge > 1) {
+ circle.alpha += 0.02;
+ if (circle.alpha > circle.targetAlpha) {
+ circle.alpha = circle.targetAlpha;
+ }
+ } else {
+ circle.alpha = circle.targetAlpha * remapClosestEdge;
+ }
+ circle.x += circle.dx + vx;
+ circle.y += circle.dy + vy;
+ circle.translateX +=
+ (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /
+ ease;
+ circle.translateY +=
+ (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /
+ ease;
+
+ drawCircle(circle, true);
+
+ // circle gets out of the canvas
+ if (
+ circle.x < -circle.size ||
+ circle.x > canvasSize.current.w + circle.size ||
+ circle.y < -circle.size ||
+ circle.y > canvasSize.current.h + circle.size
+ ) {
+ // remove the circle from the array
+ circles.current.splice(i, 1);
+ // create a new circle
+ const newCircle = circleParams();
+ drawCircle(newCircle);
+ // update the circle position
+ }
+ });
+ window.requestAnimationFrame(animate);
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default Particles;
diff --git a/src/components/effects/sparkles-text.tsx b/src/components/effects/sparkles-text.tsx
new file mode 100644
index 0000000..defbbf6
--- /dev/null
+++ b/src/components/effects/sparkles-text.tsx
@@ -0,0 +1,152 @@
+"use client";
+
+import { CSSProperties, ReactElement, useEffect, useState } from "react";
+import { motion } from "framer-motion";
+
+import { cn } from "@/lib/utils";
+
+interface Sparkle {
+ id: string;
+ x: string;
+ y: string;
+ color: string;
+ delay: number;
+ scale: number;
+ lifespan: number;
+}
+
+interface SparklesTextProps {
+ /**
+ * @default
+ * @type ReactElement
+ * @description
+ * The component to be rendered as the text
+ * */
+ as?: ReactElement;
+
+ /**
+ * @default ""
+ * @type string
+ * @description
+ * The className of the text
+ */
+ className?: string;
+
+ /**
+ * @required
+ * @type string
+ * @description
+ * The text to be displayed
+ * */
+ children: JSX.Element;
+
+ /**
+ * @default 10
+ * @type number
+ * @description
+ * The count of sparkles
+ * */
+ sparklesCount?: number;
+
+ /**
+ * @default "{first: '#9E7AFF', second: '#FE8BBB'}"
+ * @type string
+ * @description
+ * The colors of the sparkles
+ * */
+ colors?: {
+ first: string;
+ second: string;
+ };
+}
+
+const SparklesText: React.FC = ({
+ children,
+ colors = { first: "#9E7AFF", second: "#FE8BBB" },
+ className,
+ sparklesCount = 10,
+ ...props
+}) => {
+ const [sparkles, setSparkles] = useState([]);
+
+ useEffect(() => {
+ const generateStar = (): Sparkle => {
+ const starX = `${Math.random() * 100}%`;
+ const starY = `${Math.random() * 100}%`;
+ const color = Math.random() > 0.5 ? colors.first : colors.second;
+ const delay = Math.random() * 2;
+ const scale = Math.random() * 1 + 0.3;
+ const lifespan = Math.random() * 10 + 5;
+ const id = `${starX}-${starY}-${Date.now()}`;
+ return { id, x: starX, y: starY, color, delay, scale, lifespan };
+ };
+
+ const initializeStars = () => {
+ const newSparkles = Array.from({ length: sparklesCount }, generateStar);
+ setSparkles(newSparkles);
+ };
+
+ const updateStars = () => {
+ setSparkles((currentSparkles) =>
+ currentSparkles.map((star) => {
+ if (star.lifespan <= 0) {
+ return generateStar();
+ } else {
+ return { ...star, lifespan: star.lifespan - 0.1 };
+ }
+ })
+ );
+ };
+
+ initializeStars();
+ const interval = setInterval(updateStars, 100);
+
+ return () => clearInterval(interval);
+ }, [colors.first, colors.second]);
+
+ return (
+
+
+ {sparkles.map((sparkle) => (
+
+ ))}
+ {children}
+
+
+ );
+};
+
+const Sparkle: React.FC = ({ id, x, y, color, delay, scale }) => {
+ return (
+
+
+
+ );
+};
+
+export default SparklesText;
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index dfe20c7..9a3286a 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
+ "inline-flex items-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
@@ -39,14 +39,22 @@ export interface ButtonProps
extends React.ButtonHTMLAttributes,
VariantProps {
asChild?: boolean;
+ noJustify?: boolean;
}
const Button = React.forwardRef(
- ({ className, variant, size, asChild = false, ...props }, ref) => {
+ (
+ { className, variant, size, asChild = false, noJustify = false, ...props },
+ ref
+ ) => {
const Comp = asChild ? Slot : "button";
return (
diff --git a/src/version.tsx b/src/version.tsx
index 81333f7..e5e1687 100644
--- a/src/version.tsx
+++ b/src/version.tsx
@@ -2,16 +2,15 @@ import Image from "next/image";
import Link from "next/link";
import { Separator } from "./components/ui/separator";
import { Button } from "./components/ui/button";
-import Confetti, { ConfettiButton } from "./components/effects/confetti";
+import confetti from "canvas-confetti";
-export const version = "1.0";
+export const version = "1.1.0";
const User = ({ user }: { user: string }) => (
{user}
);
-import confetti from "canvas-confetti";
const handleClick = () => {
const duration = 5 * 1000;
const animationEnd = Date.now() + duration;
@@ -78,6 +77,17 @@ export const Changelog = () => (
+
+
+ Version 1.1.0 (August 24rd 2024)
+
+
+ • Brand new hero page
+ • New padding option on server list
+ • New help guide
+
+
+
Version 1.0.0 (August 22nd 2024)
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 8112d69..07babbc 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -59,6 +59,19 @@ const config = {
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
+ 'image-glow': {
+ '0%': {
+ 'opacity': '0',
+ 'animation-timing-function': 'cubic-bezier(0.74, 0.25, 0.76, 1)',
+ },
+ '10%': {
+ 'opacity': '0.7',
+ 'animation-timing-function': 'cubic-bezier(0.12, 0.01, 0.08, 0.99)',
+ },
+ '100%': {
+ opacity: '0.4',
+ },
+ },
"border-beam": {
"100%": {
"offset-distance": "100%",
@@ -77,12 +90,45 @@ const config = {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
+
+ "fade-in": {
+ from: { opacity: "0", transform: "translateY(-10px)" },
+ to: { opacity: "1", transform: "none" },
+ },
+ marquee: {
+ from: { transform: "translateX(0)" },
+ to: { transform: "translateX(calc(-100% - var(--gap)))" },
+ },
+ "marquee-vertical": {
+ from: { transform: "translateY(0)" },
+ to: { transform: "translateY(calc(-100% - var(--gap)))" },
+ },
+ "fade-up": {
+ from: { opacity: "0", transform: "translateY(20px)" },
+ to: { opacity: "1", transform: "none" },
+ },
+
+ 'shimmer': {
+ '0%, 90%, 100%': {
+ 'background-position': 'calc(-100% - var(--shimmer-width)) 0',
+ },
+ '30%, 60%': {
+ 'background-position': 'calc(100% + var(--shimmer-width)) 0',
+ },
+ },
},
animation: {
+ marquee: "marquee var(--duration) linear infinite",
+ "marquee-vertical": "marquee-vertical var(--duration) linear infinite",
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
+ 'image-glow': 'image-glow 4100ms 600ms ease-out forwards',
+ 'shimmer': 'shimmer 8s infinite',
+ "fade-in": "fade-in 1000ms var(--animation-delay, 0ms) ease forwards",
"caret-blink": "caret-blink 1.25s ease-out infinite",
"border-beam": "border-beam calc(var(--duration)*1s) infinite linear",
+
+ "fade-up": "fade-up 1000ms var(--animation-delay, 0ms) ease forwards",
},
},
},