Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

[![](./docs/img/landing.png)](https://worxpace-playground.vercel.app)

### Important

**This project is no longer maintaining.**
I'm currently working on the Notion design system, see my new repo [`Notion Kit`](https://github.com/steeeee0223/notion-kit).

### Apps

- [Steeeee WorXpace](https://worxpace.steeeee0223.vercel.app/)
Expand Down
11 changes: 11 additions & 0 deletions packages/database-ui/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import baseConfig from "@swy/eslint-config/base";
import reactConfig from "@swy/eslint-config/react";

/** @type {import('typescript-eslint').Config} */
export default [
{
ignores: ["dist/**"],
},
...baseConfig,
...reactConfig,
];
13 changes: 13 additions & 0 deletions packages/database-ui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
46 changes: 46 additions & 0 deletions packages/database-ui/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@swy/database-ui",
"version": "1.4.0",
"private": true,
"type": "module",
"scripts": {
"build": "tsc -b && vite build",
"clean": "git clean -xdf .turbo node_modules",
"dev": "vite --port 5174",
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@swy/ui": "workspace:*",
"@tanstack/react-table": "catalog:ui",
"lucide-react": "catalog:ui",
"react": "catalog:react18",
"react-dom": "catalog:react18",
"usehooks-ts": "^2.9.1",
"uuid": "catalog:uuid",
"zod": "catalog:"
},
"devDependencies": {
"@swy/eslint-config": "workspace:*",
"@swy/prettier-config": "workspace:*",
"@swy/tailwind-config": "workspace:*",
"@swy/tsconfig": "workspace:*",
"@types/node": "catalog:node22",
"@types/react": "catalog:react18",
"@types/react-dom": "catalog:react18",
"@types/uuid": "catalog:uuid",
"eslint": "catalog:",
"globals": "^15.12.0",
"prettier": "catalog:",
"sonner": "catalog:ui",
"tailwindcss": "catalog:",
"typescript": "catalog:",
"vite": "^6.0.1"
},
"prettier": "@swy/prettier-config"
}
5 changes: 5 additions & 0 deletions packages/database-ui/postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
plugins: {
tailwindcss: {},
},
};
1 change: 1 addition & 0 deletions packages/database-ui/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions packages/database-ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import "./notion.css";

import { Database } from "./database";
import { ThemeProvider, ThemeToggle } from "./theme";

function App() {
return (
<ThemeProvider>
<div className="flex h-screen w-screen flex-col items-center gap-10 bg-main">
<ThemeToggle />
{/* Notion Page Content */}
<div
className="notion-page-content"
// No need: shrink-0 grow flex flex-col w-full max-w-full items-start text-base z-40
>
{/* Wrapper for Database View */}
{/* width, left, padding-x will change when resizing */}
<div className="relative h-1/2 min-h-10 w-full px-[96px]">
<Database />
</div>
</div>
</div>
</ThemeProvider>
);
}

export default App;
48 changes: 48 additions & 0 deletions packages/database-ui/src/database/button-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from "react";
import {
ArrowUpDown,
ChevronDown,
Ellipsis,
ListFilter,
Maximize2,
Search,
Zap,
} from "lucide-react";

import { cn } from "@swy/ui/lib";
import { Button } from "@swy/ui/shadcn";

const styles = {
icon: "flex-shrink-0 size-4 text-primary/45 dark:text-primary/45",
};

export const ButtonGroup: React.FC<{ className?: string }> = ({
className,
}) => {
return (
<div className={cn("flex items-center justify-end gap-0.5", className)}>
<Button variant="nav" size="icon-md" className="p-1.5">
<ListFilter className={styles.icon} />
</Button>
<Button variant="nav" size="icon-md" className="p-1.5">
<ArrowUpDown className={styles.icon} />
</Button>
<Button variant="nav" size="icon-md" className="p-1.5">
<Zap className={styles.icon} />
</Button>
<Button variant="nav" size="icon-md" className="p-1.5">
<Search className={styles.icon} />
</Button>
<Button variant="nav" size="icon-md" className="p-1.5">
<Maximize2 className={cn(styles.icon, "rotate-90")} />
</Button>
<Button variant="nav" size="icon-md" className="p-1.5">
<Ellipsis className={styles.icon} />
</Button>
<Button variant="blue" size="sm" className="h-7 px-2">
New
<ChevronDown className="ml-1 size-4" />
</Button>
</div>
);
};
1 change: 1 addition & 0 deletions packages/database-ui/src/database/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const paddingX = 96;
56 changes: 56 additions & 0 deletions packages/database-ui/src/database/database.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { DatabaseIcon, Ellipsis, Plus } from "lucide-react";

import {
Button,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@swy/ui/shadcn";

import { TableView } from "../table-view";
import { ButtonGroup } from "./button-group";
import { ViewWrapper } from "./view-wrapper";

export const Database = () => {
return (
<Tabs
defaultValue="members"
className="group/database relative mt-1 w-full"
>
<TabsList className="gap-3 overflow-y-auto p-0">
<div className="flex grow items-center">
<TabsTrigger value="members">Members</TabsTrigger>
<Button
variant="nav"
size="icon-md"
className="size-6 opacity-0 group-hover/database:opacity-100"
>
<Plus className="size-3.5 flex-shrink-0 text-primary/45 dark:text-primary/45" />
</Button>
</div>
<ButtonGroup className="opacity-0 group-hover/database:opacity-100" />
</TabsList>
<div className="flex w-full items-center justify-between pt-2">
<div className="mx-1 flex items-center gap-1">
<DatabaseIcon className="relative size-6 flex-shrink-0" />
<div className="w-full max-w-full whitespace-pre-wrap break-words text-[22px] font-bold caret-primary">
Title
</div>
<Button
variant="nav"
size="icon-md"
className="size-6 flex-shrink-0 opacity-0 group-hover/database:opacity-100"
>
<Ellipsis className="size-3.5 flex-shrink-0 text-primary/45 dark:text-primary/45" />
</Button>
</div>
</div>
<TabsContent value="members" className="mt-0 bg-main">
<ViewWrapper>
<TableView />
</ViewWrapper>
</TabsContent>
</Tabs>
);
};
1 change: 1 addition & 0 deletions packages/database-ui/src/database/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./database";
28 changes: 28 additions & 0 deletions packages/database-ui/src/database/view-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react";

import { HintProvider, ModalProvider } from "@swy/ui/shared";

import { paddingX } from "./constant";

export const ViewWrapper: React.FC<React.PropsWithChildren> = ({
children,
}) => {
return (
<HintProvider delayDuration={500}>
<ModalProvider>
<div
// contentEditable={false}
data-content-editable-void
className="max-h-inherit relative flex w-screen shrink-0 grow flex-col"
style={{ left: `-${paddingX}px` }}
>
<div className="relative">
<div className="z-10 mb-0 mr-0 h-full shrink-0 grow overflow-x-auto overflow-y-hidden">
{children}
</div>
</div>
</div>
</ModalProvider>
</HintProvider>
);
};
15 changes: 15 additions & 0 deletions packages/database-ui/src/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Examples Usage

1. Popover with Triggers

```tsx
<PopoverDemo />
```

2. Popover with Modals

```tsx
<ModalProvider>
<PopoverDemo2 />
</ModalProvider>
```
69 changes: 69 additions & 0 deletions packages/database-ui/src/examples/cell-action-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"use client";

import React, { useRef } from "react";

import { Input, Popover, PopoverContent } from "@swy/ui/shadcn";
import { useModal } from "@swy/ui/shared";

import { CellType } from "../table-view";

import "./view.css";

type CellActionPopoverProps = CellType & {
position: {
top: number;
left: number;
};
};

export const CellActionPopover: React.FC<CellActionPopoverProps> = ({
position,
...props
}) => {
const { isOpen, setClose } = useModal();
const containerRef = useRef<HTMLDivElement>(null);

return (
<Popover open={isOpen} onOpenChange={setClose} modal>
{/* TODO this is a workaround solution */}
{/* See https://github.com/radix-ui/primitives/issues/2908 */}
<div
id="popover-popper-container"
ref={containerRef}
className="fixed radix-popper-wrapper:!relative radix-popper-wrapper:!transform-none"
style={{ ...position }}
>
{renderContent({ containerRef, ...props })}
</div>
</Popover>
);
};

type RenderContentProps = CellType & {
containerRef: React.RefObject<HTMLDivElement>;
};

function renderContent({ containerRef, ...data }: RenderContentProps) {
switch (data.type) {
case "title":
case "text":
return (
<PopoverContent
container={containerRef.current}
onClick={(e) => e.stopPropagation()}
className="flex max-h-[773px] min-h-[34px] w-[240px] flex-col overflow-visible backdrop-filter-none"
>
<Input
spellCheck
value={data.value}
className="word-break max-h-[771px] min-h-8 whitespace-pre-wrap border-none bg-transparent caret-primary"
/>
{/* <div className="flex flex-col overflow-y-auto grow h-full px-2 py-1.5 min-h-[34px] justify-between text-sm font-medium">
<div spellCheck contentEditable data-content-editable-leaf className="w-full max-w-full whitespace-pre-wrap word-break caret-primary">{value}</div>
</div> */}
</PopoverContent>
);
default:
return null;
}
}
48 changes: 48 additions & 0 deletions packages/database-ui/src/examples/popover-with-modals.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from "react";

import { Button } from "@swy/ui/shadcn";
import { useModal } from "@swy/ui/shared";

import "./view.css";

import { CellActionPopover } from "./cell-action-provider";

const randomName: Record<string, string> = {
"1": "alpha 1!!",
"2": "BRAVO",
"3": "chris for 3...",
};

export function PopoverDemo2() {
const { setOpen } = useModal();
const onClick = (e: React.MouseEvent<HTMLButtonElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
console.log("button position", e.currentTarget.title, rect);
setOpen(
<CellActionPopover
type="text"
value="Input..."
position={{ top: rect.top, left: rect.left }}
/>,
);
};
return (
<div className="flex items-center">
<div className="grid gap-4">
{Array.from("abcd").map((id) => (
<div key={id} className="flex gap-4">
{Array.from("123").map((id) => (
<Button
key={id}
onClick={onClick}
className="col-start-1 row-start-1"
>
Open {randomName[id]}
</Button>
))}
</div>
))}
</div>
</div>
);
}
Loading