Skip to content
Merged
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
2 changes: 1 addition & 1 deletion packages/ui/src/components/landing-footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ModeToggle } from './theme-mode-toggle';
export default function LandingFooter() {
return (
<footer className="border-t">
<div className="mx-auto flex max-w-6xl flex-col items-center justify-between gap-4 px-6 py-6 md:flex-row">
<div className="mx-auto flex max-w-6xl flex-col items-center justify-between gap-4 p-6 md:flex-row">
<div>
<div className="space-y-1">
<h4 className="text-sm font-semibold leading-none">Notopia</h4>
Expand Down
12 changes: 6 additions & 6 deletions packages/ui/src/components/landing-hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ export default function LandingHero() {
<div className="flex w-full max-w-6xl flex-col items-center gap-12 lg:flex-row lg:items-center">
<div className="flex flex-1 flex-col justify-center gap-6">
<div className="flex flex-col gap-3">
<h1 className="text-foreground text-4xl leading-tight font-semibold tracking-tight sm:text-5xl lg:text-[52px]">
<h1 className="text-foreground text-4xl/tight font-semibold tracking-tight sm:text-5xl lg:text-[52px]">
Connect every idea
</h1>
<p className="text-muted-foreground max-w-md text-base leading-relaxed">
<p className="text-muted-foreground max-w-md text-base/relaxed ">
Turn scattered notes into a shared universe. Visualize your team&apos;s knowledge
graph and collaborate in real-time with Notopia.
</p>
</div>

<div className="border-input bg-background flex w-full max-w-sm items-center gap-2 rounded-full border px-4 py-3 shadow-sm">
<CircleDashed className="text-muted-foreground h-5 w-5 shrink-0" />
<CircleDashed className="text-muted-foreground size-5 shrink-0" />
<Input
placeholder="Contact us"
className="text-foreground placeholder:text-muted-foreground h-auto border-0 bg-transparent p-0 text-sm shadow-none focus-visible:ring-0"
/>
<Inbox className="text-muted-foreground h-5 w-5 shrink-0" />
<Inbox className="text-muted-foreground size-5 shrink-0" />
</div>

<div className="flex items-center gap-3">
Expand All @@ -48,10 +48,10 @@ export default function LandingHero() {
</div>
</div>

<div className="from-muted to-muted/40 flex flex-1 flex-col items-center justify-center gap-6 rounded-2xl bg-gradient-to-br p-10">
<div className="from-muted to-muted/40 flex flex-1 flex-col items-center justify-center gap-6 rounded-2xl bg-linear-to-br p-10">
<div className="flex flex-col gap-3 text-center">
<h2 className="text-foreground text-2xl font-semibold">Visualize Your Knowledge</h2>
<p className="text-muted-foreground text-sm leading-relaxed">
<p className="text-muted-foreground text-sm/relaxed ">
Comment on lines 23 to +54
Notopia transforms the way teams organize, visualize, and collaborate on shared
information. Create powerful knowledge graphs and unlock new insights.
</p>
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/landing-navigation-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function LandingNavigationBar() {

<div className="flex shrink-0 items-center gap-2">
<Button variant="outline" size="icon" className="rounded-lg" aria-label="GitHub">
<Icons.Github className="h-4 w-4" />
<Icons.Github className="size-4 " />
</Button>
</div>
</div>
Expand Down
99 changes: 60 additions & 39 deletions packages/ui/src/components/tree-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuTrigger,
} from '@notopia-uit/ui/components/shadcn/context-menu';
import { Input } from '@notopia-uit/ui/components/shadcn/input';
Expand Down Expand Up @@ -241,6 +242,12 @@ const TreeView: React.FC<{ currentWorkspaceId: string }> = ({ currentWorkspaceId
queryClient.invalidateQueries({
queryKey: getNoteOptions({ path: { noteId: variables.path.noteId } }).queryKey,
});
//TODO: ideally we should only update the specific item in the tree instead of refetching the whole tree, but since we don't have an API to get a single item, we have to invalidate the whole tree for now
queryClient.invalidateQueries({
queryKey: getWorkspaceTreeOptions({
path: { workspaceId: currentWorkspaceId },
}).queryKey,
});
},
onError: (error) => {
showAlert({
Expand Down Expand Up @@ -329,22 +336,20 @@ const TreeView: React.FC<{ currentWorkspaceId: string }> = ({ currentWorkspaceId
}, [workspaceTreeData]);

const dataProvider = useMemo(() => new TreeDataProvider<string>(items), [items]);
const getTargetParentId = useCallback(() => {
const focusedId = viewState['tree-sample']?.focusedItem;
let parentId: TreeItemIndex = rootId;
const getTargetParentId = useCallback(
(targetId: TreeItemIndex) => {
const target = items[targetId];
if (!target) return rootId;

if (focusedId && items[focusedId]) {
if (items[focusedId].isFolder) {
parentId = focusedId;
} else {
const parent = Object.values(items).find(
(p) => p.isFolder && p.children?.includes(focusedId)
);
if (parent) parentId = parent.index;
if (target.isFolder) {
return targetId;
}
}
return parentId;
}, [viewState, items, rootId]);

const parent = Object.values(items).find((p) => p.isFolder && p.children?.includes(targetId));
return parent ? parent.index : rootId;
},
[items, rootId]
);

const { mutate: moveWorkspaceItems } = useMoveWorkspaceItemsMutation({
onError: (error) => {
Expand Down Expand Up @@ -498,10 +503,21 @@ const TreeView: React.FC<{ currentWorkspaceId: string }> = ({ currentWorkspaceId
);

const handleCreateItem = useCallback(
(isFolder: boolean) => {
const parentId = getTargetParentId();
(targetId: TreeItemIndex, isFolder: boolean) => {
const parentId = getTargetParentId(targetId);
const defaultName = isFolder ? 'New Folder' : 'New Note';

setViewState((prevViewState) => ({
...prevViewState,
'tree-sample': {
...prevViewState['tree-sample'],
expandedItems: [
...(prevViewState['tree-sample']?.expandedItems ?? []).filter((id) => id !== parentId),
parentId,
],
},
}));

if (isFolder) {
createFolder({
body: {
Expand Down Expand Up @@ -602,29 +618,6 @@ const TreeView: React.FC<{ currentWorkspaceId: string }> = ({ currentWorkspaceId
/>
<Button type="submit">Search</Button>
</form>

<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
size-3="true"
className="h-8 flex-1 text-xs" // flex-1 makes them share the space equally
onClick={() => handleCreateItem(false)}
>
<FilePlus className="mr-1.5 size-3" />
New Note
</Button>
<Button
variant="outline"
size="sm"
size-3="true"
className="h-8 flex-1 text-xs"
onClick={() => handleCreateItem(true)}
>
<FolderPlus className="mr-1.5 size-3" />
New Folder
</Button>
</div>
</div>
<div>
<ControlledTreeEnvironment<string>
Expand Down Expand Up @@ -686,6 +679,7 @@ const TreeView: React.FC<{ currentWorkspaceId: string }> = ({ currentWorkspaceId
focusedItem: item.index,
},
}));
tree.current?.focusTree();
}}
onSelectItems={(selectedItems, treeId) => {
const selectedId = selectedItems.at(-1) ?? '';
Expand All @@ -710,6 +704,24 @@ const TreeView: React.FC<{ currentWorkspaceId: string }> = ({ currentWorkspaceId
}}
renderItem={({ title, item, arrow, context, depth, children }) => {
const indentation = 10 * depth;
if (context.isRenaming) {
return (
<li {...context.itemContainerWithChildrenProps} className="my-px">
<div
{...context.itemContainerWithoutChildrenProps}
{...context.interactiveElementProps}
className="grid h-6 w-full grid-flow-col items-center justify-start gap-0.5 text-xs"
style={{
paddingLeft: `${item.isFolder ? indentation : indentation + 16}px`,
}}
>
{item.isFolder && arrow}
{title}
</div>
{children}
</li>
);
}
return (
<li
{...context.itemContainerWithChildrenProps}
Expand Down Expand Up @@ -746,6 +758,15 @@ const TreeView: React.FC<{ currentWorkspaceId: string }> = ({ currentWorkspaceId
</Button>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem onClick={() => handleCreateItem(item.index, false)}>
<FilePlus className="mr-2 size-4" />
New Note
</ContextMenuItem>
<ContextMenuItem onClick={() => handleCreateItem(item.index, true)}>
<FolderPlus className="mr-2 size-4" />
New Folder
</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem
variant="destructive"
onClick={() => handleTrashItem(item.index)}
Expand Down
Loading