mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-29 16:07:40 +01:00
Add more settings saving logic + add connections section to settings + fix broken modals
This commit is contained in:
parent
5a5f3e8b8c
commit
e62238459c
12 changed files with 264 additions and 26 deletions
|
@ -44,7 +44,7 @@ module.exports = {
|
||||||
"react/destructuring-assignment": "off",
|
"react/destructuring-assignment": "off",
|
||||||
"no-underscore-dangle": "off",
|
"no-underscore-dangle": "off",
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
"no-console": ["error", { allow: ["warn", "error"] }],
|
"no-console": ["warn", { allow: ["warn", "error", "debug", "info"] }],
|
||||||
"@typescript-eslint/no-this-alias": "off",
|
"@typescript-eslint/no-this-alias": "off",
|
||||||
"import/prefer-default-export": "off",
|
"import/prefer-default-export": "off",
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
"@typescript-eslint/no-empty-function": "off",
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"hls.js": "^1.0.7",
|
"hls.js": "^1.0.7",
|
||||||
"i18next": "^22.4.5",
|
"i18next": "^22.4.5",
|
||||||
"immer": "^10.0.2",
|
"immer": "^10.0.2",
|
||||||
|
"lodash.isequal": "^4.5.0",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"ofetch": "^1.0.0",
|
"ofetch": "^1.0.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
|
@ -67,6 +68,7 @@
|
||||||
"@types/crypto-js": "^4.1.1",
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/dompurify": "^2.4.0",
|
"@types/dompurify": "^2.4.0",
|
||||||
"@types/fscreen": "^1.0.1",
|
"@types/fscreen": "^1.0.1",
|
||||||
|
"@types/lodash.isequal": "^4.5.8",
|
||||||
"@types/lodash.throttle": "^4.1.7",
|
"@types/lodash.throttle": "^4.1.7",
|
||||||
"@types/node": "^17.0.15",
|
"@types/node": "^17.0.15",
|
||||||
"@types/pako": "^2.0.0",
|
"@types/pako": "^2.0.0",
|
||||||
|
|
|
@ -65,6 +65,9 @@ dependencies:
|
||||||
immer:
|
immer:
|
||||||
specifier: ^10.0.2
|
specifier: ^10.0.2
|
||||||
version: 10.0.2
|
version: 10.0.2
|
||||||
|
lodash.isequal:
|
||||||
|
specifier: ^4.5.0
|
||||||
|
version: 4.5.0
|
||||||
node-forge:
|
node-forge:
|
||||||
specifier: ^1.3.1
|
specifier: ^1.3.1
|
||||||
version: 1.3.1
|
version: 1.3.1
|
||||||
|
@ -130,6 +133,9 @@ devDependencies:
|
||||||
'@types/fscreen':
|
'@types/fscreen':
|
||||||
specifier: ^1.0.1
|
specifier: ^1.0.1
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
|
'@types/lodash.isequal':
|
||||||
|
specifier: ^4.5.8
|
||||||
|
version: 4.5.8
|
||||||
'@types/lodash.throttle':
|
'@types/lodash.throttle':
|
||||||
specifier: ^4.1.7
|
specifier: ^4.1.7
|
||||||
version: 4.1.7
|
version: 4.1.7
|
||||||
|
@ -2132,6 +2138,12 @@ packages:
|
||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/lodash.isequal@4.5.8:
|
||||||
|
resolution: {integrity: sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/lodash': 4.14.197
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/lodash.throttle@4.1.7:
|
/@types/lodash.throttle@4.1.7:
|
||||||
resolution: {integrity: sha512-znwGDpjCHQ4FpLLx19w4OXDqq8+OvREa05H89obtSyXyOFKL3dDjCslsmfBz0T2FU8dmf5Wx1QvogbINiGIu9g==}
|
resolution: {integrity: sha512-znwGDpjCHQ4FpLLx19w4OXDqq8+OvREa05H89obtSyXyOFKL3dDjCslsmfBz0T2FU8dmf5Wx1QvogbINiGIu9g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4561,6 +4573,10 @@ packages:
|
||||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/lodash.isequal@4.5.0:
|
||||||
|
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/lodash.merge@4.6.2:
|
/lodash.merge@4.6.2:
|
||||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
|
@ -55,7 +55,7 @@ export function OverlayPortal(props: {
|
||||||
onDeactivate: close,
|
onDeactivate: close,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="popout-wrapper absolute overflow-hidden pointer-events-auto inset-0 z-[999] select-none">
|
<div className="popout-wrapper fixed overflow-hidden pointer-events-auto inset-0 z-[999] select-none">
|
||||||
<Transition animation="fade" isChild>
|
<Transition animation="fade" isChild>
|
||||||
<div
|
<div
|
||||||
onClick={close}
|
onClick={close}
|
||||||
|
|
|
@ -72,10 +72,10 @@ export function useChromecast() {
|
||||||
|
|
||||||
// setup event listener
|
// setup event listener
|
||||||
function listenToEvents(e: cast.framework.RemotePlayerChangedEvent) {
|
function listenToEvents(e: cast.framework.RemotePlayerChangedEvent) {
|
||||||
console.log("chromecast event", e);
|
console.debug("chromecast event", e);
|
||||||
}
|
}
|
||||||
function connectionChanged(e: cast.framework.RemotePlayerChangedEvent) {
|
function connectionChanged(e: cast.framework.RemotePlayerChangedEvent) {
|
||||||
console.log("chromecast event connection changed", e);
|
console.info("chromecast event connection changed", e);
|
||||||
}
|
}
|
||||||
remotePlayerController.current.addEventListener(
|
remotePlayerController.current.addEventListener(
|
||||||
cast.framework.RemotePlayerEventType.PLAYER_STATE_CHANGED,
|
cast.framework.RemotePlayerEventType.PLAYER_STATE_CHANGED,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import isEqual from "lodash.isequal";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
import { SubtitleStyling } from "@/stores/subtitles";
|
import { SubtitleStyling } from "@/stores/subtitles";
|
||||||
|
@ -9,8 +10,10 @@ export function useDerived<T>(
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setOverwrite(undefined);
|
setOverwrite(undefined);
|
||||||
}, [initial]);
|
}, [initial]);
|
||||||
|
const changed = useMemo(
|
||||||
const changed = overwrite !== initial && overwrite !== undefined;
|
() => !isEqual(overwrite, initial) && overwrite !== undefined,
|
||||||
|
[overwrite, initial]
|
||||||
|
);
|
||||||
const data = overwrite === undefined ? initial : overwrite;
|
const data = overwrite === undefined ? initial : overwrite;
|
||||||
|
|
||||||
const reset = useCallback(() => setOverwrite(undefined), [setOverwrite]);
|
const reset = useCallback(() => setOverwrite(undefined), [setOverwrite]);
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useEffect } from "react";
|
import { useCallback, useEffect, useMemo } from "react";
|
||||||
import { useAsyncFn } from "react-use";
|
import { useAsyncFn } from "react-use";
|
||||||
|
|
||||||
|
import { base64ToBuffer, decryptData } from "@/backend/accounts/crypto";
|
||||||
import { getSessions } from "@/backend/accounts/sessions";
|
import { getSessions } from "@/backend/accounts/sessions";
|
||||||
|
import { updateSettings } from "@/backend/accounts/settings";
|
||||||
import { Button } from "@/components/Button";
|
import { Button } from "@/components/Button";
|
||||||
import { WideContainer } from "@/components/layout/WideContainer";
|
import { WideContainer } from "@/components/layout/WideContainer";
|
||||||
import { Heading1 } from "@/components/utils/Text";
|
import { Heading1 } from "@/components/utils/Text";
|
||||||
|
@ -12,6 +14,7 @@ import { useSettingsState } from "@/hooks/useSettingsState";
|
||||||
import { AccountActionsPart } from "@/pages/parts/settings/AccountActionsPart";
|
import { AccountActionsPart } from "@/pages/parts/settings/AccountActionsPart";
|
||||||
import { AccountEditPart } from "@/pages/parts/settings/AccountEditPart";
|
import { AccountEditPart } from "@/pages/parts/settings/AccountEditPart";
|
||||||
import { CaptionsPart } from "@/pages/parts/settings/CaptionsPart";
|
import { CaptionsPart } from "@/pages/parts/settings/CaptionsPart";
|
||||||
|
import { ConnectionsPart } from "@/pages/parts/settings/ConnectionsPart";
|
||||||
import { DeviceListPart } from "@/pages/parts/settings/DeviceListPart";
|
import { DeviceListPart } from "@/pages/parts/settings/DeviceListPart";
|
||||||
import { RegisterCalloutPart } from "@/pages/parts/settings/RegisterCalloutPart";
|
import { RegisterCalloutPart } from "@/pages/parts/settings/RegisterCalloutPart";
|
||||||
import { SidebarPart } from "@/pages/parts/settings/SidebarPart";
|
import { SidebarPart } from "@/pages/parts/settings/SidebarPart";
|
||||||
|
@ -71,10 +74,18 @@ export function SettingsPage() {
|
||||||
const setTheme = useThemeStore((s) => s.setTheme);
|
const setTheme = useThemeStore((s) => s.setTheme);
|
||||||
|
|
||||||
const appLanguage = useLanguageStore((s) => s.language);
|
const appLanguage = useLanguageStore((s) => s.language);
|
||||||
|
const setAppLanguage = useLanguageStore((s) => s.setLanguage);
|
||||||
|
|
||||||
const subStyling = useSubtitleStore((s) => s.styling);
|
const subStyling = useSubtitleStore((s) => s.styling);
|
||||||
|
const setSubStyling = useSubtitleStore((s) => s.updateStyling);
|
||||||
|
|
||||||
const deviceName = useAuthStore((s) => s.account?.deviceName);
|
const account = useAuthStore((s) => s.account);
|
||||||
|
const decryptedName = useMemo(() => {
|
||||||
|
if (!account) return "";
|
||||||
|
return decryptData(account.deviceName, base64ToBuffer(account.seed));
|
||||||
|
}, [account]);
|
||||||
|
|
||||||
|
const backendUrl = useBackendUrl();
|
||||||
|
|
||||||
const user = useAuthStore();
|
const user = useAuthStore();
|
||||||
|
|
||||||
|
@ -82,9 +93,23 @@ export function SettingsPage() {
|
||||||
activeTheme,
|
activeTheme,
|
||||||
appLanguage,
|
appLanguage,
|
||||||
subStyling,
|
subStyling,
|
||||||
deviceName
|
decryptedName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const saveChanges = useCallback(async () => {
|
||||||
|
console.log(state);
|
||||||
|
|
||||||
|
if (account) {
|
||||||
|
await updateSettings(backendUrl, account, {
|
||||||
|
applicationLanguage: state.appLanguage.state,
|
||||||
|
applicationTheme: state.theme.state ?? undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setAppLanguage(state.appLanguage.state);
|
||||||
|
setTheme(state.theme.state);
|
||||||
|
setSubStyling(state.subtitleStyling.state);
|
||||||
|
}, [state, account, backendUrl, setAppLanguage, setTheme, setSubStyling]);
|
||||||
return (
|
return (
|
||||||
<SubPageLayout>
|
<SubPageLayout>
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
|
@ -110,20 +135,28 @@ export function SettingsPage() {
|
||||||
<div id="settings-captions" className="mt-48">
|
<div id="settings-captions" className="mt-48">
|
||||||
<CaptionsPart
|
<CaptionsPart
|
||||||
styling={state.subtitleStyling.state}
|
styling={state.subtitleStyling.state}
|
||||||
setStyling={(s) => s}
|
setStyling={state.subtitleStyling.set}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</SettingsLayout>
|
<div id="settings-connection" className="mt-48">
|
||||||
|
<ConnectionsPart />
|
||||||
{state.changed ? (
|
|
||||||
<div className="bg-settings-saveBar-background border-t border-settings-card-border/50 py-4 w-full fixed bottom-0 flex justify-between px-8 items-center">
|
|
||||||
<p className="text-type-danger">You have unsaved changes</p>
|
|
||||||
<div className="space-x-6">
|
|
||||||
<Button theme="secondary">Reset</Button>
|
|
||||||
<Button theme="purple">Save</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
</SettingsLayout>
|
||||||
|
<div
|
||||||
|
className={`bg-settings-saveBar-background border-t border-settings-card-border/50 py-4 transition-opacity w-full fixed bottom-0 flex justify-between px-8 items-center ${
|
||||||
|
state.changed ? "opacity-100" : "opacity-0"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<p className="text-type-danger">You have unsaved changes</p>
|
||||||
|
<div className="space-x-6">
|
||||||
|
<Button theme="secondary" onClick={state.reset}>
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
<Button theme="purple" onClick={saveChanges}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</SubPageLayout>
|
</SubPageLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,10 @@ export function AccountEditPart() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsCard paddingClass="px-8 py-10" className="!mt-8">
|
<SettingsCard paddingClass="px-8 py-10" className="!mt-8">
|
||||||
<ProfileEditModal id={profileEditModal.id} />
|
<ProfileEditModal
|
||||||
|
id={profileEditModal.id}
|
||||||
|
close={profileEditModal.hide}
|
||||||
|
/>
|
||||||
<div className="grid lg:grid-cols-[auto,1fr] gap-8">
|
<div className="grid lg:grid-cols-[auto,1fr] gap-8">
|
||||||
<div>
|
<div>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
|
|
149
src/pages/parts/settings/ConnectionsPart.tsx
Normal file
149
src/pages/parts/settings/ConnectionsPart.tsx
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import { Button } from "@/components/Button";
|
||||||
|
import { Toggle } from "@/components/buttons/Toggle";
|
||||||
|
import { Icon, Icons } from "@/components/Icon";
|
||||||
|
import { SettingsCard } from "@/components/layout/SettingsCard";
|
||||||
|
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
||||||
|
import { Divider } from "@/components/utils/Divider";
|
||||||
|
import { Heading1 } from "@/components/utils/Text";
|
||||||
|
|
||||||
|
let idNum = 0;
|
||||||
|
|
||||||
|
interface ProxyItem {
|
||||||
|
url: string;
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ProxyEdit() {
|
||||||
|
const [customWorkers, setCustomWorkers] = useState<ProxyItem[] | null>(null);
|
||||||
|
|
||||||
|
const add = useCallback(() => {
|
||||||
|
idNum += 1;
|
||||||
|
setCustomWorkers((s) => [
|
||||||
|
...(s ?? []),
|
||||||
|
{
|
||||||
|
id: idNum,
|
||||||
|
url: "",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}, [setCustomWorkers]);
|
||||||
|
|
||||||
|
const changeItem = useCallback(
|
||||||
|
(id: number, val: string) => {
|
||||||
|
setCustomWorkers((s) => [
|
||||||
|
...(s ?? []).map((v) => {
|
||||||
|
if (v.id !== id) return v;
|
||||||
|
v.url = val;
|
||||||
|
return v;
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
[setCustomWorkers]
|
||||||
|
);
|
||||||
|
|
||||||
|
const removeItem = useCallback(
|
||||||
|
(id: number) => {
|
||||||
|
setCustomWorkers((s) => [...(s ?? []).filter((v) => v.id !== id)]);
|
||||||
|
},
|
||||||
|
[setCustomWorkers]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsCard>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div className="my-3">
|
||||||
|
<p className="text-white font-bold mb-3">Use custom proxy workers</p>
|
||||||
|
<p className="max-w-[20rem] font-medium">
|
||||||
|
To make the application function, all traffic is routed through
|
||||||
|
proxies. Enable this if you want to bring your own workers.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Toggle
|
||||||
|
onClick={() => setCustomWorkers((s) => (s === null ? [] : null))}
|
||||||
|
enabled={customWorkers !== null}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{customWorkers !== null ? (
|
||||||
|
<>
|
||||||
|
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||||
|
<p className="text-white font-bold mb-3">Worker URLs</p>
|
||||||
|
|
||||||
|
<div className="my-6 space-y-2 max-w-md">
|
||||||
|
{(customWorkers?.length ?? 0) === 0 ? (
|
||||||
|
<p>No workers yet, add one below</p>
|
||||||
|
) : null}
|
||||||
|
{(customWorkers ?? []).map((v) => (
|
||||||
|
<div className="grid grid-cols-[1fr,auto] items-center gap-2">
|
||||||
|
<AuthInputBox
|
||||||
|
value={v.url}
|
||||||
|
onChange={(val) => changeItem(v.id, val)}
|
||||||
|
placeholder="https://"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => removeItem(v.id)}
|
||||||
|
className="h-full scale-90 hover:scale-100 rounded-full aspect-square bg-authentication-inputBg hover:bg-authentication-inputBgHover flex justify-center items-center transition-transform duration-200 hover:text-white cursor-pointer"
|
||||||
|
>
|
||||||
|
<Icon className="text-xl" icon={Icons.X} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button theme="purple" onClick={add}>
|
||||||
|
Add new worker
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</SettingsCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function BackendEdit() {
|
||||||
|
const [customBackendUrl, setCustomBackendUrl] = useState<string | null>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsCard>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div className="my-3">
|
||||||
|
<p className="text-white font-bold mb-3">Custom server</p>
|
||||||
|
<p className="max-w-[20rem] font-medium">
|
||||||
|
To make the application function, all traffic is routed through
|
||||||
|
proxies. Enable this if you want to bring your own workers.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Toggle
|
||||||
|
onClick={() => setCustomBackendUrl((s) => (s === null ? "" : null))}
|
||||||
|
enabled={customBackendUrl !== null}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{customBackendUrl !== null ? (
|
||||||
|
<>
|
||||||
|
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||||
|
<p className="text-white font-bold mb-3">Custom server URL</p>
|
||||||
|
<AuthInputBox
|
||||||
|
onChange={setCustomBackendUrl}
|
||||||
|
value={customBackendUrl ?? ""}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</SettingsCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ConnectionsPart() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Heading1 border>Connections</Heading1>
|
||||||
|
<div className="space-y-6">
|
||||||
|
<ProxyEdit />
|
||||||
|
<BackendEdit />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,14 +1,44 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
import { Button } from "@/components/Button";
|
import { Button } from "@/components/Button";
|
||||||
|
import { ColorPicker } from "@/components/form/ColorPicker";
|
||||||
|
import { IconPicker } from "@/components/form/IconPicker";
|
||||||
import { Modal, ModalCard } from "@/components/overlays/Modal";
|
import { Modal, ModalCard } from "@/components/overlays/Modal";
|
||||||
|
import { UserIcons } from "@/components/UserIcon";
|
||||||
import { Heading2 } from "@/components/utils/Text";
|
import { Heading2 } from "@/components/utils/Text";
|
||||||
|
|
||||||
export function ProfileEditModal(props: { id: string }) {
|
export interface ProfileEditModalProps {
|
||||||
|
id: string;
|
||||||
|
close?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ProfileEditModal(props: ProfileEditModalProps) {
|
||||||
|
const [colorA, setColorA] = useState("#2E65CF");
|
||||||
|
const [colorB, setColorB] = useState("#2E65CF");
|
||||||
|
const [userIcon, setUserIcon] = useState<UserIcons>(UserIcons.USER);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal id={props.id}>
|
<Modal id={props.id}>
|
||||||
<ModalCard>
|
<ModalCard>
|
||||||
<Heading2 className="!mt-0">Edit profile?</Heading2>
|
<Heading2 className="!mt-0">Edit profile picture</Heading2>
|
||||||
<p>I am existing</p>
|
<div className="space-y-6">
|
||||||
<Button theme="danger">Update</Button>
|
<ColorPicker label="First color" value={colorA} onInput={setColorA} />
|
||||||
|
<ColorPicker
|
||||||
|
label="Second color"
|
||||||
|
value={colorB}
|
||||||
|
onInput={setColorB}
|
||||||
|
/>
|
||||||
|
<IconPicker
|
||||||
|
label="User icon"
|
||||||
|
value={userIcon}
|
||||||
|
onInput={setUserIcon}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-center mt-8">
|
||||||
|
<Button theme="purple" className="!px-20" onClick={props.close}>
|
||||||
|
Finish editing
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</ModalCard>
|
</ModalCard>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,9 +18,10 @@ export function SidebarPart() {
|
||||||
|
|
||||||
const settingLinks = [
|
const settingLinks = [
|
||||||
{ text: "Account", id: "settings-account", icon: Icons.USER },
|
{ text: "Account", id: "settings-account", icon: Icons.USER },
|
||||||
{ text: "Locale", id: "settings-locale", icon: Icons.LINK },
|
{ text: "Locale", id: "settings-locale", icon: Icons.BOOKMARK },
|
||||||
{ text: "Appearance", id: "settings-appearance", icon: Icons.GITHUB },
|
{ text: "Appearance", id: "settings-appearance", icon: Icons.GITHUB },
|
||||||
{ text: "Captions", id: "settings-captions", icon: Icons.CAPTIONS },
|
{ text: "Captions", id: "settings-captions", icon: Icons.CAPTIONS },
|
||||||
|
{ text: "Connections", id: "settings-connection", icon: Icons.LINK },
|
||||||
];
|
];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -109,6 +109,7 @@ export const defaultTheme = {
|
||||||
authentication: {
|
authentication: {
|
||||||
border: "#393954",
|
border: "#393954",
|
||||||
inputBg: "#171728",
|
inputBg: "#171728",
|
||||||
|
inputBgHover: "#171726",
|
||||||
wordBackground: "#171728",
|
wordBackground: "#171728",
|
||||||
copyText: "#58587A",
|
copyText: "#58587A",
|
||||||
copyTextHover: "#8888AA",
|
copyTextHover: "#8888AA",
|
||||||
|
|
Loading…
Reference in a new issue