Skip to content

Commit

Permalink
Fix sticky sidebar + new design for app information + gorgegous new d…
Browse files Browse the repository at this point in the history
…ropdown + bunch of small bug fixes + fix encryption not supporting utf8

Co-authored-by: Jip Frijlink <[email protected]>
  • Loading branch information
mrjvs and JipFr committed Nov 25, 2023
1 parent 8cdedbf commit 7bc3bb1
Show file tree
Hide file tree
Showing 16 changed files with 158 additions and 119 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"react-helmet-async": "^1.3.0",
"react-i18next": "^12.1.1",
"react-router-dom": "^5.2.0",
"react-stickynode": "^4.1.0",
"react-sticky-el": "^2.1.0",
"react-use": "^17.4.0",
"slugify": "^1.6.6",
"subsrt-ts": "^2.1.1",
Expand Down
42 changes: 8 additions & 34 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions src/backend/accounts/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function base64ToBuffer(data: string) {
return forge.util.binary.base64.decode(data);
}

export function base64ToStringBugger(data: string) {
export function base64ToStringBuffer(data: string) {
return forge.util.createBuffer(base64ToBuffer(data));
}

Expand All @@ -97,7 +97,7 @@ export async function encryptData(data: string, secret: Uint8Array) {
iv,
tagLength: 128,
});
cipher.update(forge.util.createBuffer(data));
cipher.update(forge.util.createBuffer(data, "utf8"));
cipher.finish();

const encryptedData = cipher.output;
Expand All @@ -118,11 +118,11 @@ export function decryptData(data: string, secret: Uint8Array) {
forge.util.createBuffer(secret)
);
decipher.start({
iv: base64ToStringBugger(iv),
tag: base64ToStringBugger(tag),
iv: base64ToStringBuffer(iv),
tag: base64ToStringBuffer(tag),
tagLength: 128,
});
decipher.update(base64ToStringBugger(encryptedData));
decipher.update(base64ToStringBuffer(encryptedData));
const pass = decipher.finish();

if (!pass) throw new Error("Error decrypting data");
Expand Down
40 changes: 33 additions & 7 deletions src/components/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import classNames from "classnames";
import { useMemo } from "react";

import { base64ToBuffer, decryptData } from "@/backend/accounts/crypto";
import { Icon, Icons } from "@/components/Icon";
import { UserIcon } from "@/components/UserIcon";
import { AccountProfile } from "@/pages/parts/auth/AccountCreatePart";
Expand Down Expand Up @@ -42,16 +44,40 @@ export function UserAvatar(props: {
sizeClass?: string;
iconClass?: string;
bottom?: React.ReactNode;
withName?: boolean;
}) {
const auth = useAuthStore();
if (!auth.account) return null;

const bufferSeed = useMemo(
() =>
auth.account && auth.account.seed
? base64ToBuffer(auth.account.seed)
: null,
[auth]
);

if (!auth.account || auth.account === null) return null;

const deviceName = bufferSeed
? decryptData(auth.account.deviceName, bufferSeed)
: "...";

return (
<Avatar
profile={auth.account.profile}
sizeClass={props.sizeClass ?? "w-[2rem] h-[2rem]"}
iconClass={props.iconClass}
bottom={props.bottom}
/>
<>
<Avatar
profile={auth.account.profile}
sizeClass={props.sizeClass ?? "w-[2rem] h-[2rem]"}
iconClass={props.iconClass}
bottom={props.bottom}
/>
{props.withName && bufferSeed ? (
<span>
{deviceName.length >= 20
? `${deviceName.slice(0, 20 - 1)}…`
: deviceName}
</span>
) : null}
</>
);
}

Expand Down
9 changes: 8 additions & 1 deletion src/components/LinksDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,19 @@ export function LinksDropdown(props: { children: React.ReactNode }) {
return (
<div className="relative is-dropdown">
<div
className="cursor-pointer tabbable rounded-full"
className="cursor-pointer tabbable rounded-full flex gap-2 text-white items-center py-2 px-3 bg-pill-background bg-opacity-50"
tabIndex={0}
onClick={toggleOpen}
onKeyUp={(evt) => evt.key === "Enter" && toggleOpen()}
>
{props.children}
<Icon
className={classNames(
"text-xl transition-transform duration-100",
open ? "rotate-180" : ""
)}
icon={Icons.CHEVRON_DOWN}
/>
</div>
<Transition animation="slide-down" show={open}>
<div className="rounded-lg absolute w-64 bg-dropdown-altBackground top-full mt-3 right-0">
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export function Navigation(props: NavigationProps) {
</div>
<div className="relative">
<LinksDropdown>
{loggedIn ? <UserAvatar /> : <NoUserAvatar />}
{loggedIn ? <UserAvatar withName /> : <NoUserAvatar />}
</LinksDropdown>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/utils/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function Heading1(props: TextProps) {
return (
<h1
className={[
"text-5xl font-bold text-white mb-9",
"text-3xl lg:text-5xl font-bold text-white mb-9",
props.border ? borderClass : null,
props.className ?? "",
].join(" ")}
Expand All @@ -24,7 +24,7 @@ export function Heading2(props: TextProps) {
return (
<h2
className={[
"text-3xl font-bold text-white mt-20 mb-9",
"text-xl lg:text-3xl font-bold text-white mt-20 mb-9",
props.border ? borderClass : null,
props.className ?? "",
].join(" ")}
Expand All @@ -38,7 +38,7 @@ export function Heading3(props: TextProps) {
return (
<h2
className={[
"text-xl font-bold text-white mb-3",
"text-lg lg:text-xl font-bold text-white mb-3",
props.border ? borderClass : null,
props.className ?? "",
].join(" ")}
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/auth/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ export function useAuth() {
const anyError: any = err;
if (
anyError?.response?.status === 401 ||
anyError?.response?.status === 403
anyError?.response?.status === 403 ||
anyError?.response?.status === 400
) {
await logout();
return;
Expand Down
4 changes: 3 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ function AuthWrapper() {
if (status.error)
return (
<ErrorScreen showResetButton={backendUrl !== userBackendUrl}>
Failed to fetch user data. Try resetting the backend URL.
{backendUrl !== userBackendUrl
? "Failed to fetch user data. Try resetting the backend URL"
: "Failed to fetch user data."}
</ErrorScreen>
);
return <App />;
Expand Down
18 changes: 13 additions & 5 deletions src/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function SettingsLayout(props: { children: React.ReactNode }) {
<div
className={classNames(
"grid gap-12",
isMobile ? "grid-cols-1" : "lg:grid-cols-[310px,1fr]"
isMobile ? "grid-cols-1" : "lg:grid-cols-[280px,1fr]"
)}
>
<SidebarPart />
Expand Down Expand Up @@ -240,16 +240,24 @@ export function SettingsPage() {
</div>
</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 ${
className={`bg-settings-saveBar-background border-t border-settings-card-border/50 py-4 transition-opacity w-full fixed bottom-0 flex justify-between flex-col md:flex-row px-8 items-start md:items-center gap-3 ${
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}>
<div className="space-x-3 w-full md:w-auto flex">
<Button
className="w-full md:w-auto"
theme="secondary"
onClick={state.reset}
>
Reset
</Button>
<Button theme="purple" onClick={saveChanges}>
<Button
className="w-full md:w-auto"
theme="purple"
onClick={saveChanges}
>
Save
</Button>
</div>
Expand Down
19 changes: 10 additions & 9 deletions src/pages/parts/home/HeroPart.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useState } from "react";
import Sticky from "react-stickynode";
import Sticky from "react-sticky-el";

import { ThinContainer } from "@/components/layout/ThinContainer";
import { SearchBarInput } from "@/components/SearchBar";
Expand All @@ -19,10 +19,9 @@ export function HeroPart({ setIsSticky, searchParams }: HeroPartProps) {
const [, setShowBg] = useState(false);
const bannerSize = useBannerSize();
const stickStateChanged = useCallback(
({ status }: Sticky.Status) => {
const val = status === Sticky.STATUS_FIXED;
setShowBg(val);
setIsSticky(val);
(isFixed) => {
setShowBg(isFixed);
setIsSticky(isFixed);
},
[setShowBg, setIsSticky]
);
Expand All @@ -40,11 +39,13 @@ export function HeroPart({ setIsSticky, searchParams }: HeroPartProps) {
<div className="relative z-10 mb-16">
<HeroTitle className="mx-auto max-w-xs">{title}</HeroTitle>
</div>
<div className="relative z-30">
<div className="relative h-20 z-30">
<Sticky
enabled
top={16 + bannerSize}
onStateChange={stickStateChanged}
topOffset={-16 + bannerSize}
stickyStyle={{
paddingTop: `${16 + bannerSize}px`,
}}
onFixedToggle={stickStateChanged}
>
<SearchBarInput
onChange={setSearch}
Expand Down
6 changes: 3 additions & 3 deletions src/pages/parts/settings/CaptionsPart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Menu } from "@/components/player/internals/ContextMenu";
import { CaptionCue } from "@/components/player/Player";
import { Transition } from "@/components/Transition";
import { Heading1 } from "@/components/utils/Text";
import { SubtitleStyling, useSubtitleStore } from "@/stores/subtitles";
import { SubtitleStyling } from "@/stores/subtitles";

export function CaptionPreview(props: {
fullscreen?: boolean;
Expand All @@ -24,7 +24,7 @@ export function CaptionPreview(props: {
className={classNames({
"pointer-events-none overflow-hidden w-full rounded": true,
"aspect-video relative": !props.fullscreen,
"fixed inset-0 z-50": props.fullscreen,
"fixed inset-0 z-[60]": props.fullscreen,
})}
>
<Transition animation="fade" show={props.show}>
Expand Down Expand Up @@ -71,7 +71,7 @@ export function CaptionsPart(props: {
return (
<div>
<Heading1 border>Captions</Heading1>
<div className="grid grid-cols-[1fr,356px] gap-8">
<div className="grid md:grid-cols-[1fr,356px] gap-8">
<div className="space-y-6">
<CaptionSetting
label="Background opacity"
Expand Down
4 changes: 2 additions & 2 deletions src/pages/parts/settings/ConnectionsPart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function ProxyEdit({ proxyUrls, setProxyUrls }: ProxyEditProps) {

return (
<SettingsCard>
<div className="flex justify-between items-center">
<div className="flex justify-between items-center gap-4">
<div className="my-3">
<p className="text-white font-bold mb-3">Use custom proxy workers</p>
<p className="max-w-[20rem] font-medium">
Expand Down Expand Up @@ -103,7 +103,7 @@ function ProxyEdit({ proxyUrls, setProxyUrls }: ProxyEditProps) {
function BackendEdit({ backendUrl, setBackendUrl }: BackendEditProps) {
return (
<SettingsCard>
<div className="flex justify-between items-center">
<div className="flex justify-between items-center gap-4">
<div className="my-3">
<p className="text-white font-bold mb-3">Custom server</p>
<p className="max-w-[20rem] font-medium">
Expand Down
Loading

0 comments on commit 7bc3bb1

Please sign in to comment.