mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-09 14:43:03 -04:00
Updates
This commit is contained in:
parent
418568097c
commit
b26faf2e37
10 changed files with 956 additions and 479 deletions
|
@ -8,6 +8,7 @@ import "./style.css";
|
|||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { waitFor } from "@webpack";
|
||||
import { UserStore } from "@webpack/common";
|
||||
|
@ -15,6 +16,7 @@ import { UserStore } from "@webpack/common";
|
|||
let ChannelTextAreaClasses;
|
||||
let shouldShowColorEffects: boolean;
|
||||
let position: boolean;
|
||||
let forceLeft = false;
|
||||
|
||||
waitFor(["buttonContainer", "channelTextArea"], m => (ChannelTextAreaClasses = m));
|
||||
|
||||
|
@ -68,7 +70,7 @@ export default definePlugin({
|
|||
charCounterDiv = document.createElement("div");
|
||||
charCounterDiv.classList.add("char-counter");
|
||||
|
||||
if (position) charCounterDiv.classList.add("left");
|
||||
if (position || forceLeft) charCounterDiv.classList.add("left");
|
||||
|
||||
charCounterDiv.innerHTML = `<span class="char-count">0</span>/<span class="char-max">${charMax}</span>`;
|
||||
}
|
||||
|
@ -120,7 +122,10 @@ export default definePlugin({
|
|||
const observeDOMChanges = () => {
|
||||
const observer = new MutationObserver(() => {
|
||||
const chatTextArea = document.querySelector(`.${ChannelTextAreaClasses?.channelTextArea}`);
|
||||
if (chatTextArea) {
|
||||
if (chatTextArea && !document.querySelector(".char-counter")) {
|
||||
const currentChannel = getCurrentChannel();
|
||||
forceLeft = currentChannel?.rateLimitPerUser !== 0;
|
||||
|
||||
addCharCounter();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
color: var(--text-muted);
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
bottom: -15px;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
|
|
|
@ -5,16 +5,13 @@
|
|||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Button, useEffect, useRef, UserStore, useState } from "@webpack/common";
|
||||
import type { User } from "discord-types/general";
|
||||
|
||||
import type { Theme, ThemeLikeProps } from "../types";
|
||||
import { isAuthorized } from "../utils/auth";
|
||||
import { LikeIcon } from "../utils/Icons";
|
||||
import { themeRequest } from "./ThemeTab";
|
||||
|
||||
export const logger = new Logger("ThemeLibrary", "#e5c890");
|
||||
import { logger, themeRequest } from "./ThemeTab";
|
||||
|
||||
export const LikesComponent = ({ themeId, likedThemes: initialLikedThemes }: { themeId: Theme["id"], likedThemes: ThemeLikeProps | undefined; }) => {
|
||||
const [likesCount, setLikesCount] = useState(0);
|
||||
|
@ -35,7 +32,7 @@ export const LikesComponent = ({ themeId, likedThemes: initialLikedThemes }: { t
|
|||
if (!isAuthorized()) return;
|
||||
const theme = likedThemes?.likes.find(like => like.themeId === themeId as unknown as Number);
|
||||
const currentUser: User = UserStore.getCurrentUser();
|
||||
const hasLiked: boolean = theme?.userIds.includes(currentUser.id) ?? false;
|
||||
const hasLiked: boolean = (theme?.userIds.includes(currentUser.id) || themeId === "preview") ?? false;
|
||||
const endpoint = hasLiked ? "/likes/remove" : "/likes/add";
|
||||
const token = await DataStore.get("ThemeLibrary_uniqueToken");
|
||||
|
||||
|
@ -83,9 +80,10 @@ export const LikesComponent = ({ themeId, likedThemes: initialLikedThemes }: { t
|
|||
size={Button.Sizes.MEDIUM}
|
||||
color={Button.Colors.PRIMARY}
|
||||
look={Button.Looks.OUTLINED}
|
||||
disabled={themeId === "preview"}
|
||||
style={{ marginLeft: "8px" }}
|
||||
>
|
||||
{LikeIcon(hasLiked)} {likesCount}
|
||||
{LikeIcon(hasLiked || themeId === "preview")} {themeId === "preview" ? 143 : likesCount}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
|
180
src/equicordplugins/themeLibrary/components/ThemeCard.tsx
Normal file
180
src/equicordplugins/themeLibrary/components/ThemeCard.tsx
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { generateId } from "@api/Commands";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { OpenExternalIcon } from "@components/Icons";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { Button, Card, FluxDispatcher, Forms, Parser, React, UserStore, UserUtils } from "@webpack/common";
|
||||
import { User } from "discord-types/general";
|
||||
import { Constructor } from "type-fest";
|
||||
|
||||
import type { Theme, ThemeLikeProps } from "../types";
|
||||
import { LikesComponent } from "./LikesComponent";
|
||||
import { ThemeInfoModal } from "./ThemeInfoModal";
|
||||
import { apiUrl } from "./ThemeTab";
|
||||
|
||||
interface ThemeCardProps {
|
||||
theme: Theme;
|
||||
themeLinks: string[];
|
||||
likedThemes?: ThemeLikeProps;
|
||||
setThemeLinks: (links: string[]) => void;
|
||||
removePreview?: boolean;
|
||||
removeButtons?: boolean;
|
||||
}
|
||||
|
||||
const UserRecord: Constructor<Partial<User>> = proxyLazy(() => UserStore.getCurrentUser().constructor) as any;
|
||||
|
||||
function makeDummyUser(user: { username: string; id?: string; avatar?: string; }) {
|
||||
const newUser = new UserRecord({
|
||||
username: user.username,
|
||||
id: user.id ?? generateId(),
|
||||
avatar: user.avatar,
|
||||
bot: true,
|
||||
});
|
||||
FluxDispatcher.dispatch({
|
||||
type: "USER_UPDATE",
|
||||
user: newUser,
|
||||
});
|
||||
return newUser;
|
||||
}
|
||||
|
||||
export const ThemeCard: React.FC<ThemeCardProps> = ({ theme, themeLinks, likedThemes, setThemeLinks, removeButtons, removePreview }) => {
|
||||
|
||||
const getUser = (id: string, username: string) => UserUtils.getUser(id) ?? makeDummyUser({ username, id });
|
||||
|
||||
const handleAddRemoveTheme = () => {
|
||||
const onlineThemeLinks = themeLinks.includes(`${apiUrl}/${theme.name}`)
|
||||
? themeLinks.filter(link => link !== `${apiUrl}/${theme.name}`)
|
||||
: [...themeLinks, `${apiUrl}/${theme.name}`];
|
||||
|
||||
setThemeLinks(onlineThemeLinks);
|
||||
Vencord.Settings.themeLinks = onlineThemeLinks;
|
||||
};
|
||||
|
||||
const handleThemeAttributesCheck = () => {
|
||||
const requiresThemeAttributes = theme.requiresThemeAttributes ?? false;
|
||||
|
||||
if (requiresThemeAttributes && !Settings.plugins.ThemeAttributes.enabled) {
|
||||
openModal(modalProps => (
|
||||
<ModalRoot {...modalProps} size={ModalSize.SMALL}>
|
||||
<ModalHeader>
|
||||
<Forms.FormTitle tag="h4">Hold on!</Forms.FormTitle>
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<Forms.FormText style={{ padding: "8px" }}>
|
||||
<p>This theme requires the <b>ThemeAttributes</b> plugin to work properly!</p>
|
||||
<p>Do you want to enable it?</p>
|
||||
</Forms.FormText>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
look={Button.Looks.FILLED}
|
||||
color={Button.Colors.GREEN}
|
||||
onClick={() => {
|
||||
Settings.plugins.ThemeAttributes.enabled = true;
|
||||
modalProps.onClose();
|
||||
handleAddRemoveTheme();
|
||||
}}
|
||||
>
|
||||
Enable Plugin
|
||||
</Button>
|
||||
<Button
|
||||
color={Button.Colors.RED}
|
||||
look={Button.Looks.FILLED}
|
||||
className={Margins.right8}
|
||||
onClick={() => modalProps.onClose()}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
));
|
||||
} else {
|
||||
handleAddRemoveTheme();
|
||||
}
|
||||
};
|
||||
|
||||
const handleViewSource = () => {
|
||||
const content = window.atob(theme.content);
|
||||
const metadata = content.match(/\/\*\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g)?.[0] || "";
|
||||
const source = metadata.match(/@source\s+(.+)/)?.[1] || "";
|
||||
|
||||
if (source) {
|
||||
VencordNative.native.openExternal(source);
|
||||
} else {
|
||||
VencordNative.native.openExternal(`${apiUrl}/${theme.name}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card style={{ padding: ".5rem", marginBottom: ".5em", marginTop: ".5em", display: "flex", flexDirection: "column", backgroundColor: "var(--background-secondary-alt)" }} key={theme.id}>
|
||||
<Forms.FormTitle tag="h2" style={{ overflowWrap: "break-word", marginTop: 8 }} className="vce-theme-text">
|
||||
{theme.name}
|
||||
</Forms.FormTitle>
|
||||
<Forms.FormText className="vce-theme-text">
|
||||
{Parser.parse(theme.description)}
|
||||
</Forms.FormText>
|
||||
{!removePreview && (
|
||||
<img role="presentation" src={theme.thumbnail_url} loading="lazy" alt={theme.name} className="vce-theme-info-preview" />
|
||||
)}
|
||||
<div className="vce-theme-info">
|
||||
<div style={{ justifyContent: "flex-start", flexDirection: "column" }}>
|
||||
{theme.tags && (
|
||||
<Forms.FormText>
|
||||
{theme.tags.map(tag => (
|
||||
<span className="vce-theme-info-tag" key={tag}>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</Forms.FormText>
|
||||
)}
|
||||
{!removeButtons && (
|
||||
< div style={{ marginTop: "8px", display: "flex", flexDirection: "row" }}>
|
||||
<Button
|
||||
onClick={handleThemeAttributesCheck}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
color={themeLinks.includes(`${apiUrl}/${theme.name}`) ? Button.Colors.RED : Button.Colors.GREEN}
|
||||
look={Button.Looks.FILLED}
|
||||
className={Margins.right8}
|
||||
disabled={!theme.content || theme.id === "preview"}
|
||||
>
|
||||
{themeLinks.includes(`${apiUrl}/${theme.name}`) ? "Remove Theme" : "Add Theme"}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
const authors = Array.isArray(theme.author)
|
||||
? await Promise.all(theme.author.map(author => getUser(author.discord_snowflake, author.discord_name)))
|
||||
: [await getUser(theme.author.discord_snowflake, theme.author.discord_name)];
|
||||
|
||||
openModal(props => <ThemeInfoModal {...props} author={authors} theme={theme} />);
|
||||
}}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
color={Button.Colors.BRAND}
|
||||
look={Button.Looks.FILLED}
|
||||
>
|
||||
Theme Info
|
||||
</Button>
|
||||
<LikesComponent themeId={theme.id} likedThemes={likedThemes} />
|
||||
<Button
|
||||
onClick={handleViewSource}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
color={Button.Colors.LINK}
|
||||
look={Button.Looks.LINK}
|
||||
disabled={!theme.content || theme.id === "preview"}
|
||||
style={{ display: "flex", alignItems: "center", justifyContent: "center" }}
|
||||
>
|
||||
View Source <OpenExternalIcon height={16} width={16} />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card >
|
||||
);
|
||||
};
|
|
@ -16,7 +16,7 @@ import { Button, Clipboard, Forms, Parser, React, showToast, Toasts } from "@web
|
|||
|
||||
import { Theme, ThemeInfoModalProps } from "../types";
|
||||
import { ClockIcon, DownloadIcon, WarningIcon } from "../utils/Icons";
|
||||
import { logger } from "./LikesComponent";
|
||||
import { logger } from "./ThemeTab";
|
||||
|
||||
const Native = VencordNative.pluginHelpers.ThemeLibrary as PluginNative<typeof import("../native")>;
|
||||
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
||||
|
@ -25,7 +25,7 @@ async function downloadTheme(themesDir: string, theme: Theme) {
|
|||
try {
|
||||
await Native.downloadTheme(themesDir, theme);
|
||||
showToast(`Downloaded ${theme.name}!`, Toasts.Type.SUCCESS);
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
logger.error(err);
|
||||
showToast(`Failed to download ${theme.name}! (check console)`, Toasts.Type.FAILURE);
|
||||
}
|
||||
|
@ -121,34 +121,36 @@ export const ThemeInfoModal: React.FC<ThemeInfoModalProps> = ({ author, theme, .
|
|||
)}
|
||||
<Forms.FormTitle tag="h5" style={{ marginTop: "10px" }}>Source</Forms.FormTitle>
|
||||
<Forms.FormText>
|
||||
<Button onClick={() => openModal(modalProps => (
|
||||
<ModalRoot {...modalProps} size={ModalSize.LARGE}>
|
||||
<ModalHeader>
|
||||
<Forms.FormTitle tag="h4">Theme Source</Forms.FormTitle>
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<Forms.FormText style={{
|
||||
padding: "8px",
|
||||
}}>
|
||||
<CodeBlock lang="css" content={themeContent} />
|
||||
</Forms.FormText>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
color={Button.Colors.RED}
|
||||
look={Button.Looks.OUTLINED}
|
||||
onClick={() => modalProps.onClose()}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button className={Margins.right8}
|
||||
onClick={() => {
|
||||
Clipboard.copy(themeContent);
|
||||
showToast("Copied to Clipboard", Toasts.Type.SUCCESS);
|
||||
}}>Copy to Clipboard</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
))}
|
||||
<Button
|
||||
disabled={!theme.content || theme.id === "preview"}
|
||||
onClick={() => openModal(modalProps => (
|
||||
<ModalRoot {...modalProps} size={ModalSize.LARGE}>
|
||||
<ModalHeader>
|
||||
<Forms.FormTitle tag="h4">Theme Source</Forms.FormTitle>
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<Forms.FormText style={{
|
||||
padding: "8px",
|
||||
}}>
|
||||
<CodeBlock lang="css" content={themeContent} />
|
||||
</Forms.FormText>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
color={Button.Colors.RED}
|
||||
look={Button.Looks.OUTLINED}
|
||||
onClick={() => modalProps.onClose()}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button className={Margins.right8}
|
||||
onClick={() => {
|
||||
Clipboard.copy(themeContent);
|
||||
showToast("Copied to Clipboard", Toasts.Type.SUCCESS);
|
||||
}}>Copy to Clipboard</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
))}
|
||||
>
|
||||
View Theme Source
|
||||
</Button>
|
||||
|
@ -190,6 +192,7 @@ export const ThemeInfoModal: React.FC<ThemeInfoModalProps> = ({ author, theme, .
|
|||
color={Button.Colors.GREEN}
|
||||
look={Button.Looks.OUTLINED}
|
||||
className={classes("vce-button", Margins.right8)}
|
||||
disabled={!theme.content || theme.id === "preview"}
|
||||
onClick={async () => {
|
||||
const themesDir = await VencordNative.themes.getThemesDir();
|
||||
const exists = await Native.themeExists(themesDir, theme);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -89,3 +89,41 @@
|
|||
border-radius: 8px;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.vce-image-paste {
|
||||
border-radius: 8px;
|
||||
border: 3px dashed var(--background-modifier-accent);
|
||||
background-color: var(--background-secondary);
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
margin-top: 20px;
|
||||
transition: border 0.3s ease;
|
||||
}
|
||||
|
||||
.vce-image-paste:hover {
|
||||
border: 3px dashed var(--brand-500);
|
||||
transition: border 0.3s ease;
|
||||
}
|
||||
|
||||
.vce-styled-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vce-styled-list li {
|
||||
padding: 10px 0;
|
||||
border-bottom: thin solid var(--background-modifier-accent);
|
||||
}
|
||||
|
||||
.vce-styled-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.vce-divider-border {
|
||||
border-bottom: thin solid var(--background-modifier-accent);
|
||||
padding: 10px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -4,51 +4,74 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { SettingsRouter } from "@webpack/common";
|
||||
import { ModalProps } from "@utils/modal";
|
||||
import { User } from "discord-types/general";
|
||||
|
||||
import { settings } from "./utils/settings";
|
||||
type Author = {
|
||||
github_name?: string;
|
||||
discord_name: string;
|
||||
discord_snowflake: string;
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "ThemeLibrary",
|
||||
description: "A library of themes for Vencord.",
|
||||
authors: [EquicordDevs.Fafa],
|
||||
settings,
|
||||
toolboxActions: {
|
||||
"Open Theme Library": () => {
|
||||
SettingsRouter.open("ThemeLibrary");
|
||||
},
|
||||
},
|
||||
export interface Theme {
|
||||
id: string;
|
||||
name: string;
|
||||
content: string;
|
||||
type: string | "theme" | "snippet";
|
||||
description: string;
|
||||
version: string;
|
||||
author: Author | Author[];
|
||||
likes: number;
|
||||
tags: string[];
|
||||
thumbnail_url: string;
|
||||
release_date: Date;
|
||||
last_updated?: Date;
|
||||
guild?: {
|
||||
name: string;
|
||||
snowflake: string;
|
||||
invite_link: string;
|
||||
};
|
||||
source?: string;
|
||||
requiresThemeAttributes?: boolean;
|
||||
}
|
||||
|
||||
start() {
|
||||
const customSettingsSections = (
|
||||
Vencord.Plugins.plugins.Settings as any as {
|
||||
customSections: ((ID: Record<string, unknown>) => any)[];
|
||||
}
|
||||
).customSections;
|
||||
export interface ThemeInfoModalProps extends ModalProps {
|
||||
author: User | User[];
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const ThemeSection = () => ({
|
||||
section: "ThemeLibrary",
|
||||
label: "Theme Library",
|
||||
element: require("./components/ThemeTab").default,
|
||||
id: "ThemeSection",
|
||||
});
|
||||
export const enum TabItem {
|
||||
THEMES,
|
||||
SUBMIT_THEMES,
|
||||
}
|
||||
|
||||
customSettingsSections.push(ThemeSection);
|
||||
},
|
||||
export interface LikesComponentProps {
|
||||
theme: Theme;
|
||||
userId: User["id"];
|
||||
}
|
||||
|
||||
stop() {
|
||||
const customSettingsSections = (
|
||||
Vencord.Plugins.plugins.Settings as any as {
|
||||
customSections: ((ID: Record<string, unknown>) => any)[];
|
||||
}
|
||||
).customSections;
|
||||
export const enum SearchStatus {
|
||||
ALL,
|
||||
ENABLED,
|
||||
DISABLED,
|
||||
THEME,
|
||||
SNIPPET,
|
||||
DARK,
|
||||
LIGHT,
|
||||
LIKED,
|
||||
}
|
||||
|
||||
const i = customSettingsSections.findIndex(
|
||||
section => section({}).id === "ThemeSection"
|
||||
);
|
||||
export type ThemeLikeProps = {
|
||||
status: number;
|
||||
likes: [{
|
||||
themeId: number;
|
||||
userIds: User["id"][];
|
||||
}];
|
||||
};
|
||||
|
||||
if (i !== -1) customSettingsSections.splice(i, 1);
|
||||
},
|
||||
});
|
||||
export interface Contributor {
|
||||
username: User["username"];
|
||||
github_username: string;
|
||||
id: User["id"];
|
||||
avatar: string;
|
||||
}
|
||||
|
|
|
@ -68,3 +68,10 @@ export type ThemeLikeProps = {
|
|||
userIds: User["id"][];
|
||||
}];
|
||||
};
|
||||
|
||||
export interface Contributor {
|
||||
username: User["username"];
|
||||
github_username: string;
|
||||
id: User["id"];
|
||||
avatar: string;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { showNotification } from "@api/Notifications";
|
|||
import { openModal } from "@utils/modal";
|
||||
import { OAuth2AuthorizeModal, Toasts, UserStore } from "@webpack/common";
|
||||
|
||||
import { logger } from "../components/LikesComponent";
|
||||
import { logger, themeRequest } from "../components/ThemeTab";
|
||||
|
||||
export async function authorizeUser(triggerModal: boolean = true) {
|
||||
const isAuthorized = await getAuthorization();
|
||||
|
@ -76,7 +76,7 @@ export async function deauthorizeUser() {
|
|||
}
|
||||
});
|
||||
|
||||
const res = await fetch("https://themes-delta.vercel.app/api/user/revoke", {
|
||||
const res = await themeRequest("/user/revoke", {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
|
@ -111,7 +111,7 @@ export async function getAuthorization() {
|
|||
return false;
|
||||
} else {
|
||||
// check if valid
|
||||
const res = await fetch("https://themes-delta.vercel.app/api/user/findUserByToken", {
|
||||
const res = await themeRequest("/user/findUserByToken", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue