Skip to content

Commit

Permalink
feat: Explorer panel (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
areknawo committed Nov 2, 2023
1 parent d787165 commit 86014ab
Show file tree
Hide file tree
Showing 18 changed files with 239 additions and 58 deletions.
2 changes: 2 additions & 0 deletions apps/web/src/components/fragments/mini-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Paragraph,
Text,
Bold,
Underline,
Code,
Italic,
Blockquote,
Expand Down Expand Up @@ -68,6 +69,7 @@ const getExtensions = (options: ExtensionOptions): Extensions => {
if (options.inline) {
extensions.push(
Bold,
Underline,
Code,
Italic,
Strike,
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/lib/editor/editing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Heading,
Link,
Bold,
Underline,
Code,
Italic,
HorizontalRule,
Expand Down Expand Up @@ -99,6 +100,7 @@ const createExtensions = (
};
const marks: Record<App.WorkspaceSettings["marks"][number], MarkExtension> = {
bold: Bold,
underline: Underline,
italic: Italic,
strike: Strike,
code: Code,
Expand Down
3 changes: 3 additions & 0 deletions apps/web/src/styles/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ kbd {
@apply border border-primary;
}
}
:where(u) {
text-decoration: underline wavy;
}
}

.form-checkbox {
Expand Down
10 changes: 8 additions & 2 deletions apps/web/src/views/editor/menus/bubble/format.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from "clsx";
import { Component, For, createEffect, createSignal } from "solid-js";
import { Component, For, createSignal } from "solid-js";
import { SolidEditor } from "@vrite/tiptap-solid";
import {
mdiFormatBold,
Expand All @@ -11,7 +11,8 @@ import {
mdiFormatSubscript,
mdiFormatSuperscript,
mdiKeyboardCloseOutline,
mdiCommentOutline
mdiCommentOutline,
mdiFormatUnderlineWavy
} from "@mdi/js";
import { nanoid } from "nanoid";
import { Card, IconButton, Tooltip } from "#components/primitives";
Expand Down Expand Up @@ -77,6 +78,11 @@ const FormatMenu: Component<{
mark: "strike",
label: "Strike"
},
{
icon: mdiFormatUnderlineWavy,
mark: "underline",
label: "Underline"
},
{
icon: mdiCodeTags,
mark: "code",
Expand Down
187 changes: 156 additions & 31 deletions apps/web/src/views/explorer/content-group-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
import { createRef } from "#lib/utils";

interface ContentGroupRowProps {
contentGroup?: App.ContentGroup | null;
contentGroup: App.ContentGroup;
customLabel?: string;
menuDisabled?: boolean;
draggable?: boolean;
Expand All @@ -35,6 +35,7 @@ interface ContentGroupRowProps {
removeContentGroup(id: string): void;
removeContentPiece(id: string): void;
onClick?(): void;
onExpand?(forceOpen?: boolean): void;
}

declare module "#context" {
Expand All @@ -49,12 +50,94 @@ const ContentGroupRow: Component<ContentGroupRowProps> = (props) => {
const { notify } = useNotifications();
const { confirmDelete } = useConfirmationModal();
const [containerRef, setContainerRef] = createRef<HTMLDivElement | null>(null);
const [showGhost, setShowGhost] = createRef(() => {});
const [activeDraggableGroup, setActiveDraggableGroup] = createSharedSignal(
"activeDraggableGroup",
null
);
const [dropdownOpened, setDropdownOpened] = createSignal(false);
const [highlight, setHighlight] = createSignal(false);
const menuOptions = createMemo(() => {
const menuOptions: Array<{
icon: string;
label: string;
class?: string;
color?: "danger" | "success";
onClick(): void;
}> = [
{
icon: mdiIdentifier,
label: "Copy ID",
async onClick() {
await window.navigator.clipboard.writeText(props.contentGroup.id);
setDropdownOpened(false);
notify({
text: "Content group ID copied to the clipboard",
type: "success"
});
}
}
];

if (hasPermission("manageDashboard")) {
menuOptions.push({
icon: props.contentGroup.locked ? mdiFileLockOpen : mdiFileLock,
label: props.contentGroup.locked ? "Unlock" : "Lock",
async onClick() {
await client.contentGroups.update.mutate({
id: props.contentGroup.id,
locked: !props.contentGroup.locked
});
setContentPieces(
contentPieces().map((contentPiece) => {
return {
...contentPiece,
locked: !props.contentGroup.locked
};
})
);
setDropdownOpened(false);
}
});
}

if (!props.contentGroup.locked && hasPermission("manageDashboard")) {
menuOptions.push({
icon: mdiTrashCan,
label: "Delete",
class: "justify-start",
color: "danger",
onClick() {
setDropdownOpened(false);
confirmDelete({
header: "Delete group",
content: (
<p>
Do you really want to delete this content group? This will also delete all pieces
related to this group.
</p>
),
async onConfirm() {
try {
await client.contentGroups.delete.mutate({ id: props.contentGroup.id });
setStorage((storage) => ({
...storage,
...(contentPieces().find((contentPiece) => {
return contentPiece.contentGroupId === props.contentGroup.id;
}) && { contentPieceId: undefined })
}));
notify({ text: "Content group deleted", type: "success" });
} catch (error) {
notify({ text: "Couldn't delete the content group", type: "success" });
}
}
});
}
});
}

return menuOptions;
});

window.addEventListener("touchmove", (event) => {
if (activeDraggableGroup()) {
Expand All @@ -63,7 +146,7 @@ const ContentGroupRow: Component<ContentGroupRowProps> = (props) => {
const elementAtTouchPoint = document.elementFromPoint(x, y);

if (
props.contentGroup?.id !== activeDraggableGroup()?.id &&
props.contentGroup.id !== activeDraggableGroup()?.id &&
(elementAtTouchPoint === containerRef() || containerRef()?.contains(elementAtTouchPoint))
) {
setHighlight(true);
Expand All @@ -75,7 +158,7 @@ const ContentGroupRow: Component<ContentGroupRowProps> = (props) => {

return (
<div
class="flex flex-1 justify-center items-center cursor-pointer overflow-x-hidden"
class="flex flex-1 justify-center items-center cursor-pointer overflow-x-hidden group ml-1"
ref={(el) => {
SortableLib.create(el, {
group: {
Expand All @@ -90,11 +173,6 @@ const ContentGroupRow: Component<ContentGroupRowProps> = (props) => {
delayOnTouchOnly: true,
delay: 500,
disabled: !hasPermission("manageDashboard"),
/* ghostClass: "!hidden",
dragClass: "!block", */
/* ghostClass: "!hidden",
chosenClass: "!hidden",
selectedClass: "!hidden", */
revertOnSpill: true,
draggable: ".draggable",
fallbackOnBody: true,
Expand All @@ -104,6 +182,9 @@ const ContentGroupRow: Component<ContentGroupRowProps> = (props) => {

if (ghost) {
ghost.classList.add("!hidden");
setShowGhost(() => {
ghost.classList.remove("!hidden");
});
}
});
},
Expand Down Expand Up @@ -136,20 +217,18 @@ const ContentGroupRow: Component<ContentGroupRowProps> = (props) => {
setActiveDraggableGroup(props.contentGroup);
},
onEnd() {
showGhost()();
setActiveDraggableGroup(null);
}
});
setContainerRef(el);
}}
>
<button
<div
class={clsx(
"flex flex-1 justify-center items-center overflow-hidden rounded-lg cursor-pointer p-1",
"flex flex-1 justify-start items-center overflow-hidden rounded-lg cursor-pointer h-7",
props.draggable !== false && "draggable"
)}
onClick={() => {
props.onClick?.();
}}
data-content-group-id={props.contentGroup?.id || ""}
onDragOver={(event) => event.preventDefault()}
onDragEnter={(event) => {
Expand Down Expand Up @@ -179,27 +258,73 @@ const ContentGroupRow: Component<ContentGroupRowProps> = (props) => {
}
}}
>
<Icon
class={clsx("h-5 w-5 transform transition", props.opened && "rotate-90")}
<IconButton
class={clsx("transform transition m-0 p-0.25", props.opened && "rotate-90")}
path={mdiChevronRight}
variant="text"
onClick={() => {
props.onExpand?.();
}}
/>
<Icon
class={clsx(
"h-5 w-5 mr-1 text-gray-500 dark:text-gray-400",
(highlight() || (props.active && !highlight())) && "fill-[url(#gradient)]"
)}
path={props.opened ? mdiFolderOpen : mdiFolder}
/>
<span
class={clsx(
"!text-base inline-flex text-start flex-1 overflow-x-auto content-group-name scrollbar-hidden select-none",
(highlight() || (props.active && !highlight())) &&
"text-transparent bg-clip-text bg-gradient-to-tr"
)}
<button
class="flex flex-1"
onClick={() => {
props.onExpand?.(true);
props.onClick?.();
}}
>
{props.customLabel || props.contentGroup?.name || ""}
</span>
</button>
<Icon
class={clsx(
"h-6 w-6 mr-1 text-gray-500 dark:text-gray-400",
(highlight() || (props.active && !activeDraggableGroup())) && "fill-[url(#gradient)]"
)}
path={props.opened ? mdiFolderOpen : mdiFolder}
/>
<span
class={clsx(
"!text-base inline-flex text-start flex-1 overflow-x-auto content-group-name scrollbar-hidden select-none",
(highlight() || (props.active && !activeDraggableGroup())) &&
"text-transparent bg-clip-text bg-gradient-to-tr"
)}
>
{props.customLabel || props.contentGroup?.name || ""}
</span>
</button>
<div class="hidden group-hover:flex">
<Dropdown
placement="bottom-end"
opened={dropdownOpened()}
fixed
class="ml-1 mr-3"
setOpened={setDropdownOpened}
activatorButton={() => (
<IconButton path={mdiDotsVertical} class="m-0 p-0.25" text="soft" variant="text" />
)}
>
<div class="w-full gap-1 flex flex-col">
<For each={menuOptions()}>
{(item) => {
return (
<IconButton
path={item.icon}
label={item.label}
variant="text"
text="soft"
color={item.color}
class={clsx("justify-start whitespace-nowrap w-full m-0", item.class)}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
item.onClick();
}}
/>
);
}}
</For>
</div>
</Dropdown>
</div>
</div>
</div>
);
};
Expand Down
6 changes: 2 additions & 4 deletions apps/web/src/views/explorer/content-piece-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const ContentPieceRow: Component<ContentPieceRowProps> = (props) => {
>
<Card
color="contrast"
class="m-0 border-0 rounded-none justify-start items-center @hover:bg-gray-200 dark:@hover:bg-gray-700 @hover:cursor-pointer p-1 flex !bg-transparent"
class="m-0 border-0 rounded-none justify-start items-center @hover:bg-gray-200 dark:@hover:bg-gray-700 @hover:cursor-pointer flex !bg-transparent p-0"
>
<div
class="flex flex-1 justify-center items-center cursor-pointer overflow-hidden rounded-lg"
Expand Down Expand Up @@ -69,10 +69,8 @@ const ContentPieceRow: Component<ContentPieceRowProps> = (props) => {
>
<IconButton
path={mdiFileDocumentOutline}
class="m-0 ml-5 mr-1 p-0"
iconProps={{ class: "h-5 w-5" }}
class="m-0 ml-5 mr-1"
variant="text"
size="small"
text="soft"
hover={false}
badge
Expand Down
Loading

0 comments on commit 86014ab

Please sign in to comment.