add ritajs, let it show rhymes for the selected word upon clicking the rhyme FAB
This commit is contained in:
parent
ad61063c0d
commit
bb16921a74
|
@ -3,3 +3,14 @@
|
||||||
@import "tailwindcss/utilities";
|
@import "tailwindcss/utilities";
|
||||||
|
|
||||||
/* This file is for your main application CSS */
|
/* This file is for your main application CSS */
|
||||||
|
|
||||||
|
#rhyme-fab {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: solid 1px #d4d4d4;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 25px;
|
||||||
|
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
#rhyme-fab:hover {
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
// https://elixirforum.com/t/how-to-connect-quill-with-phoenix/46004
|
// https://elixirforum.com/t/how-to-connect-quill-with-phoenix/46004
|
||||||
import Quill from 'quill';
|
import Quill from 'quill';
|
||||||
import socket from '../user_socket';
|
import socket from '../user_socket';
|
||||||
|
import RhymeModule from '../lib/rhyme';
|
||||||
|
|
||||||
|
Quill.register('modules/rhymeModule', RhymeModule);
|
||||||
|
|
||||||
export let TextEditor = {
|
export let TextEditor = {
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -8,7 +11,10 @@ export let TextEditor = {
|
||||||
this.clientId;
|
this.clientId;
|
||||||
|
|
||||||
this.quill = new Quill(this.el, {
|
this.quill = new Quill(this.el, {
|
||||||
theme: 'snow'
|
theme: 'snow',
|
||||||
|
modules: {
|
||||||
|
rhymeModule: true
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let channel = socket.channel(`pad:${padId}`, {});
|
let channel = socket.channel(`pad:${padId}`, {});
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
import { RiTa } from "rita";
|
||||||
|
|
||||||
|
class RhymeModule {
|
||||||
|
constructor(quill, options) {
|
||||||
|
this.rhymeElement = document.getElementById("poex-rhymes");
|
||||||
|
this.rhymeContent = "";
|
||||||
|
this.currentSelection = null;
|
||||||
|
this.fabElement = document.getElementById("rhyme-fab");
|
||||||
|
this.quill = quill;
|
||||||
|
this.quill.on("selection-change", (range) => this.onSelectionChange(range));
|
||||||
|
this.fabElement.addEventListener("click", () => {
|
||||||
|
this.onFabClick();
|
||||||
|
});
|
||||||
|
this.quill.root.addEventListener("contextmenu", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const range = this.quill.getSelection();
|
||||||
|
if (range && range.length > 0) {
|
||||||
|
const word = this.getWordAtCursor(range.index + range.length - 1);
|
||||||
|
if (word) {
|
||||||
|
this.findAndPrintRhymes(word).bind(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onTextChange() {
|
||||||
|
const range = this.quill.getSelection();
|
||||||
|
if (range && range.length === 0) {
|
||||||
|
const word = this.getWordAtCursor(range.index);
|
||||||
|
if (word) {
|
||||||
|
this.findAndPrintRhymes(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.hideFab();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectionChange(range) {
|
||||||
|
if (range && range.length > 0) {
|
||||||
|
const bounds = this.quill.getBounds(range);
|
||||||
|
this.currentSelection = this.quill.getSelection();
|
||||||
|
this.showFab(bounds.left + bounds.width / 2, bounds.top);
|
||||||
|
} else {
|
||||||
|
this.hideFab();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFabClick() {
|
||||||
|
const range = this.currentSelection;
|
||||||
|
if (range && range.length > 0) {
|
||||||
|
const word = this.getWordAtCursor(range.index + range.length - 1);
|
||||||
|
if (word) {
|
||||||
|
this.findAndPrintRhymes(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showFab(x, y) {
|
||||||
|
this.fabElement.style.display = "block";
|
||||||
|
this.fabElement.style.position = "absolute";
|
||||||
|
this.fabElement.style.left = `${x}px`;
|
||||||
|
this.fabElement.style.top = `${y}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideFab() {
|
||||||
|
this.fabElement.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
getWordAtCursor(index) {
|
||||||
|
const text = this.quill.getText();
|
||||||
|
const wordBoundary = /\s/;
|
||||||
|
let start = index;
|
||||||
|
let end = index;
|
||||||
|
|
||||||
|
while (start > 0 && !wordBoundary.test(text[start - 1])) {
|
||||||
|
start--;
|
||||||
|
}
|
||||||
|
while (end < text.length && !wordBoundary.test(text[end])) {
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
return text.substring(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAndPrintRhymes(word) {
|
||||||
|
const rhymes = await RiTa.rhymes(word);
|
||||||
|
this.rhymeContent += `Rhymes for '${word}': ${rhymes.join(", ")}\n`;
|
||||||
|
this.rhymeElement.innerText = this.rhymeContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RhymeModule;
|
|
@ -6,9 +6,49 @@
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"quill": "^1.3.7",
|
"quill": "^1.3.7",
|
||||||
"quill-delta": "^5.1.0"
|
"quill-delta": "^5.1.0",
|
||||||
|
"rita": "^3.0.23"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@chevrotain/cst-dts-gen": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@chevrotain/gast": "11.0.3",
|
||||||
|
"@chevrotain/types": "11.0.3",
|
||||||
|
"lodash-es": "4.17.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chevrotain/gast": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@chevrotain/types": "11.0.3",
|
||||||
|
"lodash-es": "4.17.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chevrotain/regexp-to-ast": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA=="
|
||||||
|
},
|
||||||
|
"node_modules/@chevrotain/types": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@chevrotain/utils": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@ungap/structured-clone": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="
|
||||||
|
},
|
||||||
"node_modules/call-bind": {
|
"node_modules/call-bind": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz",
|
||||||
|
@ -22,6 +62,19 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chevrotain": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@chevrotain/cst-dts-gen": "11.0.3",
|
||||||
|
"@chevrotain/gast": "11.0.3",
|
||||||
|
"@chevrotain/regexp-to-ast": "11.0.3",
|
||||||
|
"@chevrotain/types": "11.0.3",
|
||||||
|
"@chevrotain/utils": "11.0.3",
|
||||||
|
"lodash-es": "4.17.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/clone": {
|
"node_modules/clone": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||||
|
@ -192,6 +245,14 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/he": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||||
|
"bin": {
|
||||||
|
"he": "bin/he"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-arguments": {
|
"node_modules/is-arguments": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
|
@ -236,6 +297,11 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||||
|
},
|
||||||
"node_modules/lodash.clonedeep": {
|
"node_modules/lodash.clonedeep": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||||
|
@ -246,6 +312,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
|
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/mingo": {
|
||||||
|
"version": "6.4.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/mingo/-/mingo-6.4.10.tgz",
|
||||||
|
"integrity": "sha512-/pOGeZKcZrKKw8YkCMKn9+XPiUYeNhkfaVbTn9tqvZvfccxf1idk8ezSulecZmPdKJLibNDtp4UBfDK3nzvMrQ=="
|
||||||
|
},
|
||||||
"node_modules/object-is": {
|
"node_modules/object-is": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
||||||
|
@ -334,6 +405,39 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/riscript": {
|
||||||
|
"version": "1.0.54",
|
||||||
|
"resolved": "https://registry.npmjs.org/riscript/-/riscript-1.0.54.tgz",
|
||||||
|
"integrity": "sha512-YNFbILV6NXsDr0EJizdQhE+fk+xrIRpJVsRjfxg/QqzB1MxhE08exOcQ5vqyZ24y4pqL/vie86t/G7NEV61BbQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"chevrotain": "^11.0.3",
|
||||||
|
"he": "^1.2.0",
|
||||||
|
"mingo": "^6.4.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rita": "^3.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rita": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rita": {
|
||||||
|
"version": "3.0.23",
|
||||||
|
"resolved": "https://registry.npmjs.org/rita/-/rita-3.0.23.tgz",
|
||||||
|
"integrity": "sha512-EaYRNDqnqpnxxtdPI4AVTKricmvApZxg4GInMQZj8vYVfkfKOLWcvSd63rJ7g3syHxbMbOU3c6nEpFot8Uhafg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@ungap/structured-clone": "^1.2.0",
|
||||||
|
"riscript": "^1.0.48"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/set-function-length": {
|
"node_modules/set-function-length": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"quill": "^1.3.7",
|
"quill": "^1.3.7",
|
||||||
"quill-delta": "^5.1.0"
|
"quill-delta": "^5.1.0",
|
||||||
|
"rita": "^3.0.23"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<main class="container h-96 mx-auto py-12">
|
<main class="container h-96 mx-auto py-12">
|
||||||
<div id="poex-text-editor" phx-hook="TextEditor" data-pad-id={@id} class="flex-auto">
|
<div id="rhyme-fab" style="display: none; position: absolute; z-index: 1000; cursor: pointer;">
|
||||||
|
<!-- You can use an icon or text here -->
|
||||||
|
<span>🔍 Rhymes</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<div id="poex-text-editor" phx-hook="TextEditor" data-pad-id={@id} class="flex-auto"></div>
|
||||||
|
<div id="poex-rhymes" class="flex-auto"></div>
|
||||||
</main>
|
</main>
|
||||||
|
|
Loading…
Reference in New Issue