Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
334 changes: 334 additions & 0 deletions deadsimple.txt

Large diffs are not rendered by default.

24 changes: 18 additions & 6 deletions src/app/(feed)/feed/TodayItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ function ItemDisplay({ contentId }: { contentId: string }) {

const itemDestination = item.platform === "website" ? "read" : "watch";

const shouldOpenInSerial = feed?.openLocation === "serial";

const href = shouldOpenInSerial
? `/feed/${itemDestination}/${item.id}`
: item.url;

const target = shouldOpenInSerial ? undefined : "_blank";
const rel = shouldOpenInSerial ? undefined : "noopener noreferrer";

return (
<article
className={clsx(
Expand All @@ -176,7 +185,9 @@ function ItemDisplay({ contentId }: { contentId: string }) {
)}
>
<Link
href={`/feed/${itemDestination}/${item.contentId}`}
href={href}
target={target}
rel={rel}
className="sm:hover:bg-muted flex w-full flex-1 flex-col gap-4 py-4 pr-4 pl-6 text-left transition-colors md:h-20 md:flex-row md:items-center md:rounded md:py-0 md:pr-0"
prefetch
>
Expand All @@ -195,15 +206,16 @@ function ItemDisplay({ contentId }: { contentId: string }) {
/>
</div>
) : (
<div className="bg-muted aspect-video w-16 rounded object-cover" />
<div className="grid aspect-video w-16 place-items-center rounded object-cover">
<div className="bg-muted aspect-square h-9 rounded object-cover" />
</div>
)}

<div className="flex h-full flex-1 flex-col justify-center">
<h3 className="line-clamp-1 w-full text-xs font-semibold md:text-sm">
{item.title}
</h3>
<p className="w-full text-xs opacity-80 md:text-sm">
{item.author} • {timeAgo(item.postedAt)}
{item.author || feed?.name} • {timeAgo(item.postedAt)}
</p>
</div>
</Link>
Expand All @@ -213,7 +225,7 @@ function ItemDisplay({ contentId }: { contentId: string }) {
variant="ghost"
onClick={() => {
void setWatchLaterValue({
contentId: item.contentId,
id: item.id,
feedId: item.feedId!,
isWatchLater: !item.isWatchLater,
});
Expand All @@ -230,7 +242,7 @@ function ItemDisplay({ contentId }: { contentId: string }) {
variant="ghost"
onClick={() => {
void setWatchedValue({
contentId: item.contentId,
id: item.id,
feedId: item.feedId!,
isWatched: !item.isWatched,
});
Expand Down
52 changes: 43 additions & 9 deletions src/app/(feed)/feed/TopRightHeaderContent.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
"use client";

import { ExternalLinkIcon, MinusIcon, PlusIcon } from "lucide-react";
import {
ExternalLinkIcon,
MinusIcon,
PlusIcon,
SettingsIcon,
} from "lucide-react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { ButtonWithShortcut } from "~/components/ButtonWithShortcut";
Expand All @@ -11,13 +16,10 @@ import { useFeedItemGlobalState } from "~/lib/data/atoms";
import { useShortcut } from "~/lib/hooks/useShortcut";
import { OpenRightSidebarButton } from "./OpenRightSidebarButton";
import { RefetchItemsButton } from "./RefetchItemsButton";
import { MAX_ZOOM, MIN_ZOOM, useZoom } from "./watch/[videoID]/useZoom";

const PLATFORM_TO_FORMATTED_NAME = {
youtube: "YouTube",
peertube: "PeerTube",
website: "Website",
} as const;
import { MAX_ZOOM, MIN_ZOOM, useZoom } from "./watch/[id]/useZoom";
import { useState } from "react";
import { EditFeedDialog } from "~/components/AddFeedDialog";
import { PLATFORM_TO_FORMATTED_NAME_MAP } from "~/lib/data/feeds/utils";

function OpenInYouTubeButton() {
const pathname = usePathname();
Expand Down Expand Up @@ -46,14 +48,44 @@ function OpenInYouTubeButton() {
<Link href={feedItem.url} target="_blank" rel="noopener noreferrer">
<Button variant="outline" size="icon md:default">
<span className="hidden pr-1.5 md:block">
{PLATFORM_TO_FORMATTED_NAME[feedItem.platform]}
{PLATFORM_TO_FORMATTED_NAME_MAP[feedItem.platform]}
</span>
<ExternalLinkIcon size={16} />
</Button>
</Link>
);
}

function EditFeedButton() {
const pathname = usePathname();
const videoId = pathname.split("/feed/watch/")[1]!;
const contentId = pathname.split("/feed/read/")[1]!;

const [feedItem] = useFeedItemGlobalState(videoId || contentId || "");

const [selectedFeedForEditing, setSelectedFeedForEditing] = useState<
null | number
>(null);

return (
<>
<Button
variant="outline"
size="icon"
onClick={() => {
setSelectedFeedForEditing(feedItem.feedId);
}}
>
<SettingsIcon size={16} />
</Button>
<EditFeedDialog
selectedFeedId={selectedFeedForEditing}
onClose={() => setSelectedFeedForEditing(null)}
/>
</>
);
}

export function TopRightHeaderContent() {
const pathname = usePathname();

Expand All @@ -67,6 +99,7 @@ export function TopRightHeaderContent() {
if (isMobile) {
return (
<div className="flex items-center gap-2">
<EditFeedButton />
<OpenInYouTubeButton />
</div>
);
Expand All @@ -92,6 +125,7 @@ export function TopRightHeaderContent() {
>
<PlusIcon size={16} />
</ButtonWithShortcut>
<EditFeedButton />
<OpenInYouTubeButton />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
.article a {
background: var(--color-sidebar-accent);
color: var(--color-sidebar-accent-foreground);
border-radius: var(--radius-sm);
padding-inline: 0.125rem;
text-decoration: none;
}

Expand All @@ -59,7 +61,13 @@
}

.article img {
margin-block: 1.5rem;
margin-top: 1.5rem;
margin-bottom: 0.5rem;
width: 100%;
}

.article img + :not(span) {
margin-bottom: 1.5rem;
}

.article ul {
Expand All @@ -74,6 +82,7 @@

.article li {
margin-block: 0.25rem;
line-height: 1.7rem;
}

.article blockquote {
Expand All @@ -85,6 +94,31 @@
text-decoration: none;
}

.article img {
width: 100%;
.article span {
opacity: 0.7;
font-size: 0.9rem;
margin-block: 0.5rem;
}

.article pre {
overflow-x: scroll;
}

.article * {
--non-edge: calc(var(--article-max-width));
--edge: calc(100vw - var(--spacing) * 16);

max-width: min(var(--edge), var(--non-edge));
}

.article pre {
padding: 1rem;
background: var(--color-muted);
border-radius: var(--radius-md);
width: min-content;
}

.article code {
background: var(--color-muted);
border-radius: var(--radius-md);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import clsx from "clsx";
import { use } from "react";

import { useFeedItemGlobalState } from "~/lib/data/atoms";
import { useZoom } from "../../watch/[videoID]/useZoom";
import { useZoom } from "../../watch/[id]/useZoom";

import classes from "./article.module.css";
import { useFeeds } from "~/lib/data/feeds";
Expand All @@ -13,20 +13,30 @@ import rehypeParse from "rehype-parse";
import rehypeSanitize from "rehype-sanitize";
import rehypeStringify from "rehype-stringify";
import { useFlagState } from "~/lib/hooks/useFlagState";
import { ContentActions } from "../../watch/[videoID]/ContentActions";
import { ContentActions } from "../../watch/[id]/ContentActions";

const parser = unified()
.use(rehypeParse, { fragment: true })
.use(rehypeSanitize)
.use(rehypeStringify);

const MAX_WIDTH_MAP: Record<number, string> = {
[0]: "container-xl",
[1]: "container-2xl",
[2]: "container-3xl",
[3]: "container-4xl",
[4]: "container-5xl",
[5]: "container-6xl",
[6]: "container-7xl",
};

export default function WatchVideoPage(props: {
params: Promise<{ contentID: string }>;
params: Promise<{ id: string }>;
}) {
const [articleStyle] = useFlagState("ARTICLE_STYLE");
const params = use(props.params);

const [feedItem] = useFeedItemGlobalState(params?.contentID ?? "");
const [feedItem] = useFeedItemGlobalState(params?.id ?? "");
const { feeds } = useFeeds();

const feed = feeds.find((f) => f.id === feedItem.feedId);
Expand All @@ -50,13 +60,21 @@ export default function WatchVideoPage(props: {
"max-w-6xl": zoom === 5,
"max-w-7xl": zoom === 6,
})}
style={{
// @ts-expect-error This is fine and works
[`--article-max-width`]: `var(--${MAX_WIDTH_MAP[zoom]})`,
}}
>
<div className="mb-4 flex w-full items-center gap-2 px-6 sm:pt-6">
<img
src={feed?.imageUrl}
alt={feedItem.title}
className="aspect-square h-6 rounded object-cover"
/>
{!!feed?.imageUrl ? (
<img
src={feed?.imageUrl}
alt={feedItem.title}
className="aspect-square h-6 rounded object-cover"
/>
) : (
<div className="bg-muted aspect-square size-6 rounded object-cover" />
)}
<span className="font-mono text-sm">{feed?.name}</span>
</div>
<div className={`h-full w-full px-6 sm:pb-6 ${classes.article}`}>
Expand All @@ -69,7 +87,7 @@ export default function WatchVideoPage(props: {
/>
</div>
<div className="sticky inset-x-0 bottom-0 left-0 grid place-items-center">
<ContentActions contentID={params.contentID ?? ""} />
<ContentActions contentID={params.id ?? ""} />
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function ContentActions({ contentID }: { contentID: string }) {
const toggleWatchLater = async () => {
if (!video) return;
await setWatchLaterValue({
contentId: video.contentId,
id: video.id,
feedId: video.feedId!,
isWatchLater: !video.isWatchLater,
});
Expand All @@ -41,7 +41,7 @@ export function ContentActions({ contentID }: { contentID: string }) {
const toggleWatched = async () => {
if (!video) return;
await setWatchedValue({
contentId: video.contentId,
id: video.id,
feedId: video.feedId!,
isWatched: !video.isWatched,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useShortcut } from "~/lib/hooks/useShortcut";
import { useView } from "./useView";
import { ContentActions } from "./ContentActions";
import { useVideoNavigationShortcuts } from "./useVideoNavigationShortcuts";
import { useFeedItemGlobalState } from "~/lib/data/atoms";

export function VideoDisplay({
id,
Expand All @@ -13,6 +14,7 @@ export function VideoDisplay({
id: string;
isInactive: boolean;
}) {
const [item] = useFeedItemGlobalState(id);
const [showVideo, setShowVideo] = useState(false);

const { view, toggleView } = useView();
Expand Down Expand Up @@ -57,7 +59,7 @@ export function VideoDisplay({
"opacity-100": showVideo,
})}
>
<ResponsiveVideo videoID={id} isInactive={isInactive} />
<ResponsiveVideo videoID={item.contentId} isInactive={isInactive} />
</div>
</div>
<ContentActions contentID={id} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useZoom } from "./useZoom";
import { VideoDisplay } from "./VideoDisplay";

export default function WatchVideoPage(props: {
params: Promise<{ videoID: string }>;
params: Promise<{ id: string }>;
}) {
const params = use(props.params);

Expand Down Expand Up @@ -47,7 +47,7 @@ export default function WatchVideoPage(props: {
"sm:py-6": view === "windowed",
})}
>
<VideoDisplay id={params.videoID} isInactive={isInactive} />
<VideoDisplay id={params.id} isInactive={isInactive} />
</div>
</div>
);
Expand Down
Loading