fix max page width option

This commit is contained in:
hzrd149 2025-01-21 15:56:52 -06:00
parent 07d2df7d5c
commit 5b2113b3b9
12 changed files with 63 additions and 43 deletions

View File

@ -13,6 +13,8 @@ import { getMatchLink } from "../../helpers/regexp";
import TimelineHealth from "./timeline-health";
import useRouteSearchValue from "../../hooks/use-route-search-value";
import VerticalPageLayout from "../vertical-page-layout";
import useAppSettings from "../../hooks/use-user-app-settings";
import useMaxPageWidth from "../../hooks/use-max-page-width";
export function useTimelinePageEventFilter() {
const [params, setParams] = useSearchParams();
@ -40,6 +42,7 @@ export default function TimelinePage({
>) {
const callback = useTimelineCurserIntersectionCallback(loader);
const { maxPageWidth } = useAppSettings();
const viewParam = useRouteSearchValue("view", "timeline");
const mode = (viewParam.value as TimelineViewType) ?? "timeline";
@ -57,9 +60,11 @@ export default function TimelinePage({
return null;
}
};
const maxWidth = useMaxPageWidth("6xl");
return (
<IntersectionObserverProvider callback={callback}>
<VerticalPageLayout maxW="6xl" mx="auto" {...props}>
<VerticalPageLayout maxW={maxWidth} mx="auto" {...props}>
{header}
{renderTimeline()}
<TimelineActionAndStatus timeline={loader} />

View File

@ -29,7 +29,7 @@ export type AppSettingsV0 = {
export type AppSettingsV1 = Omit<AppSettingsV0, "version"> & {
version: 1;
mutedWords?: string;
maxPageWidth: "none" | "md" | "lg" | "xl";
maxPageWidth: "none" | "sm" | "md" | "lg" | "xl" | "full";
};
export type AppSettingsV2 = Omit<AppSettingsV1, "version"> & { version: 2; theme: string };
export type AppSettingsV3 = Omit<AppSettingsV2, "version"> & { version: 3; quickReactions: string[] };

View File

@ -0,0 +1,21 @@
import useAppSettings from "./use-user-app-settings";
export default function useMaxPageWidth(fallback?: string) {
const { maxPageWidth } = useAppSettings();
switch (maxPageWidth) {
case "sm":
return "2xl";
case "md":
return "4xl";
case "lg":
return "6xl";
case "xl":
return "8xl";
case "full":
return "full";
default:
case "none":
return fallback || "6xl";
}
}

View File

@ -15,11 +15,8 @@ import { queryStore } from "../../services/event-store";
import EventFactoryProvider from "./event-factory-provider";
function ThemeProviders({ children }: { children: React.ReactNode }) {
const { theme: themeName, primaryColor, maxPageWidth } = useAppSettings();
const theme = useMemo(
() => buildTheme(themeName, primaryColor, maxPageWidth !== "none" ? maxPageWidth : undefined),
[themeName, primaryColor, maxPageWidth],
);
const { theme: themeName, primaryColor } = useAppSettings();
const theme = useMemo(() => buildTheme(themeName, primaryColor), [themeName, primaryColor]);
return (
<ChakraProvider theme={theme} colorModeManager={localStorageManager}>

View File

@ -17,13 +17,7 @@ function getTheme(name: string) {
return {};
}
const breakpoints = ["sm", "md", "lg", "xl", "2xl"] as const;
export default function buildTheme(
themeName: string,
primaryColor: string = "#8DB600",
maxBreakpoint?: (typeof breakpoints)[number],
) {
export default function buildTheme(themeName: string, primaryColor: string = "#8DB600") {
const theme = extendTheme(getTheme(themeName), {
config: {
initialColorMode: "system",
@ -46,12 +40,5 @@ export default function buildTheme(
},
} as DeepPartial<Theme>);
// if maxBreakpoint is set, set all breakpoints above it to a large number so they are never reached
if (maxBreakpoint && breakpoints.includes(maxBreakpoint)) {
for (let i = breakpoints.indexOf(maxBreakpoint) + 1; i < breakpoints.length; i++) {
theme.breakpoints[breakpoints[i]] = 50000;
}
}
return theme;
}

View File

@ -15,6 +15,7 @@ import ArticleCard from "./components/article-card";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import { getArticleTitle } from "../../helpers/nostr/long-form";
import { ErrorBoundary } from "../../components/error-boundary";
import useMaxPageWidth from "../../hooks/use-max-page-width";
function ArticlesHomePage() {
const relays = useReadRelays();
@ -41,8 +42,10 @@ function ArticlesHomePage() {
});
const callback = useTimelineCurserIntersectionCallback(loader);
const maxWidth = useMaxPageWidth();
return (
<VerticalPageLayout maxW="6xl" mx="auto">
<VerticalPageLayout maxW={maxWidth} mx="auto">
<Flex gap="2">
<Heading>Articles</Heading>
<PeopleListSelection />

View File

@ -1,8 +1,9 @@
import { AddressPointer, EventPointer } from "nostr-tools/nip19";
import { Button, ButtonGroup, Flex, Heading, SimpleGrid, SkeletonText, Spinner } from "@chakra-ui/react";
import { Button, ButtonGroup, Flex, Heading, SkeletonText, Spinner } from "@chakra-ui/react";
import { useParams } from "react-router-dom";
import { NostrEvent } from "nostr-tools";
import { getAddressPointerFromATag, getEventPointerFromETag, isATag, isETag } from "applesauce-core/helpers";
import VerticalPageLayout from "../../components/vertical-page-layout";
import useCurrentAccount from "../../hooks/use-current-account";
import TimelineItem from "../../components/timeline-page/generic-note-timeline/timeline-item";
import useSingleEvent from "../../hooks/use-single-event";
@ -10,13 +11,12 @@ import userUserBookmarksList from "../../hooks/use-user-bookmarks-list";
import UserName from "../../components/user/user-name";
import ListMenu from "../lists/components/list-menu";
import UserAvatarLink from "../../components/user/user-avatar-link";
import { NostrEvent, isATag, isETag } from "../../types/nostr-event";
import useEventBookmarkActions from "../../hooks/use-event-bookmark-actions";
import useParamsProfilePointer from "../../hooks/use-params-pubkey-pointer";
import useReplaceableEvent from "../../hooks/use-replaceable-event";
import { EmbedEvent } from "../../components/embed-event";
import { aTagToAddressPointer, eTagToEventPointer } from "../../helpers/nostr/event";
import SimpleView from "../../components/layout/presets/simple-view";
import useMaxPageWidth from "../../hooks/use-max-page-width";
function RemoveBookmarkButton({ event }: { event: NostrEvent }) {
const { isLoading, removeBookmark } = useEventBookmarkActions(event);
@ -57,6 +57,7 @@ function BookmarkAddressItem({ pointer }: { pointer: AddressPointer }) {
function BookmarksPage({ pubkey }: { pubkey: string }) {
const { list } = userUserBookmarksList(pubkey, undefined, true);
const maxWidth = useMaxPageWidth();
if (!list) return <Spinner />;
@ -72,17 +73,17 @@ function BookmarksPage({ pubkey }: { pubkey: string }) {
</Flex>
}
actions={<ListMenu ml="auto" size="sm" list={list} aria-label="More options" />}
maxW="4xl"
maxW={maxWidth}
center
>
{Array.from(list.tags)
.reverse()
.map((tag) => {
if (isETag(tag)) {
const pointer = eTagToEventPointer(tag);
const pointer = getEventPointerFromETag(tag);
return <BookmarkEventItem key={pointer.id} pointer={pointer} />;
} else if (isATag(tag)) {
const pointer = aTagToAddressPointer(tag);
const pointer = getAddressPointerFromATag(tag);
return <BookmarkAddressItem key={tag[1]} pointer={pointer} />;
}
return null;

View File

@ -34,6 +34,7 @@ import NoteReactions from "../../../components/note/timeline-note/components/not
import FileMenu from "../components/file-menu";
import EventShareButton from "../../../components/note/timeline-note/components/event-share-button";
import { formatBytes } from "../../../helpers/number";
import useMaxPageWidth from "../../../hooks/use-max-page-width";
function FileDetailsPage({ file }: { file: NostrEvent }) {
const name = getTagValue(file, "name") || getTagValue(file, "x");
@ -44,6 +45,8 @@ function FileDetailsPage({ file }: { file: NostrEvent }) {
const sha256 = getTagValue(file, "x");
const comment = useDisclosure();
const maxWidth = useMaxPageWidth();
return (
<VerticalPageLayout>
<Flex gap="2" alignItems="center">
@ -61,7 +64,7 @@ function FileDetailsPage({ file }: { file: NostrEvent }) {
<Flex
direction="column"
maxW="6xl"
maxW={maxWidth}
mx="auto"
w="full"
maxH="2xl"
@ -74,7 +77,7 @@ function FileDetailsPage({ file }: { file: NostrEvent }) {
</TrustProvider>
</Flex>
<Flex mx="auto" maxW="6xl" w="full" gap="2" direction="column">
<Flex mx="auto" maxW={maxWidth} w="full" gap="2" direction="column">
<Flex gap="2">
{type && <Text>{type}</Text>}
{size && <Text>{formatBytes(parseInt(size))}</Text>}
@ -89,7 +92,7 @@ function FileDetailsPage({ file }: { file: NostrEvent }) {
</Box>
)}
<Divider mx="auto" maxW="6xl" w="full" />
<Divider mx="auto" maxW={maxWidth} w="full" />
{summary && <Text whiteSpace="pre-line">{summary}</Text>}
<Flex gap="2" wrap="wrap">
<ButtonGroup gap="2" size="sm" variant="ghost">

View File

@ -3,7 +3,6 @@ import { useNavigate } from "react-router-dom";
import { PasswordSigner, SerialPortSigner, SimpleSigner } from "applesauce-signer";
import { useObservable } from "applesauce-react/hooks";
import VerticalPageLayout from "../../../components/vertical-page-layout";
import useCurrentAccount from "../../../hooks/use-current-account";
import UserAvatar from "../../../components/user/user-avatar";
import UserName from "../../../components/user/user-name";
@ -11,10 +10,7 @@ import UserDnsIdentity from "../../../components/user/user-dns-identity";
import accountService from "../../../services/account";
import AccountTypeBadge from "../../../components/account-info-badge";
import SimpleSignerBackup from "./components/simple-signer-backup";
import PasswordSignerBackup from "./components/password-signer-backup";
import { ReactNode } from "react";
import MigrateAccountToDevice from "./components/migrate-to-device";
import SimpleHeader from "../../../components/layout/presets/simple-header";
import SimpleView from "../../../components/layout/presets/simple-view";
function AccountBackup() {

View File

@ -74,13 +74,15 @@ export default function DisplaySettings() {
Max Page width
</FormLabel>
<Select id="maxPageWidth" {...register("maxPageWidth")} maxW="sm">
<option value="none">None</option>
<option value="md">Medium (~768px)</option>
<option value="lg">Large (~992px)</option>
<option value="xl">Extra Large (~1280px)</option>
<option value="none">Default</option>
<option value="full">Full</option>
<option value="sm">Small</option>
<option value="md">Medium</option>
<option value="lg">Large</option>
<option value="xl">Extra Large</option>
</Select>
<FormHelperText>
<span>Setting this will restrict the width of app on desktop</span>
<span>Setting this will restrict the width of the timeline</span>
</FormHelperText>
</FormControl>
<FormControl>

View File

@ -19,6 +19,7 @@ import UserAvatarLink from "../../components/user/user-avatar-link";
import { ReplyIcon } from "../../components/icons";
import TimelineNote from "../../components/note/timeline-note";
import { getSharableEventAddress } from "../../services/relay-hints";
import useMaxPageWidth from "../../hooks/use-max-page-width";
function CollapsedReplies({
pointer,
@ -109,8 +110,9 @@ export default function ThreadView() {
const callback = useTimelineCurserIntersectionCallback(timeline);
const maxWidth = useMaxPageWidth("6xl");
return (
<VerticalPageLayout maxW="6xl" mx="auto" w="full">
<VerticalPageLayout maxW={maxWidth} mx="auto" w="full">
{!focusedEvent && (
<>
<Heading my="4">

View File

@ -9,6 +9,7 @@ import TimelineActionAndStatus from "../../components/timeline/timeline-action-a
import VerticalPageLayout from "../../components/vertical-page-layout";
import ArticleCard from "../articles/components/article-card";
import { ErrorBoundary } from "../../components/error-boundary";
import useMaxPageWidth from "../../hooks/use-max-page-width";
export default function UserArticlesTab() {
const { pubkey } = useOutletContext() as { pubkey: string };
@ -20,9 +21,11 @@ export default function UserArticlesTab() {
});
const callback = useTimelineCurserIntersectionCallback(loader);
const maxWidth = useMaxPageWidth();
return (
<IntersectionObserverProvider callback={callback}>
<VerticalPageLayout maxW="6xl" mx="auto">
<VerticalPageLayout maxW={maxWidth} mx="auto">
{articles?.map((article) => (
<ErrorBoundary key={article.id} event={article}>
<ArticleCard article={article} />