mirror of
https://github.com/hex248/ob248.com.git
synced 2026-02-09 11:13:03 +00:00
tabs always enabled
This commit is contained in:
353
src/App.tsx
353
src/App.tsx
@@ -48,7 +48,6 @@ export default App;
|
|||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const isDevMode = import.meta.env.VITE_PUBLIC_DEV === "1";
|
const isDevMode = import.meta.env.VITE_PUBLIC_DEV === "1";
|
||||||
const isTabsEnabled = import.meta.env.VITE_TABS === "1";
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [asciiArt, setAsciiArt] = useState("");
|
const [asciiArt, setAsciiArt] = useState("");
|
||||||
const [activeHomeTab, setActiveHomeTab] = useState<HomeTab>("work");
|
const [activeHomeTab, setActiveHomeTab] = useState<HomeTab>("work");
|
||||||
@@ -123,7 +122,7 @@ function Home() {
|
|||||||
if (event.defaultPrevented || event.isComposing) return;
|
if (event.defaultPrevented || event.isComposing) return;
|
||||||
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
||||||
|
|
||||||
if (isTabsEnabled && event.key === "Tab") {
|
if (event.key === "Tab") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setActiveHomeTab((prev) => {
|
setActiveHomeTab((prev) => {
|
||||||
const currentIndex = homeTabs.indexOf(prev);
|
const currentIndex = homeTabs.indexOf(prev);
|
||||||
@@ -428,201 +427,183 @@ function Home() {
|
|||||||
Age: <TimeSince date={new Date(2004, 10, 4, 11, 47, 0)} />
|
Age: <TimeSince date={new Date(2004, 10, 4, 11, 47, 0)} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isTabsEnabled ? (
|
<Tabs
|
||||||
<Tabs
|
value={activeHomeTab}
|
||||||
value={activeHomeTab}
|
onValueChange={(value) => setActiveHomeTab(value as HomeTab)}
|
||||||
onValueChange={(value) => setActiveHomeTab(value as HomeTab)}
|
className="w-full max-w-5xl gap-0"
|
||||||
className="w-full max-w-5xl gap-0"
|
>
|
||||||
|
<TabsList
|
||||||
|
variant="line"
|
||||||
|
className="relative z-0 h-auto w-full gap-0 p-0"
|
||||||
>
|
>
|
||||||
<TabsList
|
<TabsTrigger
|
||||||
variant="line"
|
value={homeTabs[0]}
|
||||||
className="relative z-0 h-auto w-full gap-0 p-0"
|
className="border-border -mr-[1px] after:hidden data-[state=active]:text-accent"
|
||||||
>
|
>
|
||||||
<TabsTrigger
|
Work
|
||||||
value={homeTabs[0]}
|
</TabsTrigger>
|
||||||
className="border-border -mr-[1px] after:hidden data-[state=active]:text-accent"
|
<TabsTrigger
|
||||||
>
|
value={homeTabs[1]}
|
||||||
Work
|
className="border-border after:hidden data-[state=active]:text-accent"
|
||||||
</TabsTrigger>
|
>
|
||||||
<TabsTrigger
|
Travel
|
||||||
value={homeTabs[1]}
|
</TabsTrigger>
|
||||||
className="border-border after:hidden data-[state=active]:text-accent"
|
</TabsList>
|
||||||
>
|
<TabsContent value={homeTabs[0]} className="relative z-10">
|
||||||
Travel
|
<div className="-mt-[1.5px] border p-2 grid grid-cols-1 gap-2 md:grid-cols-2">
|
||||||
</TabsTrigger>
|
{visibleProjects.map((project, index) => (
|
||||||
</TabsList>
|
<ProjectListItem
|
||||||
<TabsContent value={homeTabs[0]} className="relative z-10">
|
key={project.metadata.slug}
|
||||||
<div className="-mt-[1.5px] border p-2 grid grid-cols-1 gap-2 md:grid-cols-2">
|
metadata={project.metadata}
|
||||||
{visibleProjects.map((project, index) => (
|
isDevMode={isDevMode}
|
||||||
<ProjectListItem
|
isActive={
|
||||||
key={project.metadata.slug}
|
activeProjectIndex !== null && index === activeProjectIndex
|
||||||
metadata={project.metadata}
|
}
|
||||||
isDevMode={isDevMode}
|
/>
|
||||||
isActive={
|
))}
|
||||||
activeProjectIndex !== null && index === activeProjectIndex
|
</div>
|
||||||
}
|
</TabsContent>
|
||||||
/>
|
<TabsContent value={homeTabs[1]} className="relative z-10">
|
||||||
))}
|
<div className="-mt-[1px] grid grid-cols-1">
|
||||||
</div>
|
{locations.map((location, index) => (
|
||||||
</TabsContent>
|
<div key={location.id}>
|
||||||
<TabsContent value={homeTabs[1]} className="relative z-10">
|
<Button
|
||||||
<div className="-mt-[1px] grid grid-cols-1">
|
className={cn(
|
||||||
{locations.map((location, index) => (
|
"text-sm border cursor-pointer hover:border-accent justify-start w-full",
|
||||||
<div key={location.id}>
|
activeLocationIndex === index &&
|
||||||
<Button
|
activeHomeTab === "travel" &&
|
||||||
className={cn(
|
travelFocusLevel === "location" &&
|
||||||
"text-sm border cursor-pointer hover:border-accent justify-start",
|
"border-accent",
|
||||||
activeLocationIndex === index &&
|
)}
|
||||||
activeHomeTab === "travel" &&
|
onClick={(_e) => {
|
||||||
travelFocusLevel === "location" &&
|
const isExpanded = expandedLocationIndex === index;
|
||||||
"border-accent",
|
const photos = locationPhotos[location.id] ?? [];
|
||||||
)}
|
|
||||||
onClick={(_e) => {
|
|
||||||
const isExpanded = expandedLocationIndex === index;
|
|
||||||
const photos = locationPhotos[location.id] ?? [];
|
|
||||||
|
|
||||||
setActiveLocationIndex(index);
|
setActiveLocationIndex(index);
|
||||||
|
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
setExpandedLocationIndex(null);
|
setExpandedLocationIndex(null);
|
||||||
setTravelFocusLevel("location");
|
setTravelFocusLevel("location");
|
||||||
setPreviewPhotoPath(null);
|
setPreviewPhotoPath(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setExpandedLocationIndex(index);
|
setExpandedLocationIndex(index);
|
||||||
|
|
||||||
if (photos.length === 0) {
|
if (photos.length === 0) {
|
||||||
setTravelFocusLevel("location");
|
setTravelFocusLevel("location");
|
||||||
setPreviewPhotoPath(null);
|
setPreviewPhotoPath(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextPhotoIndex = clampIndex(
|
const nextPhotoIndex = clampIndex(
|
||||||
activePhotoIndexByLocation[location.id] ?? 0,
|
activePhotoIndexByLocation[location.id] ?? 0,
|
||||||
photos.length,
|
photos.length,
|
||||||
);
|
);
|
||||||
const nextPhotoName = photos[nextPhotoIndex];
|
const nextPhotoName = photos[nextPhotoIndex];
|
||||||
if (!nextPhotoName) {
|
if (!nextPhotoName) {
|
||||||
setTravelFocusLevel("location");
|
setTravelFocusLevel("location");
|
||||||
setPreviewPhotoPath(null);
|
setPreviewPhotoPath(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setActivePhotoIndexByLocation((prev) => ({
|
setActivePhotoIndexByLocation((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[location.id]: nextPhotoIndex,
|
[location.id]: nextPhotoIndex,
|
||||||
}));
|
}));
|
||||||
setPreviewPhotoPath(
|
setPreviewPhotoPath(
|
||||||
getTravelPhotoPath(location, nextPhotoName),
|
getTravelPhotoPath(location, nextPhotoName),
|
||||||
);
|
);
|
||||||
setTravelFocusLevel("photo");
|
setTravelFocusLevel("photo");
|
||||||
}}
|
}}
|
||||||
variant="dummy"
|
variant="dummy"
|
||||||
size="sm"
|
size="sm"
|
||||||
>
|
>
|
||||||
{location.city}, {location.country} - {location.date}
|
{location.city}, {location.country} - {location.date}
|
||||||
</Button>
|
</Button>
|
||||||
{expandedLocationIndex === index &&
|
{expandedLocationIndex === index &&
|
||||||
(locationPhotos[location.id].length === 0 ? (
|
(locationPhotos[location.id].length === 0 ? (
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex flex-col flex-1 ml-8">
|
<div className="flex flex-col flex-1 ml-8">
|
||||||
<Button
|
<Button
|
||||||
disabled
|
disabled
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex text-sm border cursor-pointer hover:border-accent items-center justify-start p-0 pl-2 ",
|
"flex text-sm border cursor-pointer hover:border-accent items-center justify-start p-0 pl-2 w-full",
|
||||||
)}
|
|
||||||
variant="dummy"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
<ImageDelete size={16} /> No photos available
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex">
|
|
||||||
<div
|
|
||||||
id={getTravelPhotoListId(location.id)}
|
|
||||||
className="flex flex-col flex-1 ml-8 max-h-128 overflow-y-auto gap-1"
|
|
||||||
>
|
|
||||||
{locationPhotos[location.id].map(
|
|
||||||
(photo, photoIndex) => (
|
|
||||||
<Button
|
|
||||||
key={photo}
|
|
||||||
id={getTravelPhotoItemId(
|
|
||||||
location.id,
|
|
||||||
photoIndex,
|
|
||||||
)}
|
|
||||||
onClick={() => {
|
|
||||||
const path = getTravelPhotoPath(
|
|
||||||
location,
|
|
||||||
photo,
|
|
||||||
);
|
|
||||||
setActiveLocationIndex(index);
|
|
||||||
setExpandedLocationIndex(index);
|
|
||||||
setTravelFocusLevel("photo");
|
|
||||||
setActivePhotoIndexByLocation((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[location.id]: photoIndex,
|
|
||||||
}));
|
|
||||||
setPreviewPhotoPath(path);
|
|
||||||
}}
|
|
||||||
className={cn(
|
|
||||||
"flex text-sm border cursor-pointer hover:border-accent items-center justify-start p-0 pl-2 ",
|
|
||||||
activeHomeTab === "travel" &&
|
|
||||||
travelFocusLevel === "photo" &&
|
|
||||||
activePhotoIndexByLocation[location.id] ===
|
|
||||||
photoIndex &&
|
|
||||||
"border-accent",
|
|
||||||
)}
|
|
||||||
variant="dummy"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
<Image size={22} />
|
|
||||||
{photo}
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
)}
|
)}
|
||||||
</div>
|
variant="dummy"
|
||||||
<div
|
size="sm"
|
||||||
className={
|
|
||||||
"flex-1 max-w-sm border flex items-center h-128 justify-center text-sm gap-4"
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{previewPhotoPath ? (
|
<ImageDelete size={16} /> No photos available
|
||||||
<img
|
</Button>
|
||||||
className={"flex-1 max-w-sm"}
|
|
||||||
src={previewPhotoPath}
|
|
||||||
alt={"active-photo"}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span>
|
|
||||||
<ImageDelete />
|
|
||||||
No photo selected
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</div>
|
) : (
|
||||||
))}
|
<div className="flex">
|
||||||
</div>
|
<div
|
||||||
</TabsContent>
|
id={getTravelPhotoListId(location.id)}
|
||||||
</Tabs>
|
className="flex flex-col flex-1 ml-8 max-h-128 overflow-y-auto gap-1"
|
||||||
) : (
|
>
|
||||||
<div className="w-full max-w-5xl grid grid-cols-1 gap-2 md:grid-cols-2">
|
{locationPhotos[location.id].map(
|
||||||
{visibleProjects.map((project, index) => (
|
(photo, photoIndex) => (
|
||||||
<ProjectListItem
|
<Button
|
||||||
key={project.metadata.slug}
|
key={photo}
|
||||||
metadata={project.metadata}
|
id={getTravelPhotoItemId(location.id, photoIndex)}
|
||||||
isDevMode={isDevMode}
|
onClick={() => {
|
||||||
isActive={
|
const path = getTravelPhotoPath(
|
||||||
activeProjectIndex !== null && index === activeProjectIndex
|
location,
|
||||||
}
|
photo,
|
||||||
/>
|
);
|
||||||
))}
|
setActiveLocationIndex(index);
|
||||||
</div>
|
setExpandedLocationIndex(index);
|
||||||
)}
|
setTravelFocusLevel("photo");
|
||||||
|
setActivePhotoIndexByLocation((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[location.id]: photoIndex,
|
||||||
|
}));
|
||||||
|
setPreviewPhotoPath(path);
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"flex text-sm border cursor-pointer hover:border-accent items-center justify-start p-0 pl-2 ",
|
||||||
|
activeHomeTab === "travel" &&
|
||||||
|
travelFocusLevel === "photo" &&
|
||||||
|
activePhotoIndexByLocation[location.id] ===
|
||||||
|
photoIndex &&
|
||||||
|
"border-accent",
|
||||||
|
)}
|
||||||
|
variant="dummy"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<Image size={22} />
|
||||||
|
{photo}
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"flex-1 max-w-lg border flex items-center h-128 justify-center text-sm gap-4"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{previewPhotoPath ? (
|
||||||
|
<img
|
||||||
|
className={"flex-1 object-contain max-h-full"}
|
||||||
|
src={previewPhotoPath}
|
||||||
|
alt={"active-photo"}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
<ImageDelete />
|
||||||
|
No photo selected
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
<div className="w-full max-w-5xl grid grid-cols-1 md:grid-cols-[1fr_auto_1fr] items-center gap-3 md:gap-4">
|
<div className="w-full max-w-5xl grid grid-cols-1 md:grid-cols-[1fr_auto_1fr] items-center gap-3 md:gap-4">
|
||||||
<div className="flex items-center gap-6">
|
<div className="flex items-center gap-6">
|
||||||
<AskAI name="me" inline />
|
<AskAI name="me" inline />
|
||||||
|
|||||||
Reference in New Issue
Block a user