mirror of
https://github.com/gabehf/Koito.git
synced 2026-03-15 02:15:55 -07:00
chore: initial public commit
This commit is contained in:
commit
fc9054b78c
250 changed files with 32809 additions and 0 deletions
22
client/app/components/sidebar/Sidebar.tsx
Normal file
22
client/app/components/sidebar/Sidebar.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { ExternalLink, Home, Info } from "lucide-react";
|
||||
import SidebarSearch from "./SidebarSearch";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import SidebarSettings from "./SidebarSettings";
|
||||
|
||||
export default function Sidebar() {
|
||||
|
||||
const iconSize = 20;
|
||||
|
||||
return (
|
||||
<div className="z-50 flex flex-col justify-between h-screen border-r-1 border-(--color-bg-tertiary) p-1 py-10 sticky left-0 top-0 bg-(--color-bg)">
|
||||
<div className="flex flex-col gap-4">
|
||||
<SidebarItem space={10} to="/" name="Home" onClick={() => {}} modal={<></>}><Home size={iconSize} /></SidebarItem>
|
||||
<SidebarSearch size={iconSize} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<SidebarItem icon keyHint={<ExternalLink size={14} />} space={22} externalLink to="https://koito.io" name="About" onClick={() => {}} modal={<></>}><Info size={iconSize} /></SidebarItem>
|
||||
<SidebarSettings size={iconSize} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
48
client/app/components/sidebar/SidebarItem.tsx
Normal file
48
client/app/components/sidebar/SidebarItem.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import React, { useState } from "react";
|
||||
import Popup from "../Popup";
|
||||
import { Link } from "react-router";
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
to?: string;
|
||||
onClick: Function;
|
||||
children: React.ReactNode;
|
||||
modal: React.ReactNode;
|
||||
keyHint?: React.ReactNode;
|
||||
space?: number
|
||||
externalLink?: boolean
|
||||
/* true if the keyhint is an icon and not text */
|
||||
icon?: boolean
|
||||
}
|
||||
|
||||
export default function SidebarItem({ externalLink, space, keyHint, name, to, children, modal, onClick, icon }: Props) {
|
||||
const classes = "hover:cursor-pointer hover:bg-(--color-bg-tertiary) transition duration-100 rounded-md p-2 inline-block";
|
||||
|
||||
const popupInner = keyHint ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span>{name}</span>
|
||||
{icon ?
|
||||
<div>
|
||||
{keyHint}
|
||||
</div>
|
||||
:
|
||||
<kbd className="px-1 text-sm rounded bg-(--color-bg-tertiary) text-(--color-fg) border border-[var(--color-fg)]">
|
||||
{keyHint}
|
||||
</kbd>
|
||||
}
|
||||
</div>
|
||||
) : name;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popup position="right" space={space ?? 20} inner={popupInner}>
|
||||
{to ? (
|
||||
<Link target={externalLink ? "_blank" : ""} className={classes} to={to}>{children}</Link>
|
||||
) : (
|
||||
<a className={classes} onClick={() => onClick()}>{children}</a>
|
||||
)}
|
||||
</Popup>
|
||||
{modal}
|
||||
</>
|
||||
);
|
||||
}
|
||||
33
client/app/components/sidebar/SidebarSearch.tsx
Normal file
33
client/app/components/sidebar/SidebarSearch.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import { Search } from "lucide-react";
|
||||
import SearchModal from "../modals/SearchModal";
|
||||
|
||||
interface Props {
|
||||
size: number
|
||||
}
|
||||
|
||||
export default function SidebarSearch({ size } : Props) {
|
||||
const [open, setModalOpen] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === '/' && !open) {
|
||||
e.preventDefault();
|
||||
setModalOpen(true);
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
return () => document.removeEventListener('keydown', handleKeyDown);
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<SidebarItem
|
||||
space={26}
|
||||
onClick={() => setModalOpen(true)}
|
||||
name="Search"
|
||||
keyHint="/"
|
||||
children={<Search size={size}/>} modal={<SearchModal open={open} setOpen={setModalOpen} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
29
client/app/components/sidebar/SidebarSettings.tsx
Normal file
29
client/app/components/sidebar/SidebarSettings.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { Settings2 } from "lucide-react";
|
||||
import SettingsModal from "../modals/SettingsModal";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
size: number
|
||||
}
|
||||
|
||||
export default function SidebarSettings({ size }: Props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown= (e: KeyboardEvent) => {
|
||||
if (e.key === '\\' && !open) {
|
||||
e.preventDefault();
|
||||
setOpen(true);
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
return () => document.removeEventListener('keydown', handleKeyDown);
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<SidebarItem space={30} keyHint="\" name="Settings" onClick={() => setOpen(true)} modal={<SettingsModal open={open} setOpen={setOpen} />}>
|
||||
<Settings2 size={size} />
|
||||
</SidebarItem>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue