feat: add default visibility setting to extension

This commit is contained in:
Steven 2024-04-05 22:54:03 +08:00
parent c6821a7090
commit e2c7b8c7b9
7 changed files with 147 additions and 40 deletions

View File

@ -1,8 +1,9 @@
import { Button, IconButton, Input, Modal, ModalDialog } from "@mui/joy";
import { useStorage } from "@plasmohq/storage/hook";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { useStorageContext } from "@/context";
import useShortcutStore from "@/store/shortcut";
import type { Visibility } from "@/types/proto/api/v1/common";
import { Shortcut } from "@/types/proto/api/v1/shortcut_service";
import Icon from "./Icon";
@ -13,8 +14,7 @@ interface State {
}
const CreateShortcutButton = () => {
const [instanceUrl] = useStorage("domain");
const [accessToken] = useStorage("access_token");
const context = useStorageContext();
const shortcutStore = useShortcutStore();
const [state, setState] = useState<State>({
name: "",
@ -101,13 +101,14 @@ const CreateShortcutButton = () => {
try {
const tags = tag.split(" ").filter(Boolean);
await shortcutStore.createShortcut(
instanceUrl,
accessToken,
context.instanceUrl,
context.accessToken,
Shortcut.fromPartial({
name: state.name,
title: state.title,
link: state.link,
tags,
visibility: context.defaultVisibility as Visibility,
})
);
toast.success("Shortcut created successfully");

View File

@ -1,24 +1,23 @@
import { IconButton } from "@mui/joy";
import { useStorage } from "@plasmohq/storage/hook";
import { useEffect } from "react";
import { toast } from "react-hot-toast";
import { useStorageContext } from "@/context";
import useShortcutStore from "@/store/shortcut";
import Icon from "./Icon";
const PullShortcutsButton = () => {
const [instanceUrl] = useStorage("domain");
const [accessToken] = useStorage("access_token");
const context = useStorageContext();
const shortcutStore = useShortcutStore();
useEffect(() => {
if (instanceUrl && accessToken) {
if (context.instanceUrl && context.accessToken) {
handlePullShortcuts(true);
}
}, [instanceUrl, accessToken]);
}, [context]);
const handlePullShortcuts = async (silence = false) => {
try {
await shortcutStore.fetchShortcutList(instanceUrl, accessToken);
await shortcutStore.fetchShortcutList(context.instanceUrl, context.accessToken);
if (!silence) {
toast.success("Shortcuts pulled");
}

View File

@ -0,0 +1,27 @@
import { createContext, useContext } from "react";
import { Visibility } from "@/types/proto/api/v1/common";
interface Context {
instanceUrl?: string;
accessToken?: string;
defaultVisibility: string;
setInstanceUrl: (instanceUrl: string) => void;
setAccessToken: (accessToken: string) => void;
setDefaultVisibility: (visibility: string) => void;
}
export const StorageContext = createContext<Context>({
instanceUrl: undefined,
accessToken: undefined,
defaultVisibility: Visibility.PRIVATE,
setInstanceUrl: () => {},
setAccessToken: () => {},
setDefaultVisibility: () => {},
});
const useStorageContext = () => {
const context = useContext(StorageContext);
return context;
};
export default useStorageContext;

View File

@ -0,0 +1,4 @@
import useStorageContext from "./context";
import StorageContextProvider from "./provider";
export { useStorageContext, StorageContextProvider };

View File

@ -0,0 +1,58 @@
import { Storage } from "@plasmohq/storage";
import { useEffect, useState } from "react";
import { Visibility } from "@/types/proto/api/v1/common";
import { StorageContext } from "./context";
interface Props {
children: React.ReactNode;
}
const StorageContextProvider = ({ children }: Props) => {
const storage = new Storage();
const [instanceUrl, setInstanceUrl] = useState<string | undefined>(undefined);
const [accessToken, setAccessToken] = useState<string | undefined>(undefined);
const [defaultVisibility, setDefaultVisibility] = useState<Visibility>(Visibility.PRIVATE);
const [isInitialized, setIsInitialized] = useState(false);
useEffect(() => {
(async () => {
const domain = await storage.get("domain");
const accessToken = await storage.get("access_token");
const defaultVisibility = (await storage.get("default_visibility")) as Visibility;
setInstanceUrl(domain);
setAccessToken(accessToken);
setDefaultVisibility(defaultVisibility);
setIsInitialized(true);
})();
storage.watch({
domain: (c) => {
setInstanceUrl(c.newValue);
},
access_token: (c) => {
setAccessToken(c.newValue);
},
default_visibility: (c) => {
setDefaultVisibility(c.newValue as Visibility);
},
});
}, []);
return (
<StorageContext.Provider
value={{
instanceUrl,
accessToken,
defaultVisibility,
setInstanceUrl: (instanceUrl: string) => storage.set("domain", instanceUrl),
setAccessToken: (accessToken: string) => storage.set("access_token", accessToken),
setDefaultVisibility: (visibility: Visibility) => storage.set("default_visibility", visibility),
}}
>
{isInitialized && children}
</StorageContext.Provider>
);
};
export default StorageContextProvider;

View File

@ -1,14 +1,15 @@
import { Button, CssVarsProvider, Divider, Input, Select, Option } from "@mui/joy";
import { useStorage } from "@plasmohq/storage/hook";
import { useEffect, useState } from "react";
import { Toaster, toast } from "react-hot-toast";
import Icon from "./components/Icon";
import Logo from "./components/Logo";
import PullShortcutsButton from "./components/PullShortcutsButton";
import ShortcutsContainer from "./components/ShortcutsContainer";
import { StorageContextProvider, useStorageContext } from "./context";
import useColorTheme from "./hooks/useColorTheme";
import useShortcutStore from "./store/shortcut";
import "./style.css";
import { Visibility } from "./types/proto/api/v1/common";
interface SettingState {
domain: string;
@ -32,22 +33,21 @@ const colorThemeOptions = [
const IndexOptions = () => {
const { colorTheme, setColorTheme } = useColorTheme();
const [domain, setDomain] = useStorage<string>("domain", (v) => (v ? v : ""));
const [accessToken, setAccessToken] = useStorage<string>("access_token", (v) => (v ? v : ""));
const context = useStorageContext();
const [settingState, setSettingState] = useState<SettingState>({
domain,
accessToken,
domain: context.instanceUrl || "",
accessToken: context.accessToken || "",
});
const shortcutStore = useShortcutStore();
const shortcuts = shortcutStore.getShortcutList();
const isInitialized = domain && accessToken;
const isInitialized = context.instanceUrl && context.accessToken;
useEffect(() => {
setSettingState({
domain,
accessToken,
domain: context.instanceUrl || "",
accessToken: context.accessToken || "",
});
}, [domain, accessToken]);
}, [context]);
const setPartialSettingState = (partialSettingState: Partial<SettingState>) => {
setSettingState((prevState) => ({
@ -57,8 +57,8 @@ const IndexOptions = () => {
};
const handleSaveSetting = () => {
setDomain(settingState.domain);
setAccessToken(settingState.accessToken);
context.setInstanceUrl(settingState.domain);
context.setAccessToken(settingState.accessToken);
toast.success("Setting saved");
};
@ -66,6 +66,10 @@ const IndexOptions = () => {
setColorTheme(colorTheme as any);
};
const handleDefaultVisibilitySelect = (value: Visibility) => {
context.setDefaultVisibility(value);
};
return (
<div className="w-full px-4">
<div className="w-full flex flex-row justify-center items-center">
@ -92,10 +96,10 @@ const IndexOptions = () => {
<div className="w-full flex flex-col justify-start items-start mb-4">
<div className="mb-2 text-base w-full flex flex-row justify-between items-center">
<span className="dark:text-gray-400">Instance URL</span>
{domain !== "" && (
{context.instanceUrl !== "" && (
<a
className="text-sm flex flex-row justify-start items-center underline text-blue-600 hover:opacity-80"
href={domain}
href={context.instanceUrl}
target="_blank"
>
<span className="mr-1">Go to my Slash</span>
@ -133,9 +137,9 @@ const IndexOptions = () => {
<Divider className="!my-6" />
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Preference</p>
<p className="text-base font-semibold leading-6 mb-2 text-gray-900 dark:text-gray-500">Preference</p>
<div className="w-full flex flex-row justify-between items-center">
<div className="w-full flex flex-row justify-between items-center mb-2">
<div className="flex flex-row justify-start items-center gap-x-1">
<span className="dark:text-gray-400">Color Theme</span>
</div>
@ -149,6 +153,17 @@ const IndexOptions = () => {
})}
</Select>
</div>
<div className="w-full flex flex-row justify-between items-center">
<div className="flex flex-row justify-start items-center gap-x-1">
<span className="dark:text-gray-400">Default Visibility</span>
</div>
<Select defaultValue={context.defaultVisibility} onChange={(_, value) => handleDefaultVisibilitySelect(value as Visibility)}>
<Option value={Visibility.PRIVATE}>Private</Option>
<Option value={Visibility.WORKSPACE}>Workspace</Option>
<Option value={Visibility.PUBLIC}>Public</Option>
</Select>
</div>
</div>
{isInitialized && (
@ -170,10 +185,12 @@ const IndexOptions = () => {
const Options = () => {
return (
<CssVarsProvider>
<IndexOptions />
<Toaster position="top-center" />
</CssVarsProvider>
<StorageContextProvider>
<CssVarsProvider>
<IndexOptions />
<Toaster position="top-center" />
</CssVarsProvider>
</StorageContextProvider>
);
};

View File

@ -1,5 +1,4 @@
import { Button, CssVarsProvider, Divider, IconButton } from "@mui/joy";
import { useStorage } from "@plasmohq/storage/hook";
import { useEffect } from "react";
import { Toaster } from "react-hot-toast";
import CreateShortcutButton from "@/components/CreateShortcutButton";
@ -7,24 +6,24 @@ import Icon from "@/components/Icon";
import Logo from "@/components/Logo";
import PullShortcutsButton from "@/components/PullShortcutsButton";
import ShortcutsContainer from "@/components/ShortcutsContainer";
import { StorageContextProvider, useStorageContext } from "./context";
import useColorTheme from "./hooks/useColorTheme";
import useShortcutStore from "./store/shortcut";
import "./style.css";
const IndexPopup = () => {
useColorTheme();
const [instanceUrl] = useStorage<string>("domain", "");
const [accessToken] = useStorage<string>("access_token", "");
const context = useStorageContext();
const shortcutStore = useShortcutStore();
const shortcuts = shortcutStore.getShortcutList();
const isInitialized = instanceUrl && accessToken;
const isInitialized = context.instanceUrl && context.accessToken;
useEffect(() => {
if (!isInitialized) {
return;
}
shortcutStore.fetchShortcutList(instanceUrl, accessToken);
shortcutStore.fetchShortcutList(context.instanceUrl, context.accessToken);
}, [isInitialized]);
const handleSettingButtonClick = () => {
@ -86,7 +85,7 @@ const IndexPopup = () => {
<div className="flex flex-row justify-end items-center">
<a
className="text-sm flex flex-row justify-start items-center underline text-blue-600 hover:opacity-80"
href={instanceUrl}
href={context.instanceUrl}
target="_blank"
>
<span className="mr-1">Go to my Slash</span>
@ -117,10 +116,12 @@ const IndexPopup = () => {
const Popup = () => {
return (
<CssVarsProvider>
<IndexPopup />
<Toaster position="top-center" />
</CssVarsProvider>
<StorageContextProvider>
<CssVarsProvider>
<IndexPopup />
<Toaster position="top-center" />
</CssVarsProvider>
</StorageContextProvider>
);
};