Online defaults to order:hot, with an Account toggle
New online_hot_default preference (on by default, so guests and accounts that never saved preferences get it): opening /online without a search replaces the URL with ?tags=order:hot — e621's metatag for the order the Hot page uses — so it is visible in the search field and shareable. Existing searches are never touched: they live in the URL, so a refresh or back/forward keeps them, while a fresh visit (nav pill, first time, after a long time away) gets the hot default again. Turning the toggle off opens Online on the site-wide newest posts as before. The toggle sits in Account -> Browsing preferences and saves with the rest of the settings; the backend validates the new boolean (400 for non-boolean input).
This commit is contained in:
@@ -127,3 +127,5 @@ class PreferencesSerializer(serializers.Serializer):
|
|||||||
ordering = serializers.CharField(max_length=30, required=False)
|
ordering = serializers.CharField(max_length=30, required=False)
|
||||||
per_page = serializers.IntegerField(min_value=12, max_value=200, required=False)
|
per_page = serializers.IntegerField(min_value=12, max_value=200, required=False)
|
||||||
zoom = serializers.IntegerField(min_value=120, max_value=400, required=False)
|
zoom = serializers.IntegerField(min_value=120, max_value=400, required=False)
|
||||||
|
# Open Online with the order:hot metatag when no search is given.
|
||||||
|
online_hot_default = serializers.BooleanField(required=False)
|
||||||
|
|||||||
@@ -170,6 +170,28 @@ export function PreferencesCard() {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label className="flex items-start gap-2 text-sm text-ctp-subtext0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={values.online_hot_default ?? true}
|
||||||
|
onChange={(event) =>
|
||||||
|
setValues((current) => ({
|
||||||
|
...current,
|
||||||
|
online_hot_default: event.target.checked,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className="mt-0.5 accent-ctp-mauve"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
Online starts with{" "}
|
||||||
|
<span className="font-mono text-ctp-blue">order:hot</span>
|
||||||
|
<span className="mt-0.5 block text-[11px] leading-relaxed text-ctp-overlay0">
|
||||||
|
Used when you open Online without a search. With it off, Online
|
||||||
|
opens on the site-wide newest posts.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Button onClick={() => void handleSave()} disabled={saving}>
|
<Button onClick={() => void handleSave()} disabled={saving}>
|
||||||
{saving ? "Saving…" : "Save preferences"}
|
{saving ? "Saving…" : "Save preferences"}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { X } from "lucide-react";
|
import { X } from "lucide-react";
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { Link, useLocation, useSearchParams } from "react-router-dom";
|
import { Link, useLocation, useSearchParams } from "react-router-dom";
|
||||||
|
|
||||||
import { CollapsibleSidebar } from "@/components/CollapsibleSidebar";
|
import { CollapsibleSidebar } from "@/components/CollapsibleSidebar";
|
||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
type E621Post,
|
type E621Post,
|
||||||
} from "@/lib/e621";
|
} from "@/lib/e621";
|
||||||
import { useE621 } from "@/store/e621";
|
import { useE621 } from "@/store/e621";
|
||||||
|
import { useAuth } from "@/store/auth";
|
||||||
import { useUi } from "@/store/ui";
|
import { useUi } from "@/store/ui";
|
||||||
import { toast } from "@/store/toasts";
|
import { toast } from "@/store/toasts";
|
||||||
|
|
||||||
@@ -34,11 +35,24 @@ export default function OnlinePage() {
|
|||||||
const credentials = useE621((state) => state.credentials);
|
const credentials = useE621((state) => state.credentials);
|
||||||
const blacklist = useE621((state) => state.blacklist);
|
const blacklist = useE621((state) => state.blacklist);
|
||||||
const saveBlacklist = useE621((state) => state.saveBlacklist);
|
const saveBlacklist = useE621((state) => state.saveBlacklist);
|
||||||
|
const user = useAuth((state) => state.user);
|
||||||
|
const authReady = useAuth((state) => state.ready);
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [draft, setDraft] = useState<string | null>(null);
|
const [draft, setDraft] = useState<string | null>(null);
|
||||||
const [blacklistDraft, setBlacklistDraft] = useState("");
|
const [blacklistDraft, setBlacklistDraft] = useState("");
|
||||||
const tagInput = draft ?? tags;
|
const tagInput = draft ?? tags;
|
||||||
const zoom = useUi((state) => state.zoom);
|
const zoom = useUi((state) => state.zoom);
|
||||||
|
const appliedHotDefault = useRef(false);
|
||||||
|
|
||||||
|
// Landing on Online without a search uses the order:hot default (on unless
|
||||||
|
// the account turns it off). Existing searches are left alone.
|
||||||
|
useEffect(() => {
|
||||||
|
if (!authReady || appliedHotDefault.current) return;
|
||||||
|
appliedHotDefault.current = true;
|
||||||
|
if (tags) return;
|
||||||
|
if (user?.preferences?.online_hot_default === false) return;
|
||||||
|
setSearchParams(buildParams("order:hot", 1), { replace: true });
|
||||||
|
}, [authReady, tags, user, setSearchParams]);
|
||||||
|
|
||||||
const blacklistMutation = useMutation({
|
const blacklistMutation = useMutation({
|
||||||
mutationFn: (lines: string[]) => saveBlacklist(lines),
|
mutationFn: (lines: string[]) => saveBlacklist(lines),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export interface UserPreferences {
|
|||||||
ordering?: string;
|
ordering?: string;
|
||||||
per_page?: number;
|
per_page?: number;
|
||||||
zoom?: number;
|
zoom?: number;
|
||||||
|
online_hot_default?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
|
|||||||
Reference in New Issue
Block a user