Skip to content

Commit

Permalink
now with resizable panes!
Browse files Browse the repository at this point in the history
  • Loading branch information
steezeburger committed Aug 16, 2024
1 parent 8bcd643 commit 142d454
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 32 deletions.
6 changes: 6 additions & 0 deletions web/src/components/WikipediaBrowser.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,9 @@
border-radius: 3px;
text-decoration: none !important;
}

.wikipedia-content img {
max-width: 100%;
height: auto;
}

110 changes: 78 additions & 32 deletions web/src/components/WikipediaBrowser.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
"use client";

import React, { memo, useCallback, useEffect, useState } from "react";
import React, { memo, useCallback, useEffect, useState, useRef } from "react";
import "./WikipediaBrowser.css";

interface Pane {
title: string;
content: string;
isHomepage: boolean;
width: number;
}

const SearchBar = memo(({ onSearch }: { onSearch: (term: string, isHomepage: boolean) => void }) => {
Expand Down Expand Up @@ -42,43 +43,76 @@ const SearchBar = memo(({ onSearch }: { onSearch: (term: string, isHomepage: boo
});
SearchBar.displayName = "SearchBar";

const PaneComponent = memo(({ pane, index, onClose, onClick, clickedLinks }: {
const Resizer = memo(({ onResize }: { onResize: (delta: number) => void }) => {
const startResizeX = useRef(0);

const handleMouseDown = (e: React.MouseEvent) => {
startResizeX.current = e.clientX;
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
};

const handleMouseMove = (e: MouseEvent) => {
const delta = e.clientX - startResizeX.current;
onResize(delta);
startResizeX.current = e.clientX;
};

const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};

return (
<div
className="w-1 bg-gray-300 cursor-col-resize hover:bg-gray-400 transition-colors"
onMouseDown={handleMouseDown}
/>
);
});
Resizer.displayName = "Resizer";

const PaneComponent = memo(({ pane, index, onClose, onClick, clickedLinks, onResize }: {
pane: Pane;
index: number;
onClose: (index: number) => void;
onClick: (e: React.MouseEvent<HTMLDivElement>, index: number) => void;
clickedLinks: Set<string>;
onResize: (index: number, delta: number) => void;
}) => {
return (
<div className="flex-none w-[45rem] h-full border-r border-gray-200 overflow-y-auto">
<div className="flex justify-between items-center p-2 bg-gray-100 sticky top-0 z-10">
<h2 className="text-sm font-bold truncate text-black">{pane.title}</h2>
<button
onClick={() => onClose(index)}
className="p-1 hover:bg-gray-200 rounded-full transition-colors duration-200 text-black"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd" />
</svg>
</button>
<>
<div className="flex-none h-full border-r border-gray-200 overflow-y-auto" style={{ width: pane.width }}>
<div className="flex justify-between items-center p-2 bg-gray-100 sticky top-0 z-10">
<h2 className="text-sm font-bold truncate text-black">{pane.title}</h2>
<button
onClick={() => onClose(index)}
className="p-1 hover:bg-gray-200 rounded-full transition-colors duration-200 text-black"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd" />
</svg>
</button>
</div>
<div
className="wikipedia-content"
onClick={(e) => onClick(e, index)}
dangerouslySetInnerHTML={{ __html: pane.content }}
ref={(node) => {
if (node) {
node.querySelectorAll("a").forEach(a => {
if (clickedLinks.has(a.href)) {
a.classList.add("clicked-link");
}
});
}
}}
/>
</div>
<div
className="wikipedia-content"
onClick={(e) => onClick(e, index)}
dangerouslySetInnerHTML={{ __html: pane.content }}
ref={(node) => {
if (node) {
node.querySelectorAll("a").forEach(a => {
if (clickedLinks.has(a.href)) {
a.classList.add("clicked-link");
}
});
}
}}
/>
</div>
<Resizer onResize={(delta) => onResize(index, delta)} />
</>
);
});
PaneComponent.displayName = "PaneComponent";
Expand Down Expand Up @@ -110,7 +144,7 @@ const WikipediaBrowser: React.FC = () => {
const response = await fetch(`https://en.wikipedia.org/w/api.php?action=parse&format=json&page=${encodeURIComponent(title)}&prop=text&formatversion=2&origin=*`);
const data = await response.json();
if (data.parse) {
const newPane = { title: data.parse.title, content: data.parse.text, isHomepage };
const newPane = { title: data.parse.title, content: data.parse.text, isHomepage, width: 720 };
if (panes.length === 0 || (activePane === 0 && panes[0].isHomepage) || isHomepage) {
// For the first pane or updating the homepage, just set or update it
setPanes([newPane]);
Expand Down Expand Up @@ -140,13 +174,24 @@ const WikipediaBrowser: React.FC = () => {
setActivePane(paneIndex);
fetchWikipediaContent(link.title);
}
}, [panes, fetchWikipediaContent]);
}, [fetchWikipediaContent]);

const closePane = useCallback((index: number) => {
setPanes(prevPanes => prevPanes.filter((_, i) => i !== index));
setActivePane(prevActivePane => prevActivePane > index ? prevActivePane - 1 : prevActivePane);
}, []);

const handleResize = useCallback((index: number, delta: number) => {
setPanes(prevPanes => {
const newPanes = [...prevPanes];
newPanes[index] = { ...newPanes[index], width: Math.max(200, newPanes[index].width + delta) };
if (index < newPanes.length - 1) {
newPanes[index + 1] = { ...newPanes[index + 1], width: Math.max(200, newPanes[index + 1].width - delta) };
}
return newPanes;
});
}, []);

return (
<div className="flex flex-col h-screen bg-white">
<SearchBar onSearch={fetchWikipediaContent} />
Expand All @@ -159,6 +204,7 @@ const WikipediaBrowser: React.FC = () => {
onClose={closePane}
onClick={handleLinkClick}
clickedLinks={clickedLinks}
onResize={handleResize}
/>
))}
{isLoading && (
Expand Down

0 comments on commit 142d454

Please sign in to comment.