diff --git a/flavours/classic/config/flavour_assets/components.css b/flavours/classic/config/flavour_assets/components.css index 1cd9eb4860..443a336fc5 100644 --- a/flavours/classic/config/flavour_assets/components.css +++ b/flavours/classic/config/flavour_assets/components.css @@ -1,3 +1,812 @@ /* This file was generated by the Surface compiler. */ + +/* Bonfire.Editor.Milkdown (jlrhi) */ + +.milkdown[s-jlrhi] { + width: 100%; +} + +.milkdown[s-jlrhi] img[s-jlrhi][title^=":"] { + height: 1em; + width: 1em; + margin: 0 1px 0 1.5px; + vertical-align: -1.5px; + display: inline; +} + +.milkdown[s-jlrhi] .emoji[s-jlrhi] { + height: 1em; + width: 1em; + margin: 0 1px 0 1.5px; + vertical-align: -1.5px; + display: inline; +} + +/* Bonfire.UI.Social.Activity.ActionsLive (sabiy) */ + + +/* Bonfire.UI.Social.Activity.MediaLive (bdjtg) */ + + +/* Bonfire.UI.Social.Activity.MoreActionsLive (ms2gq) */ + +div[s-ms2gq][data-id="more_menu"][data-rendered="widget"] { + @apply dropdown-top dropdown-end; +} + +/* Bonfire.UI.Social.Activity.NoteLive (sicz3) */ + +div[s-sicz3][data-rendered="widget"] { + @apply !mt-2; +} + +div[s-sicz3][data-rendered="smart_input"] { + @apply !my-0 !ml-0; +} + +div[s-sicz3][data-rendered="notifications"] { + @apply opacity-60; +} + +div[s-sicz3][data-rendered="thread"] { + @apply cursor-default; +} + +div[s-sicz3][data-id="object_body"][data-rendered="smart_input"] { + @apply !my-0 !text-sm !font-normal; +} + +div[s-sicz3][data-id="object_body"][data-main-object] { + @apply md:prose-base md:prose-p:my-0; +} + +/* Bonfire.UI.Social.Activity.SubjectLive (au77b) */ + +.mfm[s-au77b] { + display: inline-block; +} + +._mfm_tada_[s-au77b] { + font-size: 150%; + animation: mfm-tada 1s linear infinite both; +} + +._mfm_jelly_[s-au77b] { + animation: mfm-jelly 1s linear infinite both; +} + +._mfm_twitch_[s-au77b] { + animation: mfm-twitch 0.5s ease infinite; +} + +._mfm_shake_[s-au77b] { + animation: mfm-shake 0.5s ease infinite; +} + +._mfm_spin_[s-au77b] { + animation: mfm-spin 0.5s linear infinite; +} + +._mfm_spin_[s-au77b][data-x] { + animation-name: mfm-spinX; +} +._mfm_spin_[s-au77b][data-y] { + animation-name: mfm-spinY; +} +._mfm_spin_[s-au77b][left] { + animation-direction: reverse; +} +._mfm_spin_[s-au77b][alternate] { + animation-direction: alternate; +} + +._mfm_jump_[s-au77b] { + animation: mfm-jump 0.75s linear infinite; +} + +._mfm_bounce_[s-au77b] { + animation: mfm-bounce 0.75s linear infinite; + transform-origin: center bottom; +} + +._mfm_flip_[s-au77b][data-h][data-v] { + transform: scale(-1, -1); +} +._mfm_flip_[s-au77b][data-v] { + transform: scaleY(-1); +} +._mfm_flip_[s-au77b]:not([data-v]) { + transform: scaleX(-1); +} + +._mfm_x2_[s-au77b] { + font-size: 200%; +} + +._mfm_x3_[s-au77b] { + font-size: 400%; +} + +._mfm_x4_[s-au77b] { + font-size: 600%; +} + +._mfm_blur_[s-au77b] { + filter: blur(6px); + transition: filter 0.3s; +} +._mfm_blur_[s-au77b]:hover { + filter: blur(0px); +} + +._mfm_rainbow_[s-au77b] { + animation: mfm-rainbow 1s linear infinite; +} + +._mfm_rotate_[s-au77b] { + transform: rotate(90deg); + transform-origin: center center; +} + +/* sparkle */ + +@keyframes mfm-tada { + from[s-au77b] { + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 30%, + 50%, + 70%, + 90% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 40%, + 60%, + 80% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + to[s-au77b] { + transform: scale3d(1, 1, 1); + } +} + +@keyframes bounce { + 0% { + transform: scaleX(0.9) scaleY(0.9); + } + + 19% { + transform: scaleX(1.1) scaleY(1.1); + } + + 48% { + transform: scaleX(0.95) scaleY(0.95); + } + + 100% { + transform: scaleX(1) scaleY(1); + } +} + +@keyframes mfm-spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +@keyframes mfm-spinX { + 0% { + transform: perspective(128px) rotateX(0deg); + } + 100% { + transform: perspective(128px) rotateX(360deg); + } +} + +@keyframes mfm-spinY { + 0% { + transform: perspective(128px) rotateY(0deg); + } + 100% { + transform: perspective(128px) rotateY(360deg); + } +} + +@keyframes mfm-jump { + 0% { + transform: translateY(0); + } + 25% { + transform: translateY(-16px); + } + 50% { + transform: translateY(0); + } + 75% { + transform: translateY(-8px); + } + 100% { + transform: translateY(0); + } +} + +@keyframes mfm-bounce { + 0% { + transform: translateY(0) scale(1, 1); + } + 25% { + transform: translateY(-16px) scale(1, 1); + } + 50% { + transform: translateY(0) scale(1, 1); + } + 75% { + transform: translateY(0) scale(1.5, 0.75); + } + 100% { + transform: translateY(0) scale(1, 1); + } +} + +@keyframes mfm-twitch { + 0% { + transform: translate(7px, -2px); + } + 5% { + transform: translate(-3px, 1px); + } + 10% { + transform: translate(-7px, -1px); + } + 15% { + transform: translate(0, -1px); + } + 20% { + transform: translate(-8px, 6px); + } + 25% { + transform: translate(-4px, -3px); + } + 30% { + transform: translate(-4px, -6px); + } + 35% { + transform: translate(-8px, -8px); + } + 40% { + transform: translate(4px, 6px); + } + 45% { + transform: translate(-3px, 1px); + } + 50% { + transform: translate(2px, -10px); + } + 55% { + transform: translate(-7px, 0); + } + 60% { + transform: translate(-2px, 4px); + } + 65% { + transform: translate(3px, -8px); + } + 70% { + transform: translate(6px, 7px); + } + 75% { + transform: translate(-7px, -2px); + } + 80% { + transform: translate(-7px, -8px); + } + 85% { + transform: translate(9px, 3px); + } + 90% { + transform: translate(-3px, -2px); + } + 95% { + transform: translate(-10px, 2px); + } + 100% { + transform: translate(-2px, -6px); + } +} + +@keyframes mfm-shake { + 0% { + transform: translate(-3px, -1px) rotate(-8deg); + } + 5% { + transform: translate(0, -1px) rotate(-10deg); + } + 10% { + transform: translate(1px, -3px) rotate(0deg); + } + 15% { + transform: translate(1px, 1px) rotate(11deg); + } + 20% { + transform: translate(-2px, 1px) rotate(1deg); + } + 25% { + transform: translate(-1px, -2px) rotate(-2deg); + } + 30% { + transform: translate(-1px, 2px) rotate(-3deg); + } + 35% { + transform: translate(2px, 1px) rotate(6deg); + } + 40% { + transform: translate(-2px, -3px) rotate(-9deg); + } + 45% { + transform: translate(0, -1px) rotate(-12deg); + } + 50% { + transform: translate(1px, 2px) rotate(10deg); + } + 55% { + transform: translate(0, -3px) rotate(8deg); + } + 60% { + transform: translate(1px, -1px) rotate(8deg); + } + 65% { + transform: translate(0, -1px) rotate(-7deg); + } + 70% { + transform: translate(-1px, -3px) rotate(6deg); + } + 75% { + transform: translate(0, -2px) rotate(4deg); + } + 80% { + transform: translate(-2px, -1px) rotate(3deg); + } + 85% { + transform: translate(1px, -3px) rotate(-10deg); + } + 90% { + transform: translate(1px, 0) rotate(3deg); + } + 95% { + transform: translate(-2px, 0) rotate(-3deg); + } + 100% { + transform: translate(2px, 1px) rotate(2deg); + } +} + +@keyframes mfm-jelly { + from[s-au77b] { + transform: scale3d(1, 1, 1); + } + 30% { + transform: scale3d(1.25, 0.75, 1); + } + 40% { + transform: scale3d(0.75, 1.25, 1); + } + 50% { + transform: scale3d(1.15, 0.85, 1); + } + 65% { + transform: scale3d(0.95, 1.05, 1); + } + 75% { + transform: scale3d(1.05, 0.95, 1); + } + to[s-au77b] { + transform: scale3d(1, 1, 1); + } +} + +@keyframes mfm-rainbow { + 0% { + filter: hue-rotate(0deg) contrast(150%) saturate(150%); + } + 100% { + filter: hue-rotate(360deg) contrast(150%) saturate(150%); + } +} + +/* Bonfire.UI.Social.ActivityLive (xsoi6) */ + +.mfm[s-xsoi6] { + display: inline-block; +} + +._mfm_tada_[s-xsoi6] { + font-size: 150%; + animation: mfm-tada 1s linear infinite both; +} + +._mfm_jelly_[s-xsoi6] { + animation: mfm-jelly 1s linear infinite both; +} + +._mfm_twitch_[s-xsoi6] { + animation: mfm-twitch 0.5s ease infinite; +} + +._mfm_shake_[s-xsoi6] { + animation: mfm-shake 0.5s ease infinite; +} + +._mfm_spin_[s-xsoi6] { + animation: mfm-spin 0.5s linear infinite; +} + +._mfm_spin_[s-xsoi6][data-x] { + animation-name: mfm-spinX; +} +._mfm_spin_[s-xsoi6][data-y] { + animation-name: mfm-spinY; +} +._mfm_spin_[s-xsoi6][left] { + animation-direction: reverse; +} +._mfm_spin_[s-xsoi6][alternate] { + animation-direction: alternate; +} + +._mfm_jump_[s-xsoi6] { + animation: mfm-jump 0.75s linear infinite; +} + +._mfm_bounce_[s-xsoi6] { + animation: mfm-bounce 0.75s linear infinite; + transform-origin: center bottom; +} + +._mfm_flip_[s-xsoi6][data-h][data-v] { + transform: scale(-1, -1); +} +._mfm_flip_[s-xsoi6][data-v] { + transform: scaleY(-1); +} +._mfm_flip_[s-xsoi6]:not([data-v]) { + transform: scaleX(-1); +} + +._mfm_x2_[s-xsoi6] { + font-size: 200%; +} + +._mfm_x3_[s-xsoi6] { + font-size: 400%; +} + +._mfm_x4_[s-xsoi6] { + font-size: 600%; +} + +._mfm_blur_[s-xsoi6] { + filter: blur(6px); + transition: filter 0.3s; +} +._mfm_blur_[s-xsoi6]:hover { + filter: blur(0px); +} + +._mfm_rainbow_[s-xsoi6] { + animation: mfm-rainbow 1s linear infinite; +} + +._mfm_rotate_[s-xsoi6] { + transform: rotate(90deg); + transform-origin: center center; +} + +/* sparkle */ + +@keyframes mfm-tada { + from[s-xsoi6] { + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 30%, + 50%, + 70%, + 90% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 40%, + 60%, + 80% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + to[s-xsoi6] { + transform: scale3d(1, 1, 1); + } +} + +@keyframes bounce { + 0% { + transform: scaleX(0.9) scaleY(0.9); + } + + 19% { + transform: scaleX(1.1) scaleY(1.1); + } + + 48% { + transform: scaleX(0.95) scaleY(0.95); + } + + 100% { + transform: scaleX(1) scaleY(1); + } +} + +@keyframes mfm-spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +@keyframes mfm-spinX { + 0% { + transform: perspective(128px) rotateX(0deg); + } + 100% { + transform: perspective(128px) rotateX(360deg); + } +} + +@keyframes mfm-spinY { + 0% { + transform: perspective(128px) rotateY(0deg); + } + 100% { + transform: perspective(128px) rotateY(360deg); + } +} + +@keyframes mfm-jump { + 0% { + transform: translateY(0); + } + 25% { + transform: translateY(-16px); + } + 50% { + transform: translateY(0); + } + 75% { + transform: translateY(-8px); + } + 100% { + transform: translateY(0); + } +} + +@keyframes mfm-bounce { + 0% { + transform: translateY(0) scale(1, 1); + } + 25% { + transform: translateY(-16px) scale(1, 1); + } + 50% { + transform: translateY(0) scale(1, 1); + } + 75% { + transform: translateY(0) scale(1.5, 0.75); + } + 100% { + transform: translateY(0) scale(1, 1); + } +} + +@keyframes mfm-twitch { + 0% { + transform: translate(7px, -2px); + } + 5% { + transform: translate(-3px, 1px); + } + 10% { + transform: translate(-7px, -1px); + } + 15% { + transform: translate(0, -1px); + } + 20% { + transform: translate(-8px, 6px); + } + 25% { + transform: translate(-4px, -3px); + } + 30% { + transform: translate(-4px, -6px); + } + 35% { + transform: translate(-8px, -8px); + } + 40% { + transform: translate(4px, 6px); + } + 45% { + transform: translate(-3px, 1px); + } + 50% { + transform: translate(2px, -10px); + } + 55% { + transform: translate(-7px, 0); + } + 60% { + transform: translate(-2px, 4px); + } + 65% { + transform: translate(3px, -8px); + } + 70% { + transform: translate(6px, 7px); + } + 75% { + transform: translate(-7px, -2px); + } + 80% { + transform: translate(-7px, -8px); + } + 85% { + transform: translate(9px, 3px); + } + 90% { + transform: translate(-3px, -2px); + } + 95% { + transform: translate(-10px, 2px); + } + 100% { + transform: translate(-2px, -6px); + } +} + +@keyframes mfm-shake { + 0% { + transform: translate(-3px, -1px) rotate(-8deg); + } + 5% { + transform: translate(0, -1px) rotate(-10deg); + } + 10% { + transform: translate(1px, -3px) rotate(0deg); + } + 15% { + transform: translate(1px, 1px) rotate(11deg); + } + 20% { + transform: translate(-2px, 1px) rotate(1deg); + } + 25% { + transform: translate(-1px, -2px) rotate(-2deg); + } + 30% { + transform: translate(-1px, 2px) rotate(-3deg); + } + 35% { + transform: translate(2px, 1px) rotate(6deg); + } + 40% { + transform: translate(-2px, -3px) rotate(-9deg); + } + 45% { + transform: translate(0, -1px) rotate(-12deg); + } + 50% { + transform: translate(1px, 2px) rotate(10deg); + } + 55% { + transform: translate(0, -3px) rotate(8deg); + } + 60% { + transform: translate(1px, -1px) rotate(8deg); + } + 65% { + transform: translate(0, -1px) rotate(-7deg); + } + 70% { + transform: translate(-1px, -3px) rotate(6deg); + } + 75% { + transform: translate(0, -2px) rotate(4deg); + } + 80% { + transform: translate(-2px, -1px) rotate(3deg); + } + 85% { + transform: translate(1px, -3px) rotate(-10deg); + } + 90% { + transform: translate(1px, 0) rotate(3deg); + } + 95% { + transform: translate(-2px, 0) rotate(-3deg); + } + 100% { + transform: translate(2px, 1px) rotate(2deg); + } +} + +@keyframes mfm-jelly { + from[s-xsoi6] { + transform: scale3d(1, 1, 1); + } + 30% { + transform: scale3d(1.25, 0.75, 1); + } + 40% { + transform: scale3d(0.75, 1.25, 1); + } + 50% { + transform: scale3d(1.15, 0.85, 1); + } + 65% { + transform: scale3d(0.95, 1.05, 1); + } + 75% { + transform: scale3d(1.05, 0.95, 1); + } + to[s-xsoi6] { + transform: scale3d(1, 1, 1); + } +} + +@keyframes mfm-rainbow { + 0% { + filter: hue-rotate(0deg) contrast(150%) saturate(150%); + } + 100% { + filter: hue-rotate(360deg) contrast(150%) saturate(150%); + } +} + +.p_line_clamp_4[s-xsoi6], +.p_line_clamp_6[s-xsoi6] { + overflow: hidden; + text-overflow: ellipsis; + white-space: initial; + display: -webkit-box; + -webkit-box-orient: vertical; +} +.p_line_clamp_4[s-xsoi6] { + -webkit-line-clamp: 4; + line-clamp: 4; +} +.p_line_clamp_6[s-xsoi6] { + -webkit-line-clamp: 6; + line-clamp: 6; +} +.p_line_clamp_4[s-xsoi6] p[s-xsoi6], +.p_line_clamp_6[s-xsoi6] p[s-xsoi6] { + display: contents; +} diff --git a/flavours/classic/config/flavour_assets/hooks/Bonfire.Editor.Milkdown.hooks.js b/flavours/classic/config/flavour_assets/hooks/Bonfire.Editor.Milkdown.hooks.js new file mode 100644 index 0000000000..494678c339 --- /dev/null +++ b/flavours/classic/config/flavour_assets/hooks/Bonfire.Editor.Milkdown.hooks.js @@ -0,0 +1,578 @@ +/* +This file was generated by the Surface compiler. +*/ + +import { + defaultValueCtx, + editorViewOptionsCtx, + Editor, + editorViewCtx, + commandsCtx, + rootCtx, +} from "@milkdown/kit/core"; +import { $prose, replaceAll, insert } from "@milkdown/utils"; +import { + commonmark, + toggleStrongCommand, + toggleEmphasisCommand, +} from "@milkdown/kit/preset/commonmark"; +import { gfm } from "@milkdown/kit/preset/gfm"; +import { emoji } from "@milkdown/plugin-emoji"; +import { listener, listenerCtx } from "@milkdown/kit/plugin/listener"; +import { SlashProvider, slashFactory } from "@milkdown/kit/plugin/slash"; +import { gemoji } from "gemoji"; +import { clipboard } from "@milkdown/kit/plugin/clipboard"; +import { createPopup } from "@picmo/popup-picker"; +import { Plugin, PluginKey } from "@milkdown/kit/prose/state"; +import { Decoration, DecorationSet } from "@milkdown/kit/prose/view"; + +const PlaceholderPlugin = new Plugin({ + key: new PluginKey("milkdown-placeholder"), + props: { + decorations: (state) => { + const element = document.createElement("span"); + + element.classList.add("milkdown-placeholder"); + element.style.position = "absolute"; + element.style.opacity = "0.5"; + element.innerText = "Write something..."; + + const placeholderDecoration = Decoration.widget(0, element, { + key: "milkdown-placeholder", + side: 0, + }); + if (state.doc.textContent.trim().length === 0) { + return DecorationSet.create(state.doc, [placeholderDecoration]); + } + }, + }, +}); +const placeholder = $prose(() => PlaceholderPlugin); + +const MIN_PREFIX_LENGTH = 2; +const VALID_CHARS = "[\\w\\+_\\-:]"; +const MENTION_PREFIX = "(?:@)"; +const EMOJI_PREFIX = "(?::)"; +const MENTION_REGEX = new RegExp( + `(?:\\s|^)(${MENTION_PREFIX}${VALID_CHARS}{${MIN_PREFIX_LENGTH},})$`, +); +const EMOJI_REGEX = new RegExp( + `(?:\\s|^)(${EMOJI_PREFIX}${VALID_CHARS}{${MIN_PREFIX_LENGTH},})$`, +); + +import "@milkdown/theme-nord/style.css"; + +const markdown = ``; + +function mentionsPluginView(view) { + const content = document.createElement("ul"); + content.tabIndex = 1; + + content.className = + "milkdown-menu absolute m-0 p-0 menu left-menu bg-base-200 border border-base-content/10 shadow-xl border-lg"; + let list = ""; + + const provider = new SlashProvider({ + content, + shouldShow: (view, prevState) => { + // get the current content of the editor + const { state } = view; + const { doc } = state; + const currentText = doc.textContent; + + if (currentText === "") { + return false; + } + + const mentions = currentText.match(MENTION_REGEX); + // Display the menu if the last character is `@` followed by 2 chars. + if (mentions) { + // get the characters that follows the `@` in currentText + const text = mentions[1].split("@").pop(); + + return getFeedItems(text, "@").then((res) => { + list = ""; + if (res.length > 0) { + // Add max 4 items to the menu + let maxItems = 4; + for (let i = 0; i < res.length && i < maxItems; i++) { + list += mentionItemRenderer(res[i], text); + } + content.innerHTML = list; + return true; + } else { + content.innerHTML = ""; + return false; + } + }); + } + + return false; + }, + trigger: "@", + }); + + return { + update: (updatedView, prevState) => { + provider.update(updatedView, prevState); + }, + destroy: () => { + provider.destroy(); + content.remove(); + }, + }; +} + +function emojisPluginView() { + const content = document.createElement("ul"); + content.tabIndex = 1; + + content.className = + "milkdown-menu absolute m-0 p-0 menu w-72 bg-base-100 border border-base-content/10 shadow-lg"; + let list = ""; + + const provider = new SlashProvider({ + content, + shouldShow: (view, prevState) => { + // get the current content of the editor + const { state } = view; + const { doc } = state; + const currentText = doc.textContent; + + if (currentText === "") { + return false; + } + + const emojis = currentText.match(EMOJI_REGEX); + // Display the menu if the last character is `@` followed by 2 chars. + if (emojis) { + // get the characters that follows the `@` in currentText + const text = emojis[1].split(":").pop(); + const index = gemoji.findIndex((emoji) => { + return emoji.names.some((name) => name.includes(text)); + }); + list = ""; + if (index > 0) { + // Add max 4 items to the menu + gemoji + .filter((emoji) => { + return emoji.names.some((name) => name.includes(text)); + }) + .slice(0, 6) + .map((emoji) => { + list += emojiItemRenderer(emoji, text); + }); + + content.innerHTML = list; + return true; + } else { + content.innerHTML = ""; + return false; + } + } + return false; + }, + trigger: ":", + }); + + return { + update: (updatedView, prevState) => { + provider.update(updatedView, prevState); + }, + destroy: () => { + provider.destroy(); + content.remove(); + }, + }; +} + +// function slashPluginView(view) { +// const content = document.createElement('ul'); +// content.tabIndex = 1; + +// content.className = 'm-0 p-0 menu w-72 bg-base-100 shadow-lg ring-2'; +// let list = slashItemRenderer() +// content.innerHTML = list + +// const provider = new SlashProvider({ +// content, +// trigger: '/', +// }); + +// return { +// update: (updatedView, prevState) => { +// provider.update(updatedView, prevState); +// }, +// destroy: () => { +// provider.destroy(); +// content.remove(); +// } +// } +// } + +function getFeedItems(queryText, prefix) { + // console.log(prefix) + if (queryText && queryText.length > 0) { + return new Promise((resolve) => { + // this requires the bonfire_tag extension + fetch("/api/tag/autocomplete/ck5/" + prefix + "/" + queryText) + .then((response) => response.json()) + .then((data) => { + console.log("data"); + console.log(data); + let values = data.map((item) => ({ + id: item.id, + value: item.name, + icon: item.icon, + })); + resolve(values); + }) + .catch((error) => { + console.error("There has been a problem with the tag search:", error); + resolve([]); + }); + }); + } else return []; +} + +const mentionItemRenderer = (item, text) => { + return ` +
  • + +
  • `; +}; + +const emojiItemRenderer = (item, text) => { + return ` +
  • + +
  • `; +}; + +// const slashItemRenderer = () => { +// return ` +//
  • +// +//
  • +//
  • +// +//
  • +//
  • +// +//
  • +//
  • +// +//
  • + +//
  • +// +//
  • +// ` + +// } + +const mentionSlash = slashFactory("mentions-slash"); +const emojisSlash = slashFactory("emojis-slash"); +// const slash = slashFactory('slash'); +// let isUpdatingMarkdown = false; + +const createEditor = async (_this, hidden_input, composer$) => { + const editor = await Editor.make() + .config((ctx) => { + ctx.set(rootCtx, "#editor"); + ctx.set(defaultValueCtx, markdown); + ctx.set(mentionSlash.key, { + view: mentionsPluginView, + }); + ctx.set(emojisSlash.key, { + view: emojisPluginView, + }); + ctx.get(listenerCtx).markdownUpdated((ctx, markdown, prevMarkdown) => { + const transformedMarkdown = markdown + .replace(/!\[(.*?)\]\(.*?\)/g, "$1") + // Remove backslash before # at the start of a line or after a space + .replace(/(^|\s)\\#/g, "$1#") + // Remove backslash before underscore in hashtags + .replace(/(#[^_\s]+)\\(_[^_\s]+)/g, "$1$2"); + + hidden_input.value = transformedMarkdown; + + console.log("transformedMarkdown"); + console.log(transformedMarkdown); + const inputEvent = new Event("input", { + bubbles: true, + }); + + hidden_input.dispatchEvent(inputEvent); + }); + ctx.update(editorViewOptionsCtx, (prev) => ({ + ...prev, + attributes: { + placeholder: "Type your text here...", + class: + "editor prose prose-sm h-full p-2 focus:outline-none composer w-full max-w-full", + spellcheck: "false", + }, + })); + }) + //.config(nord) + .use(commonmark) + // .use(remarkInlineLinkPlugin) + .use(gfm) + .use(emoji) + .use(listener) + .use(mentionSlash) + .use(emojisSlash) + .use(clipboard) + .use(placeholder) + // .use(slash) + .create(); + + const trigger = document.querySelector(".emoji-button"); + + trigger.addEventListener("click", () => { + picker.toggle(); + }); + + const picker = createPopup( + {}, + { + referenceElement: trigger, + triggerElement: trigger, + emojiSize: "1.75rem", + className: "z-[99999999999999999999]", + }, + ); + + picker.addEventListener("emoji:select", (event) => { + console.log(event.emoji); + editor.action((ctx) => { + const view = ctx.get(editorViewCtx); + const { state } = view; + const { selection } = state; + view.dispatch(view.state.tr.insertText(event.emoji + " ")); + view.focus(); + }); + }); + + const submit_btn = document.getElementById("submit_btn"); + const heading_btn = document.getElementById("heading_btn"); + const bold_btn = document.getElementById("bold_btn"); + const italic_btn = document.getElementById("italic_btn"); + + // const quote_btn = document.getElementById('quote_btn'); + // const strike_btn = document.getElementById('strike_btn'); + // const table_btn = document.getElementById('table_btn'); + _this.handleEvent("smart_input:reset", ({ text }) => { + editor.action(replaceAll("")); + }); + + // submit_btn.addEventListener('click', (e) => { + // editor.action(replaceAll('')) + // }) + + _this.handleEvent("mention_suggestions", ({ text }) => { + // replace the current text with the text from the event + editor.action(replaceAll("")); + if (text != null) { + editor.action((ctx) => { + const view = ctx.get(editorViewCtx); + view.dispatch(view.state.tr.insertText(text + " ")); + view.focus(); + }); + } + }); + + // heading_btn.addEventListener('click', (e) => { + // e.preventDefault(); + // editor.action((ctx) => { + // const commandManager = ctx.get(commandsCtx); + // const view = ctx.get(editorViewCtx); + // commandManager.call(wrapInHeadingCommand.key, 3); + // view.focus() + // }); + // }) + + bold_btn.addEventListener("click", (e) => { + e.preventDefault(); + editor.action((ctx) => { + const commandManager = ctx.get(commandsCtx); + const view = ctx.get(editorViewCtx); + const state = view.state; + const { from, to } = state.selection; + const isActive = state.schema.marks.strong.isInSet( + state.doc.rangeHasMark(from, to, state.schema.marks.strong), + ); + + commandManager.call(toggleStrongCommand.key); + view.focus(); + + // Update button class based on the current state + // if (isActive) { + // bold_btn.classList.remove('btn-active'); + // } else { + // bold_btn.classList.add('btn-active'); + // } + }); + }); + + italic_btn.addEventListener("click", (e) => { + e.preventDefault(); + editor.action((ctx) => { + const commandManager = ctx.get(commandsCtx); + const view = ctx.get(editorViewCtx); + commandManager.call(toggleEmphasisCommand.key); + view.focus(); + }); + }); + + // quote_btn.addEventListener('click', (e) => { + // e.preventDefault(); + // editor.action((ctx) => { + // const commandManager = ctx.get(commandsCtx); + // const view = ctx.get(editorViewCtx); + // commandManager.call(wrapInBlockquoteCommand.key); + // view.focus() + // }); + // }) + + // strike_btn.addEventListener('click', (e) => { + // e.preventDefault(); + // editor.action((ctx) => { + // const commandManager = ctx.get(commandsCtx); + // const view = ctx.get(editorViewCtx); + // commandManager.call(toggleStrikethroughCommand.key); + // view.focus() + // }); + // }) + + // table_btn.addEventListener('click', (e) => { + // e.preventDefault(); + // editor.action((ctx) => { + // const commandManager = ctx.get(commandsCtx); + // const view = ctx.get(editorViewCtx); + // commandManager.call(insertTableCommand.key); + // view.focus() + // }); + // }) + + composer$.addEventListener("click", (e) => { + if (e.target.matches(".emoji_btn")) { + e.preventDefault(); + const emoji = e.target.dataset.emoji; + const text = e.target.dataset.text; + editor.action((ctx) => { + const view = ctx.get(editorViewCtx); + const { state } = view; + const { selection } = state; + view.dispatch( + view.state.tr + .delete(selection.from - text.length - 1, selection.from) + .insertText(emoji + " "), + ); + view.focus(); + }); + } + + if (e.target.matches(".mention_btn")) { + e.preventDefault(); + const mention = e.target.dataset.mention; + const text = e.target.dataset.text; + editor.action((ctx) => { + const view = ctx.get(editorViewCtx); + const { state } = view; + const { selection } = state; + + // Calculate the start position for deletion + const startPos = selection.from - text.length - 1; + + view.dispatch( + view.state.tr + .delete(startPos, selection.from) + .insertText(`${mention} ` + `\u200B `), // add a space character after the mention variable + ); + view.focus(); + }); + } + }); + + return editor; +}; + +export default { + mounted() { + console.log("ssss"); + window.addEventListener("bonfire:focus-composer", (event) => { + const composerContainer = document.querySelector("#composer_container"); + if (composerContainer) { + const contentEditableDiv = + composerContainer.querySelector("[contenteditable]"); + if (contentEditableDiv) { + contentEditableDiv.focus(); + // Place the cursor at the end of the content + const range = document.createRange(); + const selection = window.getSelection(); + range.selectNodeContents(contentEditableDiv); + range.collapse(false); + selection.removeAllRanges(); + selection.addRange(range); + } + } + }); + const hidden_input = document.getElementById("editor_hidden_input"); + const composer$ = this.el.querySelector("#editor"); + createEditor(this, hidden_input, composer$); + }, + + destroyed() { + // Clean up event listener when the component is destroyed + window.removeEventListener( + "bonfire:focus-composer", + this.focusComposerHandler, + ); + + // Clean up editor if necessary + // if (this.editor && typeof this.editor.destroy === 'function') { + // this.editor.destroy(); + // } + }, +}; diff --git a/flavours/classic/config/flavour_assets/hooks/Bonfire.UI.Social.Activity.DateAgoLive.hooks.js b/flavours/classic/config/flavour_assets/hooks/Bonfire.UI.Social.Activity.DateAgoLive.hooks.js new file mode 100644 index 0000000000..f69a38f7fc --- /dev/null +++ b/flavours/classic/config/flavour_assets/hooks/Bonfire.UI.Social.Activity.DateAgoLive.hooks.js @@ -0,0 +1,51 @@ +/* +This file was generated by the Surface compiler. +*/ + +export default { + timeAgo(input) { + const locale = + navigator.languages && navigator.languages.length + ? navigator.languages[0] + : navigator.language; // TODO: use app local instead of browser locale + const date = input instanceof Date ? input : new Date(input); + const formatter = new Intl.RelativeTimeFormat(locale); + const ranges = { + years: 3600 * 24 * 365, + months: 3600 * 24 * 30, + weeks: 3600 * 24 * 7, + days: 3600 * 24, + hours: 3600, + minutes: 60, + seconds: 1, + }; + const secondsElapsed = (date.getTime() - Date.now()) / 1000; + for (let key in ranges) { + if (ranges[key] < Math.abs(secondsElapsed)) { + const delta = secondsElapsed / ranges[key]; + return formatter.format(Math.round(delta), key); + } + } + }, + setTimeAgo(el, the_date) { + var date_ago = this.timeAgo(the_date); + // console.log(date_ago) + + if (date_ago) { + this.el.innerHTML = date_ago; + + setTimeout(() => { + this.setTimeAgo(el, the_date); + }, 60_000); + } + }, + mounted() { + var the_date = this.el.getAttribute("data-date"); + // console.log(the_date) + if (the_date) { + setTimeout(() => { + this.setTimeAgo(this.el, the_date); + }, 60_000); + } + }, +}; diff --git a/flavours/classic/config/flavour_assets/hooks/index.js b/flavours/classic/config/flavour_assets/hooks/index.js index b8a2ab6813..287625429c 100644 --- a/flavours/classic/config/flavour_assets/hooks/index.js +++ b/flavours/classic/config/flavour_assets/hooks/index.js @@ -10,24 +10,28 @@ function ns(hooks, nameSpace) { return updatedHooks } -import * as c1 from "./Bonfire.UI.Common.ViewCodeLive.hooks.js" -import * as c2 from "./Bonfire.UI.Common.LazyImage.hooks.js" -import * as c3 from "./Bonfire.UI.Common.PreviewContentLive.hooks.js" -import * as c4 from "./Bonfire.UI.Common.NotificationLive.hooks.js" -import * as c5 from "./Bonfire.UI.Common.LoadMoreLive.hooks.js" -import * as c6 from "./Bonfire.UI.Common.ChangeLocaleLive.hooks.js" -import * as c7 from "./Bonfire.UI.Common.ChangeThemesLive.hooks.js" -import * as c8 from "./Bonfire.UI.Common.ComposerLive.hooks.js" +import * as c1 from "./Bonfire.Editor.Milkdown.hooks.js" +import * as c2 from "./Bonfire.UI.Common.ViewCodeLive.hooks.js" +import * as c3 from "./Bonfire.UI.Common.LazyImage.hooks.js" +import * as c4 from "./Bonfire.UI.Common.PreviewContentLive.hooks.js" +import * as c5 from "./Bonfire.UI.Common.NotificationLive.hooks.js" +import * as c6 from "./Bonfire.UI.Common.LoadMoreLive.hooks.js" +import * as c7 from "./Bonfire.UI.Common.ChangeLocaleLive.hooks.js" +import * as c8 from "./Bonfire.UI.Common.ChangeThemesLive.hooks.js" +import * as c9 from "./Bonfire.UI.Common.ComposerLive.hooks.js" +import * as c10 from "./Bonfire.UI.Social.Activity.DateAgoLive.hooks.js" let hooks = Object.assign( - ns(c1, "Bonfire.UI.Common.ViewCodeLive"), - ns(c2, "Bonfire.UI.Common.LazyImage"), - ns(c3, "Bonfire.UI.Common.PreviewContentLive"), - ns(c4, "Bonfire.UI.Common.NotificationLive"), - ns(c5, "Bonfire.UI.Common.LoadMoreLive"), - ns(c6, "Bonfire.UI.Common.ChangeLocaleLive"), - ns(c7, "Bonfire.UI.Common.ChangeThemesLive"), - ns(c8, "Bonfire.UI.Common.ComposerLive") + ns(c1, "Bonfire.Editor.Milkdown"), + ns(c2, "Bonfire.UI.Common.ViewCodeLive"), + ns(c3, "Bonfire.UI.Common.LazyImage"), + ns(c4, "Bonfire.UI.Common.PreviewContentLive"), + ns(c5, "Bonfire.UI.Common.NotificationLive"), + ns(c6, "Bonfire.UI.Common.LoadMoreLive"), + ns(c7, "Bonfire.UI.Common.ChangeLocaleLive"), + ns(c8, "Bonfire.UI.Common.ChangeThemesLive"), + ns(c9, "Bonfire.UI.Common.ComposerLive"), + ns(c10, "Bonfire.UI.Social.Activity.DateAgoLive") ) export default hooks