← back to Nineoh Guide

apps/web/components/EpisodeControls.tsx

60 lines

"use client";
import { useEffect, useState } from "react";

/**
 * Sort + density for the episode guide (standing rule). Density toggles whether
 * recaps show (comfortable) or hide for fast title scanning (compact), via a CSS
 * var + localStorage. Sort flips season order through a query param (server-ordered).
 */
const KEY = "nineoh.epDensity.v1";

export function EpisodeControls({ order }: { order: string }) {
  const [compact, setCompact] = useState(false);

  useEffect(() => {
    const c = localStorage.getItem(KEY) === "compact";
    setCompact(c);
    document.documentElement.style.setProperty("--ep-recaps", c ? "none" : "block");
  }, []);

  const setDensity = (c: boolean) => {
    setCompact(c);
    document.documentElement.style.setProperty("--ep-recaps", c ? "none" : "block");
    localStorage.setItem(KEY, c ? "compact" : "comfortable");
  };

  const onSort = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const url = new URL(window.location.href);
    url.searchParams.set("order", e.target.value);
    window.location.href = url.toString();
  };

  return (
    <div style={{ display: "flex", gap: 14, alignItems: "center", flexWrap: "wrap", margin: "10px 0 4px", fontSize: 13 }}>
      <label>
        Sort{" "}
        <select defaultValue={order} onChange={onSort} aria-label="Sort episodes">
          <option value="asc">Season 1 → 5</option>
          <option value="desc">Season 5 → 1</option>
        </select>
      </label>
      <span style={{ display: "inline-flex", border: "1px solid var(--line)", borderRadius: 8, overflow: "hidden" }}>
        <button
          onClick={() => setDensity(false)}
          style={{ border: "none", borderRadius: 0, background: !compact ? "var(--gold-2)" : "transparent" }}
          aria-pressed={!compact}
        >
          Comfortable
        </button>
        <button
          onClick={() => setDensity(true)}
          style={{ border: "none", borderRadius: 0, background: compact ? "var(--gold-2)" : "transparent" }}
          aria-pressed={compact}
        >
          Compact
        </button>
      </span>
    </div>
  );
}