diff --git a/src/routes/Outlet.module.css b/src/routes/Outlet.module.css index a49842cab0..10002c172d 100644 --- a/src/routes/Outlet.module.css +++ b/src/routes/Outlet.module.css @@ -16,7 +16,14 @@ /* If empty state or page is shown (not hidden), router outlet (first column) should have max width */ > div:not(:global(.ion-hide)) ~ ion-router-outlet { - max-width: 520px; + flex: 0 0 var(--first-column-width); + max-width: calc(100% - 300px); + } + + /* Column divider */ + > .columnDivider { + order: 0; + flex: 0 0 auto; } /* First column (main content) */ @@ -42,3 +49,32 @@ } } } + +/* Resizable divider styles */ +.columnDivider { + width: 4px; + background: var( + --ion-toolbar-background, + var(--ion-color-step-50, var(--ion-background-color-step-50, #f7f7f7)) + ); + cursor: col-resize; + position: relative; + transition: background-color 0.2s ease; +} + +.columnDivider:hover, +.columnDivider:active { + background: var(--ion-color-light); +} + +.columnDivider::before { + content: ""; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 2px; + height: 20px; + background: var(--ion-color-light); + border-radius: 1px; +} diff --git a/src/routes/Outlet.tsx b/src/routes/Outlet.tsx index 71260dcb25..cbfd0aab57 100644 --- a/src/routes/Outlet.tsx +++ b/src/routes/Outlet.tsx @@ -15,6 +15,7 @@ import buildPostsRoutes from "./tabs/posts"; import profile from "./tabs/profile"; import search from "./tabs/search"; import settings from "./tabs/settings"; +import ColumnDivider from "./twoColumn/ColumnDivider"; import SecondColumnContent from "./twoColumn/SecondColumnContent"; import styles from "./Outlet.module.css"; @@ -51,6 +52,7 @@ function AppRoutes() { return (
+ {twoColumnLayoutEnabled && } {twoColumnLayoutEnabled && } {/* This is first (order = -1) in css. Why? See Outlet.module.css */} diff --git a/src/routes/twoColumn/ColumnDivider.tsx b/src/routes/twoColumn/ColumnDivider.tsx new file mode 100644 index 0000000000..d4f46c8454 --- /dev/null +++ b/src/routes/twoColumn/ColumnDivider.tsx @@ -0,0 +1,85 @@ +import { useEffect, useRef, useState } from "react"; + +import { useColumnWidth } from "./useColumnWidth"; + +import styles from "../Outlet.module.css"; + +interface ColumnDividerProps { + onResize?: (width: number) => void; +} + +export default function ColumnDivider({ onResize }: ColumnDividerProps) { + const dividerRef = useRef(null); + const [isResizing, setIsResizing] = useState(false); + const [startX, setStartX] = useState(0); + const [startWidth, setStartWidth] = useState(0); + const { updateColumnWidth } = useColumnWidth(); + + useEffect(() => { + const handleMouseDown = (e: MouseEvent) => { + if (e.target === dividerRef.current) { + console.log("Mouse down on divider"); + setIsResizing(true); + setStartX(e.clientX); + + // Get current width with fallback to default + const currentWidthStr = getComputedStyle( + document.documentElement, + ).getPropertyValue("--first-column-width"); + const currentWidth = parseInt(currentWidthStr) || 520; // fallback to 520px + console.log( + "Current width:", + currentWidth, + "raw value:", + currentWidthStr, + ); + setStartWidth(currentWidth); + + document.body.style.cursor = "col-resize"; + document.body.style.userSelect = "none"; + } + }; + + const handleMouseMove = (e: MouseEvent) => { + if (!isResizing) return; + + const deltaX = e.clientX - startX; + const newWidth = Math.max(300, Math.min(800, startWidth + deltaX)); + + console.log("Resizing to:", newWidth, "delta:", deltaX); + updateColumnWidth(newWidth); + onResize?.(newWidth); + }; + + const handleMouseUp = () => { + console.log("Mouse up, stopping resize"); + setIsResizing(false); + document.body.style.cursor = ""; + document.body.style.userSelect = ""; + }; + + const divider = dividerRef.current; + if (divider) { + divider.addEventListener("mousedown", handleMouseDown); + } + + document.addEventListener("mousemove", handleMouseMove); + document.addEventListener("mouseup", handleMouseUp); + + return () => { + if (divider) { + divider.removeEventListener("mousedown", handleMouseDown); + } + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + }; + }, [isResizing, startX, startWidth, onResize, updateColumnWidth]); + + return ( +
+ ); +} diff --git a/src/routes/twoColumn/useColumnWidth.ts b/src/routes/twoColumn/useColumnWidth.ts new file mode 100644 index 0000000000..50c1f1c69b --- /dev/null +++ b/src/routes/twoColumn/useColumnWidth.ts @@ -0,0 +1,36 @@ +import { useEffect, useState } from "react"; + +const DEFAULT_WIDTH = 520; +const MIN_WIDTH = 300; +const MAX_WIDTH = 800; + +export function useColumnWidth() { + const [columnWidth, setColumnWidth] = useState(DEFAULT_WIDTH); + + // Initialize the CSS custom property when the component mounts + useEffect(() => { + document.documentElement.style.setProperty( + "--first-column-width", + `${DEFAULT_WIDTH}px`, + ); + console.log("Initialized CSS property to:", DEFAULT_WIDTH); + }, []); + + const updateColumnWidth = (width: number) => { + const clampedWidth = Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, width)); + console.log("Setting column width to:", clampedWidth); + setColumnWidth(clampedWidth); + document.documentElement.style.setProperty( + "--first-column-width", + `${clampedWidth}px`, + ); + console.log( + "CSS property set, checking:", + getComputedStyle(document.documentElement).getPropertyValue( + "--first-column-width", + ), + ); + }; + + return { columnWidth, updateColumnWidth }; +}