This commit is contained in:
Jon Staab
2024-08-26 14:43:43 -07:00
parent 644c32dd09
commit 88318e9753
36 changed files with 370 additions and 311 deletions
+4 -4
View File
@@ -6,7 +6,7 @@
</style>
<script lang="ts">
import cx from 'classnames'
import cx from "classnames"
import {switcher} from "@welshman/lib"
import AddSquare from "@assets/icons/Add Square.svg?dataurl"
import Code2 from "@assets/icons/Code 2.svg?dataurl"
@@ -69,8 +69,8 @@
const data = switcher(icon, {
"add-square": AddSquare,
"code-2": Code2,
"earth": Earth,
"pen": Pen,
earth: Earth,
pen: Pen,
"headphones-round": HeadphonesRound,
"add-circle": AddCircle,
"alt-arrow-down": AltArrowDown,
@@ -105,7 +105,7 @@
"menu-dots": MenuDots,
"notes-minimalistic": NotesMinimalistic,
"pallete-2": Pallete2,
"paperclip": Paperclip,
paperclip: Paperclip,
plain: Plain,
reply: Reply,
"remote-controller-minimalistic": RemoteControllerMinimalistic,
@@ -69,7 +69,7 @@
on:dragleave|preventDefault|stopPropagation={onDragLeave}
on:drop|preventDefault|stopPropagation={onDrop}>
<div
class="absolute right-0 top-0 overflow-hidden rounded-full bg-primary h-5 w-5"
class="absolute right-0 top-0 h-5 w-5 overflow-hidden rounded-full bg-primary"
class:bg-error={file}
class:bg-primary={!file}>
{#if file}
+1 -1
View File
@@ -1,3 +1,3 @@
<div class="flex w-60 flex-col gap-1 bg-base-300 flex-shrink-0">
<div class="flex w-60 flex-shrink-0 flex-col gap-1 bg-base-300">
<slot />
</div>
+2 -2
View File
@@ -36,7 +36,7 @@
on:click
class={cx(
$$props.class,
"flex items-center gap-3 transition-all hover:bg-base-100 hover:text-base-content text-left",
"flex items-center gap-3 text-left transition-all hover:bg-base-100 hover:text-base-content",
)}
class:text-base-content={active}
class:bg-base-100={active}>
@@ -48,7 +48,7 @@
on:click
class={cx(
$$props.class,
"flex w-full items-center gap-3 transition-all hover:bg-base-100 hover:text-base-content text-left",
"flex w-full items-center gap-3 text-left transition-all hover:bg-base-100 hover:text-base-content",
)}
class:text-base-content={active}
class:bg-base-100={active}>
+18 -17
View File
@@ -1,41 +1,42 @@
import { Node, nodePasteRule, type PasteRuleMatch } from '@tiptap/core'
import type { Node as ProsemirrorNode } from '@tiptap/pm/model'
import type { MarkdownSerializerState } from 'prosemirror-markdown'
import {Node, nodePasteRule, type PasteRuleMatch} from "@tiptap/core"
import type {Node as ProsemirrorNode} from "@tiptap/pm/model"
import type {MarkdownSerializerState} from "prosemirror-markdown"
export const LINK_REGEX = /^([a-z\+:]{2,30}:\/\/)?[^<>\(\)\s]+\.[a-z]{2,6}[^\s]*[^<>"'\.!?,:\s\)\(]*/gi
export const LINK_REGEX =
/^([a-z\+:]{2,30}:\/\/)?[^<>\(\)\s]+\.[a-z]{2,6}[^\s]*[^<>"'\.!?,:\s\)\(]*/gi
export const createPasteRuleMatch = <T extends Record<string, unknown>>(
match: RegExpMatchArray,
data: T,
): PasteRuleMatch => ({ index: match.index!, replaceWith: match[2], text: match[0], match, data })
): PasteRuleMatch => ({index: match.index!, replaceWith: match[2], text: match[0], match, data})
export interface LinkAttributes {
url: string
}
declare module '@tiptap/core' {
declare module "@tiptap/core" {
interface Commands<ReturnType> {
link: {
insertLink: (options: { url: string }) => ReturnType
insertLink: (options: {url: string}) => ReturnType
}
}
}
export const LinkExtension = Node.create({
atom: true,
name: 'link',
group: 'inline',
name: "link",
group: "inline",
inline: true,
selectable: true,
draggable: true,
priority: 1000,
addAttributes() {
return {
url: { default: null },
url: {default: null},
}
},
renderHTML(props) {
return ['div', { 'data-url': props.node.attrs.url }]
return ["div", {"data-url": props.node.attrs.url}]
},
renderText(props) {
return props.node.attrs.url
@@ -53,10 +54,10 @@ export const LinkExtension = Node.create({
addCommands() {
return {
insertLink:
({ url }) =>
({ commands }) => {
({url}) =>
({commands}) => {
return commands.insertContent(
{ type: this.name, attrs: { url } },
{type: this.name, attrs: {url}},
{
updateSelection: false,
},
@@ -68,13 +69,13 @@ export const LinkExtension = Node.create({
return [
nodePasteRule({
type: this.type,
getAttributes: (match) => match.data,
find: (text) => {
getAttributes: match => match.data,
find: text => {
const matches = []
for (const match of text.matchAll(LINK_REGEX)) {
try {
matches.push(createPasteRuleMatch(match, { url: match[0] }))
matches.push(createPasteRuleMatch(match, {url: match[0]}))
} catch (e) {
continue
}
+15 -16
View File
@@ -1,19 +1,18 @@
import type {SvelteComponent, ComponentType} from 'svelte'
import type {Readable} from 'svelte/store'
import tippy, {type Instance} from 'tippy.js'
import {mergeAttributes, Node} from '@tiptap/core'
import type {Editor} from '@tiptap/core'
import {PluginKey} from '@tiptap/pm/state'
import Suggestion from '@tiptap/suggestion'
import type {Search} from '@lib/util'
import type {SvelteComponent, ComponentType} from "svelte"
import type {Readable} from "svelte/store"
import tippy, {type Instance} from "tippy.js"
import type {Editor} from "@tiptap/core"
import {PluginKey} from "@tiptap/pm/state"
import Suggestion from "@tiptap/suggestion"
import type {Search} from "@lib/util"
export type SuggestionsOptions = {
char: string,
name: string,
editor: Editor,
char: string
name: string
editor: Editor
search: Readable<Search<any, any>>
select: (value: any, props: any) => void
allowCreate?: boolean,
allowCreate?: boolean
suggestionComponent: ComponentType
suggestionsComponent: ComponentType
}
@@ -27,7 +26,7 @@ export const createSuggestions = (options: SuggestionsOptions) =>
// increase range.to by one when the next node is of type "text"
// and starts with a space character
const nodeAfter = editor.view.state.selection.$to.nodeAfter
const overrideSpace = nodeAfter?.text?.startsWith(' ')
const overrideSpace = nodeAfter?.text?.startsWith(" ")
if (overrideSpace) {
range.to += 1
@@ -38,13 +37,13 @@ export const createSuggestions = (options: SuggestionsOptions) =>
.focus()
.insertContentAt(range, [
{type: options.name, attrs: props},
{type: 'text', text: ' '},
{type: "text", text: " "},
])
.run()
window.getSelection()?.collapseToEnd()
},
allow: ({ state, range }) => {
allow: ({state, range}) => {
const $from = state.doc.resolve(range.from)
const type = state.schema.nodes[options.name]
@@ -67,7 +66,7 @@ export const createSuggestions = (options: SuggestionsOptions) =>
onStart: props => {
target = document.createElement("div")
popover = tippy('body', {
popover = tippy("body", {
getReferenceClientRect: props.clientRect as any,
appendTo: document.body,
content: target,
+15 -15
View File
@@ -1,7 +1,7 @@
import {Node, nodePasteRule} from '@tiptap/core'
import type {Node as ProsemirrorNode} from '@tiptap/pm/model'
import type {MarkdownSerializerState} from 'prosemirror-markdown'
import {createPasteRuleMatch} from '@lib/tiptap/util'
import {Node, nodePasteRule} from "@tiptap/core"
import type {Node as ProsemirrorNode} from "@tiptap/pm/model"
import type {MarkdownSerializerState} from "prosemirror-markdown"
import {createPasteRuleMatch} from "@lib/tiptap/util"
export const TOPIC_REGEX = /(#[^\s]+)/g
@@ -9,25 +9,25 @@ export interface TopicAttributes {
name: string
}
declare module '@tiptap/core' {
declare module "@tiptap/core" {
interface Commands<ReturnType> {
topic: {
insertTopic: (options: { name: string }) => ReturnType
insertTopic: (options: {name: string}) => ReturnType
}
}
}
export const TopicExtension = Node.create({
atom: true,
name: 'topic',
group: 'inline',
name: "topic",
group: "inline",
inline: true,
selectable: true,
draggable: true,
priority: 1000,
addAttributes() {
return {
name: { default: null },
name: {default: null},
}
},
renderText(props) {
@@ -46,10 +46,10 @@ export const TopicExtension = Node.create({
addCommands() {
return {
insertTopic:
({ name }) =>
({ commands }) => {
({name}) =>
({commands}) => {
return commands.insertContent(
{ type: this.name, attrs: { name } },
{type: this.name, attrs: {name}},
{
updateSelection: false,
},
@@ -61,13 +61,13 @@ export const TopicExtension = Node.create({
return [
nodePasteRule({
type: this.type,
getAttributes: (match) => match.data,
find: (text) => {
getAttributes: match => match.data,
find: text => {
const matches = []
for (const match of text.matchAll(TOPIC_REGEX)) {
try {
matches.push(createPasteRuleMatch(match, { name: match[0] }))
matches.push(createPasteRuleMatch(match, {name: match[0]}))
} catch (e) {
continue
}
+4 -4
View File
@@ -1,4 +1,4 @@
export * from '@lib/tiptap/util'
export {createSuggestions} from '@lib/tiptap/Suggestions'
export {TopicExtension} from '@lib/tiptap/TopicExtension'
export {LinkExtension} from '@lib/tiptap/LinkExtension'
export * from "@lib/tiptap/util"
export {createSuggestions} from "@lib/tiptap/Suggestions"
export {TopicExtension} from "@lib/tiptap/TopicExtension"
export {LinkExtension} from "@lib/tiptap/LinkExtension"
+2 -2
View File
@@ -1,9 +1,9 @@
import type {JSONContent, PasteRuleMatch} from '@tiptap/core'
import type {JSONContent, PasteRuleMatch} from "@tiptap/core"
export const createPasteRuleMatch = <T extends Record<string, unknown>>(
match: RegExpMatchArray,
data: T,
): PasteRuleMatch => ({ index: match.index!, replaceWith: match[2], text: match[0], match, data })
): PasteRuleMatch => ({index: match.index!, replaceWith: match[2], text: match[0], match, data})
export const findNodes = (type: string, json: JSONContent) => {
const results: JSONContent[] = []
+1 -1
View File
@@ -1,7 +1,7 @@
import type {FlyParams} from "svelte/transition"
import {fly as baseFly} from "svelte/transition"
export {fade} from 'svelte/transition'
export {fade} from "svelte/transition"
export const fly = (node: Element, params?: FlyParams | undefined) =>
baseFly(node, {y: 20, ...params})
-1
View File
@@ -33,7 +33,6 @@ export const synced = <T>(key: string, defaultValue: T, delay = 300) => {
}
export type SearchOptions<V, T> = {
getValue: (item: T) => V
fuseOptions?: IFuseOptions<T>
sortFn?: (items: FuseResult<T>) => any