Skip to content

Commit

Permalink
Merge pull request #939 from gofractally/bf/chainmail-maintenance
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonfancher authored Dec 5, 2024
2 parents c12bd9b + db3149c commit e7a69d5
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 294 deletions.
128 changes: 67 additions & 61 deletions services/user/Chainmail/ui/src/components/compose-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,72 +169,78 @@ export const ComposeDialog = ({
>
{trigger}
<DialogContent
className="flex h-[90dvh] max-w-screen-2xl flex-col"
className="flex h-[90dvh] max-w-screen-lg flex-col"
onCloseAutoFocus={(e) => {
// This helps in not focusing on the trigger after closing the modal
e.preventDefault();
}}
>
<DialogHeader>
<DialogTitle>Compose message</DialogTitle>
<DialogDescription>
Send a message to another account on the network
</DialogDescription>
</DialogHeader>
<Separator />
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex h-[80dvh] flex-1 flex-grow flex-col space-y-2"
>
<FormField
control={form.control}
name="to"
render={({ field }) => (
<FormItem>
<FormControl>
<Input placeholder="To" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="subject"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
placeholder="Subject"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<MilkdownProvider>
<ProsemirrorAdapterProvider>
<div className="sticky top-0 z-10">
<ControlBar />
<Separator />
</div>
<MarkdownEditor
initialValue={
message?.status === "draft"
? message.body
: ""
}
updateMarkdown={updateDraft}
/>
</ProsemirrorAdapterProvider>
</MilkdownProvider>
<DialogFooter>
<Button type="submit">Send</Button>
</DialogFooter>
</form>
</Form>
<div className="flex max-h-full flex-1 flex-col">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex max-h-full flex-1 flex-grow flex-col space-y-2"
>
<DialogHeader>
<DialogTitle>Compose message</DialogTitle>
<DialogDescription>
Send a message to another account on the
network
</DialogDescription>
</DialogHeader>
<Separator />
<FormField
control={form.control}
name="to"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
placeholder="To"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="subject"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
placeholder="Subject"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<MilkdownProvider>
<ProsemirrorAdapterProvider>
<div className="sticky top-0 z-10">
<ControlBar />
<Separator />
</div>
<MarkdownEditor
initialValue={
message?.status === "draft"
? message.body
: ""
}
updateMarkdown={updateDraft}
/>
</ProsemirrorAdapterProvider>
</MilkdownProvider>
<DialogFooter>
<Button type="submit">Send</Button>
</DialogFooter>
</form>
</Form>
</div>
</DialogContent>
</Dialog>
);
Expand Down
182 changes: 55 additions & 127 deletions services/user/Chainmail/ui/src/components/editor/link-widget.tsx
Original file line number Diff line number Diff line change
@@ -1,136 +1,64 @@
import { commandsCtx } from "@milkdown/core";
import { updateLinkCommand } from "@milkdown/preset-commonmark";
import { Plugin } from "@milkdown/prose/state";
import { DecorationSet } from "@milkdown/prose/view";
import { useInstance } from "@milkdown/react";
import { $prose } from "@milkdown/utils";
import type { useWidgetViewFactory } from "@prosemirror-adapter/react";
import { useWidgetViewContext } from "@prosemirror-adapter/react";
import type { Ctx } from "@milkdown/ctx";
import type { EditorView } from "@milkdown/prose/view";
import type { EditorState } from "@milkdown/prose/state";

export const LinkWidgetBefore = () => {
return <>[</>;
};
import { editorViewCtx } from "@milkdown/core";
import { linkSchema } from "@milkdown/preset-commonmark";
import {
configureLinkTooltip,
linkTooltipAPI,
linkTooltipState,
} from "@milkdown/components/link-tooltip";
import { TooltipProvider, tooltipFactory } from "@milkdown/plugin-tooltip";

export const LinkWidgetAfter = () => {
const { spec } = useWidgetViewContext();
const [loading, editor] = useInstance();
const href = spec?.href ?? "";
const title = spec?.title ?? "";
import "../../styles/link-tooltip.css";

return (
<>
]
<span>
(
{
<>
<small className="text-nord8 font-light">link: </small>
<input
size={href.length}
placeholder="empty"
onBlur={(e) => {
if (loading) return;
editor().action((ctx) => {
const commands = ctx.get(commandsCtx);
commands.call(updateLinkCommand.key, {
href: e.target.value,
});
});
}}
className="rounded border-none bg-gray-50 px-2 py-0 ring-1 dark:bg-gray-900"
type="text"
defaultValue={href}
/>
&nbsp;
<small className="text-nord8 font-light">title: </small>
&quot;
<input
size={title.length || 5}
placeholder="empty"
onBlur={(e) => {
if (loading) return;
editor().action((ctx) => {
const commands = ctx.get(commandsCtx);
commands.call(updateLinkCommand.key, {
title: e.target.value,
});
});
}}
className="rounded border-none bg-gray-50 px-2 py-0 ring-1 dark:bg-gray-900"
type="text"
defaultValue={title}
/>
&quot;
</>
}
)
</span>
</>
);
};
export { linkTooltipPlugin } from "@milkdown/components/link-tooltip";

export const linkPlugin = (
widgetViewFactory: ReturnType<typeof useWidgetViewFactory>,
) => {
const before = widgetViewFactory({
as: "span",
component: LinkWidgetBefore,
});
const after = widgetViewFactory({ as: "span", component: LinkWidgetAfter });

return $prose(
() =>
new Plugin({
state: {
init() {
return DecorationSet.empty;
},
apply(tr) {
const { selection } = tr;
export const insertLinkTooltip = tooltipFactory("CREATE_LINK");

const { $from, $to } = selection;
const node = tr.doc.nodeAt(selection.from);
export function tooltipPluginView(ctx: Ctx) {
return (_view: EditorView) => {
const content = document.createElement("div");
const provider = new TooltipProvider({
content,
shouldShow: (view: EditorView) => {
const { selection, doc } = view.state;
const has = doc.rangeHasMark(
selection.from,
selection.to,
linkSchema.type(ctx),
);
if (has || selection.empty) return false;

const mark = node?.marks.find(
(mark) => mark.type.name === "link",
);
return true;
},
});

if (!mark) return DecorationSet.empty;
content.onmousedown = (e: MouseEvent) => {
e.preventDefault();
const view = ctx.get(editorViewCtx);
const { selection } = view.state;
ctx.get(linkTooltipAPI.key).addLink(selection.from, selection.to);
provider.hide();
};

let markPos = { start: -1, end: -1 };
tr.doc.nodesBetween(
$from.start(),
$to.end(),
(n, pos) => {
if (node === n) {
markPos = {
start: pos,
end:
pos +
Math.max(n.textContent.length, 1),
};
return {
update: (updatedView: EditorView, prevState: EditorState) => {
if (ctx.get(linkTooltipState.key).mode === "edit") return;
provider.update(updatedView, prevState);
},
destroy: () => {
provider.destroy();
content.remove();
},
};
};
}

// stop recursing if result is found
return false;
}
return undefined;
},
);

return DecorationSet.create(tr.doc, [
before(markPos.start),
after(markPos.end, {
href: mark.attrs.href,
title: mark.attrs.title,
}),
]);
},
},
props: {
decorations(state) {
return this.getState(state);
},
},
}),
);
};
export function linkTooltipConfig(ctx: Ctx) {
ctx.set(insertLinkTooltip.key, {
view: tooltipPluginView(ctx),
});
configureLinkTooltip(ctx);
}
Loading

0 comments on commit e7a69d5

Please sign in to comment.