diff --git a/package.json b/package.json index fad3cfe8..1afc154b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "qortal-ui", - "version": "2.2.4", + "version": "3.0.1", "description": "Qortal Project - decentralize the world - Data storage, communications, web hosting, decentralized trading, complete infrastructure for the future blockchain-based Internet", "keywords": [ "QORT", @@ -37,14 +37,12 @@ "os-locale": "3.0.0" }, "devDependencies": { - "electron": "22.0.2", + "electron": "22.1.0", "electron-builder": "23.6.0", "electron-packager": "17.1.1", - "eslint-plugin-lit": "1.8.0", - "eslint-plugin-wc": "1.4.0", "shelljs": "0.8.5" }, "engines": { "node": ">=16.17.1" } -} +} \ No newline at end of file diff --git a/qortal-ui-core/font/MavenPro.ttf b/qortal-ui-core/font/MavenPro.ttf new file mode 100644 index 00000000..ab146a80 Binary files /dev/null and b/qortal-ui-core/font/MavenPro.ttf differ diff --git a/qortal-ui-core/font/material-icons.css b/qortal-ui-core/font/material-icons.css index 1af6891e..bf6891fc 100644 --- a/qortal-ui-core/font/material-icons.css +++ b/qortal-ui-core/font/material-icons.css @@ -14,9 +14,9 @@ @font-face { font-family: 'Material Symbols Outlined'; font-style: normal; - src: local('MaterialSymbolsOutlined'), - url(MaterialSymbolsOutlined.ttf) format('truetype'), - url(MaterialSymbolsOutlined.woff2) format('woff2') + src: local('MaterialSymbolsOutlined'), + url(MaterialSymbolsOutlined.ttf) format('truetype'), + url(MaterialSymbolsOutlined.woff2) format('woff2') } @font-face { @@ -26,6 +26,13 @@ url(Montserrat.ttf) format('truetype'); } +@font-face { + font-family: 'MavenPro'; + src: local('MavenPro'), + local('MavenPro'), + url(Montserrat.ttf) format('truetype'); +} + @font-face { font-family: 'Raleway'; src: local('Raleway'), @@ -77,7 +84,8 @@ font-family: 'Material Symbols Outlined'; font-weight: normal; font-style: normal; - font-size: 24px; /* Preferred icon size */ + font-size: 24px; + /* Preferred icon size */ display: inline-block; line-height: 1; text-transform: none; diff --git a/qortal-ui-core/font/switch-theme.css b/qortal-ui-core/font/switch-theme.css index 3d164a7c..ee0a4f91 100644 --- a/qortal-ui-core/font/switch-theme.css +++ b/qortal-ui-core/font/switch-theme.css @@ -51,6 +51,7 @@ html { --lightChatHeadHover: #1e1f201a; --group-header: #929292; --group-drop-shadow: rgb(17 17 26 / 10%) 0px 1px 0px; + --gifs-drop-shadow: #32326926 0px 2px 5px 0px, #0000000d 0px 1px 1px 0px; } html[theme="dark"] { @@ -105,5 +106,6 @@ html[theme="dark"] { --chatHeadTextActive: #ffffff; --lightChatHeadHover: #e0e1e31a; --group-header: #c8c8c8; - --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px + --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px; + --gifs-drop-shadow: 0px 2px 2px 0px hsla(0, 0%, 0%, 0.14), 0px 3px 1px -2px hsla(0, 0%, 0%, 0.12), 0px 1px 5px 0px hsla(0, 0%, 0%, 0.2); } \ No newline at end of file diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 43efa61b..a3287762 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -572,8 +572,9 @@ "cchange63": "Enter Enabled", "cchange64": "Enter Disabled", "cchange65": "Please enter a recipient", - "cchange66": "Cannot fetch replied-to message. Message is too old." - + "cchange66": "Cannot fetch replied-to message. Message is too old.", + "cchange80": "Gif Explorer", + "cchange81": "Explore Collections" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", diff --git a/qortal-ui-core/package.json b/qortal-ui-core/package.json index 5515942d..f9013451 100644 --- a/qortal-ui-core/package.json +++ b/qortal-ui-core/package.json @@ -17,7 +17,7 @@ "author": "QORTAL ", "license": "GPL-3.0", "dependencies": { - "@hapi/hapi": "21.2.0", + "@hapi/hapi": "21.2.1", "@hapi/inert": "7.0.0", "sass": "1.57.1" }, @@ -58,12 +58,12 @@ "@rollup/plugin-commonjs": "24.0.1", "@rollup/plugin-node-resolve": "15.0.1", "@rollup/plugin-replace": "5.0.2", - "@rollup/plugin-terser": "0.3.0", - "@vaadin/button": "23.3.5", - "@vaadin/grid": "23.3.5", - "@vaadin/icons": "23.3.5", - "@vaadin/password-field": "23.3.5", - "@vaadin/tooltip": "23.3.5", + "@rollup/plugin-terser": "0.4.0", + "@vaadin/button": "23.3.6", + "@vaadin/grid": "23.3.6", + "@vaadin/icons": "23.3.6", + "@vaadin/password-field": "23.3.6", + "@vaadin/tooltip": "23.3.6", "asmcrypto.js": "2.3.2", "bcryptjs": "2.4.3", "epml": "0.3.3", @@ -73,7 +73,7 @@ "pwa-helpers": "0.9.1", "redux": "4.2.0", "redux-thunk": "2.4.2", - "rollup": "3.10.1", + "rollup": "3.12.0", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", "rollup-plugin-scss": "3.0.0", diff --git a/qortal-ui-core/src/styles/switch-theme.css b/qortal-ui-core/src/styles/switch-theme.css index 72dfa151..47162c6b 100644 --- a/qortal-ui-core/src/styles/switch-theme.css +++ b/qortal-ui-core/src/styles/switch-theme.css @@ -48,6 +48,7 @@ html { --chatHeadTextActive: #080808; --group-header: #929292; --group-drop-shadow: rgb(17 17 26 / 10%) 0px 1px 0px; + --gifs-drop-shadow: #32326926 0px 2px 5px 0px, #0000000d 0px 1px 1px 0px; } html[theme="dark"] { @@ -99,5 +100,6 @@ html[theme="dark"] { --chatHeadText: #ffffff; --chatHeadTextActive: #ffffff; --group-header: #c8c8c8; - --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px + --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px; + --gifs-drop-shadow: 0px 2px 2px 0px hsla(0, 0%, 0%, 0.14), 0px 3px 1px -2px hsla(0, 0%, 0%, 0.12), 0px 1px 5px 0px hsla(0, 0%, 0%, 0.2); } \ No newline at end of file diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index f41d6d38..198b0be6 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -21,15 +21,16 @@ "@material/mwc-list": "0.27.0", "@material/mwc-select": "0.27.0", "@tiptap/core": "2.0.0-beta.209", + "@tiptap/extension-highlight": "2.0.0-beta.209", "@tiptap/extension-image": "2.0.0-beta.209", "@tiptap/extension-placeholder": "2.0.0-beta.209", "@tiptap/extension-underline": "2.0.0-beta.209", - "@tiptap/extension-highlight": "2.0.0-beta.209", "@tiptap/html": "2.0.0-beta.209", "@tiptap/starter-kit": "2.0.0-beta.209", "asmcrypto.js": "2.3.2", "compressorjs": "1.1.1", "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js", + "localforage": "1.10.0", "prosemirror-commands": "1.5.0", "prosemirror-dropcursor": "1.6.1", "prosemirror-gapcursor": "1.3.1", @@ -40,7 +41,6 @@ "prosemirror-state": "1.4.2", "prosemirror-transform": "1.7.0", "prosemirror-view": "1.29.1", - "localforage": "1.10.0", "short-unique-id": "4.4.4" }, "devDependencies": { @@ -48,6 +48,7 @@ "@material/mwc-button": "0.27.0", "@material/mwc-checkbox": "0.27.0", "@material/mwc-dialog": "0.27.0", + "@material/mwc-fab": "0.27.0", "@material/mwc-formfield": "0.27.0", "@material/mwc-icon": "0.27.0", "@material/mwc-icon-button": "0.27.0", @@ -68,26 +69,27 @@ "@rollup/plugin-commonjs": "24.0.1", "@rollup/plugin-node-resolve": "15.0.1", "@rollup/plugin-replace": "5.0.2", - "@rollup/plugin-terser": "0.3.0", - "@vaadin/avatar": "23.3.5", - "@vaadin/button": "23.3.5", - "@vaadin/grid": "23.3.5", - "@vaadin/icons": "23.3.5", - "@vaadin/tooltip": "23.3.5", + "@rollup/plugin-terser": "0.4.0", + "@vaadin/avatar": "23.3.6", + "@vaadin/button": "23.3.6", + "@vaadin/grid": "23.3.6", + "@vaadin/icons": "23.3.6", + "@vaadin/tooltip": "23.3.6", + "@zip.js/zip.js": "^2.6.62", "epml": "0.3.3", "file-saver": "2.0.5", "highcharts": "10.3.3", "html-escaper": "3.0.3", "lit": "2.6.1", "lit-translate": "2.0.1", - "rollup": "3.10.1", + "passive-events-support": "1.0.33", + "rollup": "3.12.0", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", "rollup-plugin-web-worker-loader": "1.6.1", - "@zip.js/zip.js": "2.6.62", - "validator": "13.7.0" + "validator": "^13.7.0" }, "engines": { "node": ">=16.17.1" } -} \ No newline at end of file +} diff --git a/qortal-ui-plugins/plugins/core/components/ChatGifs.js b/qortal-ui-plugins/plugins/core/components/ChatGifs.js deleted file mode 100644 index 9a97986e..00000000 --- a/qortal-ui-plugins/plugins/core/components/ChatGifs.js +++ /dev/null @@ -1,585 +0,0 @@ -import { LitElement, html, css } from 'lit' -import { render } from 'lit/html.js' -import { Epml } from '../../../epml.js' -import * as zip from "@zip.js/zip.js"; -import { saveAs } from 'file-saver'; -import '@material/mwc-icon' -import ShortUniqueId from 'short-unique-id'; -import { publishData } from '../../utils/publish-image.js'; -import { get } from 'lit-translate'; - -import './ChatGifsExplore.js' -// import isAlphanumeric from 'validator/lib/isAlphanumeric'/ -const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) - -class ChatGifs extends LitElement { - static get properties() { - return { - selectedAddress: { type: Object }, - myGifCollections: { type: Array }, - mySubscribedCollections: {type: Array}, - exploreCollections: { type: Array }, - gifsToBeAdded: { type: Array}, - webWorkerImage: {type: Object}, - mode: {type: String}, - currentCollection: {type: String}, - isLoading: {type: String}, - newCollectionName: {type: String} - } - } - - static get styles() { - return css` - - ` - } - - constructor() { - super() - this.uid = new ShortUniqueId() - this.selectedAddress = window.parent.reduxStore.getState().app.selectedAddress - this.myGifCollections = [] - this.mySubscribedCollections = [] - this.exploreCollections = [] - this.myAccountName = '' - this.gifsToBeAdded = [] - // mode can be 'myCollection', 'newCollection', 'explore', 'subscribedCollection' - this.mode = "myCollection" - this.currentCollection = null - this.pageNumber = 0 - this.isLoading = false - this.newCollectionName = "" - } - - async structureCollections(gifCollections){ - try { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; - const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; - const getMetaDataGifs = (gifCollections || []).map(async (collection) => { - let collectionObj = collection - try { - const metaData = await parentEpml.request('apiCall', { - url: `/arbitrary/metadata/GIF_REPOSITORY/${this.myAccountName}/${collection.identifier}` - }) - - collectionObj = { - ...collection, - gifUrls: [] - } - if(metaData.files){ - const metaDataArray = metaData.files.split(';').map((data)=> { - return `${nodeUrl}/arbitrary/GIF_REPOSITORY/${this.myAccountName}/${collection.identifier}?filepath=${data}` - }) - - - collectionObj = { - ...collection, - gifUrls: metaDataArray - } - - } - - - - } catch (error) { - console.log(error) - } - - return collectionObj - }) - return await Promise.all(getMetaDataGifs) - } catch (error) { - - } - } - - - - - async getMoreExploreGifs(){ - try { - - const getAllGifCollections = await parentEpml.request("apiCall", { - type: "api", - url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=20&offset=${this.pageNumber * 20}`, - }); - - const gifCollectionWithMetaData = await this.structureCollections(getAllGifCollections) - this.exploreCollections = [...this.exploreCollections, ...gifCollectionWithMetaData] - - this.pageNumber = this.pageNumber + 1 - } catch (error) { - console.error(error) - } - } - - async getCollectionList(){ - try { - return await parentEpml.request("apiCall", { - type: "api", - url: `/lists/gifSubscribedRepos`, - }); - - } catch (error) { - - } - } - - async addCollectionToList(collection){ - try { - - const body = { - - "items": [ - collection - ] - - } - const bodyToString = JSON.stringify(body) - await parentEpml.request("apiCall", { - type: "api", - method: "POST", - url: `/lists/gifSubscribedRepos`, - body: bodyToString, - headers: { - 'Content-Type': 'application/json' - } - }) - } catch (error) { - - } - } - - async removeCollectionFromList(collection){ - try { - - const body = { - - "items": [ - collection - ] - - } - const bodyToString = JSON.stringify(body) - await parentEpml.request("apiCall", { - type: "api", - method: 'DELETE', - url: `/lists/gifSubscribedRepos`, - body: bodyToString, - headers: { - 'Content-Type': 'application/json' - } - }) - } catch (error) { - - } - } - - async getMyGifCollections(){ - const userName = await this.getName(this.selectedAddress.address); - this.myAccountName = userName - if(this.myAccountName){ - const getMyGifColloctions = await parentEpml.request('apiCall', { - url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=0&name=${this.myAccountName}` - }) - - const gifCollectionWithMetaData = await this.structureCollections(getMyGifColloctions) - - console.log({gifCollectionWithMetaData}) - this.myGifCollections = gifCollectionWithMetaData - } - } - async getAllCollections(){ - this.pageNumber = 0 - // for the explore section - const getAllGifCollections = await parentEpml.request("apiCall", { - type: "api", - url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=20&offset=${this.pageNumber * 20}`, - }); - const gifCollectionWithMetaData = await this.structureCollections(getAllGifCollections) - this.exploreCollections = gifCollectionWithMetaData - this.pageNumber = this.pageNumber + 1 - } - - async getSavedCollections(){ - const getCollectionList = await this.getCollectionList() - - let savedCollections = [] - const getSavedGifRepos = (getCollectionList || []).map(async (collection) => { - let splitCollection = collection.split('/') - const name = splitCollection[0] - const identifier = splitCollection[1] - try { - console.log({collection}) - const data = await parentEpml.request('apiCall', { - url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=0&name=${name}&identifier=${identifier}` - }) - if(data.length > 0){ - savedCollections.push(data[0]) - } - - - - } catch (error) { - console.log(error) - } - - return collection - }) - await Promise.all(getSavedGifRepos) - const savedCollectionsWithMetaData = await this.structureCollections(savedCollections) - this.mySubscribedCollections = savedCollectionsWithMetaData - } - - - async firstUpdated() { - - - try { - this.isLoading = true - await this.getMyGifCollections() - await this.getAllCollections() - await this.getSavedCollections() - this.isLoading = false - - - } catch (error) { - this.isLoading = false - console.error(error) - } - } - - async updated(changedProperties) { - console.log({changedProperties}) - if (changedProperties && changedProperties.has('mode')) { - const mode = this.mode - console.log({mode}) - if (mode === 'myCollection') { - try { - this.isLoading = true - - await this.getMyGifCollections() - this.isLoading = false - } catch (error) { - this.isLoading = false - } - - } - if (mode === 'explore') { - try { - this.isLoading = true - - await this.getAllCollections() - this.isLoading = false - } catch (error) { - this.isLoading = false - } - - } - if (mode === 'subscribedCollection') { - try { - this.isLoading = true - - await this.getSavedCollections() - this.isLoading = false - } catch (error) { - this.isLoading = false - } - - } - } - - - - } - - - - async getName (recipient) { - try { - const getNames = await parentEpml.request("apiCall", { - type: "api", - url: `/names/address/${recipient}`, - }); - - if (Array.isArray(getNames) && getNames.length > 0 ) { - return getNames[0].name - } else { - return '' - } - - } catch (error) { - return "" - } - } - - addGifs(gifs){ - console.log('gifs', gifs) - const mapGifs = gifs.map((file)=> { - return { - file, - name: file.name - } - }) - console.log({mapGifs}) - this.gifsToBeAdded = [...this.gifsToBeAdded, ...mapGifs] - console.log('this.gifsToBeAdded', this.gifsToBeAdded) - } - - async uploadGifCollection(){ - if(!this.newCollectionName){ - parentEpml.request('showSnackBar', get("chatpage.cchange27")); - return - } - - // if(!isAlphanumeric(this.newCollectionName)){ - // parentEpml.request('showSnackBar', get("chatpage.cchange27")); - // return - // } - try { - const userName = await this.getName(this.selectedAddress.address); - const doesNameExist = await parentEpml.request('apiCall', { - url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=0&name=${userName}&identifier=${this.newCollectionName}` - }) - - if(doesNameExist.length !== 0){ - parentEpml.request('showSnackBar', get("chatpage.cchange27")); - return - } - function blobToBase64(blob) { - return new Promise((resolve, _) => { - const reader = new FileReader(); - reader.onloadend = () => resolve(reader.result); - reader.readAsDataURL(blob); - }); - } - const zipFileWriter = new zip.BlobWriter("application/zip"); -// Creates a TextReader object storing the text of the entry to add in the zip -// (i.e. "Hello world!"). -const helloWorldReader = new zip.TextReader("Hello world!"); - -// Creates a ZipWriter object writing data via `zipFileWriter`, adds the entry -// "hello.txt" containing the text "Hello world!" via `helloWorldReader`, and -// closes the writer. - -const zipWriter = new zip.ZipWriter(zipFileWriter, { bufferedWrite: true }); - - -for (let i = 0; i < this.gifsToBeAdded.length; i++) { - await zipWriter.add(this.gifsToBeAdded[i].name, new zip.BlobReader(this.gifsToBeAdded[i].file)); - } - - -await zipWriter.close(); -const zipFileBlob = await zipFileWriter.getData() -const blobTobase = await blobToBase64(zipFileBlob) -console.log({blobTobase}) - - if (!userName) { - parentEpml.request('showSnackBar', get("chatpage.cchange27")); - this.isLoading = false; - return; - } - const id = this.uid(); - const identifier = `gif_${id}`; -await publishData({ - registeredName: userName, - file : blobTobase.split(',')[1], - service: 'GIF_REPOSITORY', - identifier: this.newCollectionName, - parentEpml, - metaData: undefined, - uploadType: 'zip', - selectedAddress: this.selectedAddress, - worker: this.webWorkerImage, - isBase64: true - }) - - await new Promise((res)=> { - let interval = null - let stop = false - const getAnswer = async () => { - - - if (!stop) { - stop = true - try { - let myCollection = await parentEpml.request('apiCall', { - url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=0&name=${userName}&identifier=${this.newCollectionName}` - }) - if (myCollection.length > 0) { - clearInterval(interval) - res() - } - } catch (error) {} - stop = false - } - } - interval = setInterval(getAnswer, 5000) - }) -saveAs(zipFileBlob, 'zipfile'); -console.log({zipFileBlob}) - } catch (error) { - console.log(error) - } - } - - setCurrentCollection(val){ - this.currentCollection = val - } - - render() { - console.log('this.currentCollection', this.currentCollection) - return html` -
-
- - - - - - -${this.mode === "myCollection" && !this.currentCollection ? html` - ${this.isLoading === true ? html` -

Loading...

- ` : ''} - ${this.myGifCollections.map((collection)=> { - return html` -
-

{ - this.currentCollection = collection - }}>${collection.identifier}

- -
- ` - })} - ` : ''} - ${this.mode === "subscribedCollection" && !this.currentCollection ? html` - ${this.isLoading === true ? html` -

Loading...

- ` : ''} - ${this.mySubscribedCollections.map((collection)=> { - return html` -
-

{ - this.currentCollection = collection - }}>${collection.identifier}

- -
- ` - })} - ` : ''} - ${this.mode === "explore" && !this.currentCollection ? html` - ${this.isLoading === true ? html` -

Loading...

- ` : ''} - this.getMoreExploreGifs(val)} .exploreCollections=${this.exploreCollections} - .setCurrentCollection=${(val)=> this.setCurrentCollection(val)} - > - - ` : ''} - ${this.currentCollection && this.mode === "myCollection" ? html` - - ${this.currentCollection.gifUrls.map((gif)=> { - console.log({gif}) - - return html` - { - e.target.src = gif - }} src=${gif} style="width: 50px; height: 50px" /> - ` - })} - ` : ''} - ${this.currentCollection && this.mode === "subscribedCollection" ? html` - - ${this.currentCollection.gifUrls.map((gif)=> { - console.log({gif}) - - return html` - { - e.target.src = gif - }} src=${gif} style="width: 50px; height: 50px" /> - ` - })} - ` : ''} - ${this.currentCollection && this.mode === "explore" ? html` - - - ${this.currentCollection.gifUrls.map((gif)=> { - console.log({gif}) - - return html` - { - e.target.src = gif - }} src=${gif} style="width: 50px; height: 50px" /> - ` - })} - ` : ''} - ${this.mode === "newCollection" ? html` - - - - { - this.newCollectionName = e.target.value - })} /> -
- ${this.gifsToBeAdded.map((gif, i)=> { - console.log({gif}) - return html` -
- - { - this.gifsToBeAdded[i] = { - ...gif, - name: e.target.value - } - })} /> -
- - ` - })} -
- ` : ''} - -
-
- ` - } - - -} - -window.customElements.define('chat-gifs', ChatGifs) diff --git a/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs-css.js b/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs-css.js new file mode 100644 index 00000000..11c2272b --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs-css.js @@ -0,0 +1,41 @@ +import { css } from 'lit' + +export const gifExplorerStyles = css` + .gif-explorer-container { + display: flex; + flex-direction: column; + justify-content: center; + width: 100%; + align-items: center; + gap: 15px; + } + + .title-row { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + } + + .gif-explorer-title { + flex: 1; + text-align: center; + font-family: Roboto, sans-serif; + letter-spacing: 0.8px; + font-size: 25px; + color: var(--chat-bubble-msg-color); + margin: 0; + } + + .explore-collections-icon { + margin-left: auto; + text-align: right; + font-size: 20px; + color: var(--chat-bubble-msg-color); + box-shadow: rgba(0, 0, 0, 0.1) 0px 20px 25px -5px, rgba(0, 0, 0, 0.04) 0px 10px 10px -5px; + padding: 5px; + background-color: var(--chat-menu-bg); + border: none; + border-radius: 12px; + } +` diff --git a/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs.js b/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs.js new file mode 100644 index 00000000..4b41e11f --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs.js @@ -0,0 +1,594 @@ +import { LitElement, html, css } from 'lit' +import { render } from 'lit/html.js' +import { Epml } from '../../../../epml.js' +import * as zip from "@zip.js/zip.js"; +import { saveAs } from 'file-saver'; +import '@material/mwc-icon' +import ShortUniqueId from 'short-unique-id'; +import { publishData } from '../../../utils/publish-image.js'; +import { translate, get } from 'lit-translate'; +import { gifExplorerStyles } from "./ChatGifs-css.js"; +import './ChatGifsExplore.js'; +import '@vaadin/tooltip'; + +const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) + +class ChatGifs extends LitElement { + static get properties() { + return { + selectedAddress: { type: Object }, + myGifCollections: { type: Array }, + mySubscribedCollections: {type: Array}, + exploreCollections: { type: Array }, + gifsToBeAdded: { type: Array}, + webWorkerImage: {type: Object}, + mode: {type: String}, + currentCollection: {type: String}, + isLoading: {type: String}, + newCollectionName: {type: String} + } + } + + static styles = [gifExplorerStyles] + + constructor() { + super() + this.uid = new ShortUniqueId() + this.selectedAddress = window.parent.reduxStore.getState().app.selectedAddress + this.myGifCollections = [] + this.mySubscribedCollections = [] + this.exploreCollections = [] + this.myAccountName = '' + this.gifsToBeAdded = [] + // mode can be 'myCollection', 'newCollection', 'explore', 'subscribedCollection' + this.mode = "myCollection" + this.currentCollection = null + this.pageNumber = 0 + this.isLoading = false + this.newCollectionName = "" + } + + async structureCollections(gifCollections){ + try { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; + const getMetaDataGifs = (gifCollections || []).map(async (collection) => { + let collectionObj = collection + try { + const metaData = await parentEpml.request('apiCall', { + url: `/arbitrary/metadata/GIF_REPOSITORY/${this.myAccountName}/${collection.identifier}` + }) + + collectionObj = { + ...collection, + gifUrls: [] + } + if(metaData.files){ + const metaDataArray = metaData.files.map((data)=> { + return `${nodeUrl}/arbitrary/GIF_REPOSITORY/${this.myAccountName}/${collection.identifier}?filepath=${data}` + }) + + + collectionObj = { + ...collection, + gifUrls: metaDataArray + } + + } + + } catch (error) { + console.log(error) + } + + return collectionObj + }) + return await Promise.all(getMetaDataGifs) + } catch (error) { + + } + } + + async getMoreExploreGifs(){ + try { + const getAllGifCollections = await parentEpml.request("apiCall", { + type: "api", + url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=20&offset=${this.pageNumber * 20}`, + }); + + const gifCollectionWithMetaData = await this.structureCollections(getAllGifCollections) + this.exploreCollections = [...this.exploreCollections, ...gifCollectionWithMetaData] + + this.pageNumber = this.pageNumber + 1 + } catch (error) { + console.error(error) + } + } + + async getCollectionList(){ + try { + return await parentEpml.request("apiCall", { + type: "api", + url: `/lists/gifSubscribedRepos`, + }); + + } catch (error) { + + } + } + + async addCollectionToList(collection){ + try { + const body = { + + "items": [ + collection + ] + + } + + const bodyToString = JSON.stringify(body) + await parentEpml.request("apiCall", { + type: "api", + method: "POST", + url: `/lists/gifSubscribedRepos`, + body: bodyToString, + headers: { + 'Content-Type': 'application/json' + } + }) + } catch (error) { + + } + } + + async removeCollectionFromList(collection){ + try { + + const body = { + + "items": [ + collection + ] + + } + const bodyToString = JSON.stringify(body) + await parentEpml.request("apiCall", { + type: "api", + method: 'DELETE', + url: `/lists/gifSubscribedRepos`, + body: bodyToString, + headers: { + 'Content-Type': 'application/json' + } + }) + } catch (error) { + + } + } + + async getMyGifCollections(){ + const userName = await this.getName(this.selectedAddress.address); + this.myAccountName = userName + if(this.myAccountName){ + const getMyGifColloctions = await parentEpml.request('apiCall', { + url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=0&name=${this.myAccountName}` + }) + const gifCollectionWithMetaData = await this.structureCollections(getMyGifColloctions) + + console.log({gifCollectionWithMetaData}) + this.myGifCollections = gifCollectionWithMetaData + } + } + async getAllCollections(){ + this.pageNumber = 0 + // for the explore section + const getAllGifCollections = await parentEpml.request("apiCall", { + type: "api", + url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=20&offset=${this.pageNumber * 20}`, + }); + const gifCollectionWithMetaData = await this.structureCollections(getAllGifCollections) + this.exploreCollections = gifCollectionWithMetaData + this.pageNumber = this.pageNumber + 1 + } + + async getSavedCollections(){ + const getCollectionList = await this.getCollectionList() + let savedCollections = [] + const getSavedGifRepos = (getCollectionList || []).map(async (collection) => { + let splitCollection = collection.split('/') + const name = splitCollection[0] + const identifier = splitCollection[1] + try { + console.log({collection}) + const data = await parentEpml.request('apiCall', { + url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=0&name=${name}&identifier=${identifier}` + }) + if(data.length > 0){ + savedCollections.push(data[0]) + } + } catch (error) { + console.log(error) + } + return collection + }) + await Promise.all(getSavedGifRepos) + const savedCollectionsWithMetaData = await this.structureCollections(savedCollections) + this.mySubscribedCollections = savedCollectionsWithMetaData + } + + async firstUpdated() { + const tooltip = this.shadowRoot.querySelector('vaadin-tooltip'); + const overlay = tooltip.shadowRoot.querySelector('vaadin-tooltip-overlay'); + overlay.shadowRoot.getElementById("overlay").style.cssText = "background-color: transparent; box-shadow: rgb(50 50 93 / 25%) 0px 2px 5px -1px, rgb(0 0 0 / 30%) 0px 1px 3px -1px"; + overlay.shadowRoot.getElementById('content').style.cssText = "background-color: var(--reactions-tooltip-bg); color: var(--chat-bubble-msg-color); text-align: center; padding: 20px 10px; border-radius: 8px; font-family: Roboto, sans-serif; letter-spacing: 0.3px; font-weight: 300; font-size: 13.5px; transition: all 0.3s ease-in-out;"; + + try { + this.isLoading = true + await this.getMyGifCollections() + await this.getAllCollections() + await this.getSavedCollections() + this.isLoading = false + } catch (error) { + this.isLoading = false + console.error(error) + } + } + + async updated(changedProperties) { + console.log({changedProperties}) + if (changedProperties && changedProperties.has('mode')) { + const mode = this.mode + console.log({mode}) + if (mode === 'myCollection') { + try { + this.isLoading = true + + await this.getMyGifCollections() + this.isLoading = false + } catch (error) { + this.isLoading = false + } + + } + + if (mode === 'explore') { + try { + this.isLoading = true + + await this.getAllCollections() + this.isLoading = false + } catch (error) { + this.isLoading = false + } + + } + if (mode === 'subscribedCollection') { + try { + this.isLoading = true + + await this.getSavedCollections() + this.isLoading = false + } catch (error) { + this.isLoading = false + } + + } + } + + + + } + + async getName (recipient) { + try { + const getNames = await parentEpml.request("apiCall", { + type: "api", + url: `/names/address/${recipient}`, + }); + + if (Array.isArray(getNames) && getNames.length > 0 ) { + return getNames[0].name + } else { + return '' + } + + } catch (error) { + return "" + } + } + + addGifs(gifs){ + console.log('gifs', gifs) + const mapGifs = gifs.map((file)=> { + return { + file, + name: file.name + } + }) + console.log({mapGifs}) + this.gifsToBeAdded = [...this.gifsToBeAdded, ...mapGifs] + console.log('this.gifsToBeAdded', this.gifsToBeAdded) + } + + async uploadGifCollection(){ + if(!this.newCollectionName){ + parentEpml.request('showSnackBar', get("chatpage.cchange27")); + return + } + + // if(!isAlphanumeric(this.newCollectionName)){ + // parentEpml.request('showSnackBar', get("chatpage.cchange27")); + // return + // } + try { + const userName = await this.getName(this.selectedAddress.address); + const doesNameExist = await parentEpml.request('apiCall', { + url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=0&name=${userName}&identifier=${this.newCollectionName}` + }) + + if(doesNameExist.length !== 0){ + parentEpml.request('showSnackBar', get("chatpage.cchange27")); + return + } + function blobToBase64(blob) { + return new Promise((resolve, _) => { + const reader = new FileReader(); + reader.onloadend = () => resolve(reader.result); + reader.readAsDataURL(blob); + }); + } + const zipFileWriter = new zip.BlobWriter("application/zip"); +// Creates a TextReader object storing the text of the entry to add in the zip +// (i.e. "Hello world!"). + const helloWorldReader = new zip.TextReader("Hello world!"); + +// Creates a ZipWriter object writing data via `zipFileWriter`, adds the entry +// "hello.txt" containing the text "Hello world!" via `helloWorldReader`, and +// closes the writer. + + const zipWriter = new zip.ZipWriter(zipFileWriter, { bufferedWrite: true }); + + + for (let i = 0; i < this.gifsToBeAdded.length; i++) { + await zipWriter.add(this.gifsToBeAdded[i].name, new zip.BlobReader(this.gifsToBeAdded[i].file)); + } + + + await zipWriter.close(); + const zipFileBlob = await zipFileWriter.getData() + const blobTobase = await blobToBase64(zipFileBlob) + console.log({blobTobase}) + + if (!userName) { + parentEpml.request('showSnackBar', get("chatpage.cchange27")); + this.isLoading = false; + return; + } + const id = this.uid(); + const identifier = `gif_${id}`; + await publishData({ + registeredName: userName, + file : blobTobase.split(',')[1], + service: 'GIF_REPOSITORY', + identifier: this.newCollectionName, + parentEpml, + metaData: undefined, + uploadType: 'zip', + selectedAddress: this.selectedAddress, + worker: this.webWorkerImage, + isBase64: true + }) + + await new Promise((res)=> { + let interval = null + let stop = false + const getAnswer = async () => { + if (!stop) { + stop = true + try { + let myCollection = await parentEpml.request('apiCall', { + url: `/arbitrary/resources?service=GIF_REPOSITORY&limit=0&name=${userName}&identifier=${this.newCollectionName}` + }) + if (myCollection.length > 0) { + clearInterval(interval) + res() + } + } catch (error) {} + stop = false + } + } + interval = setInterval(getAnswer, 5000) + }) + + saveAs(zipFileBlob, 'zipfile'); + console.log({zipFileBlob}) + } catch (error) { + console.log(error) + } + } + + setCurrentCollection(val){ + this.currentCollection = val + } + + render() { + console.log('this.currentCollection', this.currentCollection) + console.log(3, "chat gifs here") + return html` +
+
+

${translate("chatpage.cchange80")}

+ { + if(this.isLoading) return; + this.mode = "explore"; + }} + icon="vaadin:search" + slot="icon"> + + + +
+
+ + + + ${this.mode === "myCollection" && !this.currentCollection ? html` + ${this.isLoading === true ? html` +

Loading...

+ ` : ''} + ${this.myGifCollections.map((collection)=> { + return html` +
+

{ + this.currentCollection = collection + }}>${collection.identifier}

+ +
+ ` + })} + ` : ''} + ${this.mode === "subscribedCollection" && !this.currentCollection ? html` + ${this.isLoading === true ? html` +

Loading...

+ ` : ''} + ${this.mySubscribedCollections.map((collection)=> { + return html` +
+

{ + this.currentCollection = collection + }}>${collection.identifier}

+ +
+ ` + })} + ` : ''} + ${this.mode === "explore" && !this.currentCollection ? html` + ${this.isLoading === true ? html` +

Loading...

+ ` : ''} + this.getMoreExploreGifs(val)} .exploreCollections=${this.exploreCollections} + .setCurrentCollection=${(val)=> this.setCurrentCollection(val)} + > + + ` : ''} + ${this.currentCollection && this.mode === "myCollection" ? html` + + ${this.currentCollection.gifUrls.map((gif)=> { + console.log({gif}) + + return html` + { + e.target.src = gif + }} src=${gif} style="width: 50px; height: 50px" /> + ` + })} + ` : ''} + ${this.currentCollection && this.mode === "subscribedCollection" ? html` + + ${this.currentCollection.gifUrls.map((gif)=> { + console.log({gif}) + + return html` + { + e.target.src = gif + }} src=${gif} style="width: 50px; height: 50px" /> + ` + })} + ` : ''} + ${this.currentCollection && this.mode === "explore" ? html` + + + ${this.currentCollection.gifUrls.map((gif)=> { + console.log({gif}) + + return html` + { + e.target.src = gif + }} src=${gif} style="width: 50px; height: 50px" /> + ` + })} + ` : ''} + ${this.mode === "newCollection" ? html` + + + + { + this.newCollectionName = e.target.value + })} /> +
+ ${this.gifsToBeAdded.map((gif, i)=> { + console.log({gif}) + return html` +
+ + { + this.gifsToBeAdded[i] = { + ...gif, + name: e.target.value + } + })} /> +
+ + ` + })} +
+ ` : ''} + +
+
+ ` + } + + +} + +window.customElements.define('chat-gifs', ChatGifs) diff --git a/qortal-ui-plugins/plugins/core/components/ChatGifsExplore.js b/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifsExplore.js similarity index 96% rename from qortal-ui-plugins/plugins/core/components/ChatGifsExplore.js rename to qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifsExplore.js index bbd7fc3d..b5cca445 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatGifsExplore.js +++ b/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifsExplore.js @@ -1,11 +1,11 @@ import { LitElement, html, css } from 'lit' import { render } from 'lit/html.js' -import { Epml } from '../../../epml.js' +import { Epml } from '../../../../epml.js' import * as zip from "@zip.js/zip.js"; import { saveAs } from 'file-saver'; import '@material/mwc-icon' import ShortUniqueId from 'short-unique-id'; -import { publishData } from '../../utils/publish-image.js'; +import { publishData } from '../../../utils/publish-image.js'; const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 5ebc0247..e3bf62c3 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -11,7 +11,7 @@ import {unsafeHTML} from 'lit/directives/unsafe-html.js'; import { Editor, Extension } from '@tiptap/core' import * as zip from "@zip.js/zip.js"; import { saveAs } from 'file-saver'; -import './ChatGifs' +import './ChatGifs/ChatGifs.js'; // import localForage from "localforage"; registerTranslateConfig({ loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) @@ -44,10 +44,6 @@ import WebWorker from 'web-worker:./computePowWorker.js'; import WebWorkerImage from 'web-worker:./computePowWorkerImage.js'; import '@polymer/paper-dialog/paper-dialog.js' -// const messagesCache = localForage.createInstance({ -// name: "messages-cache", -// }); - const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class ChatPage extends LitElement { @@ -111,724 +107,748 @@ class ChatPage extends LitElement { } static get styles() { - return css` - html { - scroll-behavior: smooth; - } + return css` + html { + scroll-behavior: smooth; + } + + .chat-head-container { + display: flex; + justify-content: flex-start; + flex-direction: column; + height: 50vh; + overflow-y: auto; + overflow-x: hidden; + width: 100%; + } - .chat-head-container { + .repliedTo-container { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 10px 10px 8px 10px; + } + + .senderName { + margin: 0; + color: var(--mdc-theme-primary); + font-weight: bold; + user-select: none; + } + + .original-message { + color: var(--chat-bubble-msg-color); + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + margin: 0; + width: 800px; + } + + + .close-icon { + color: #676b71; + width: 18px; + transition: all 0.1s ease-in-out; + } + + .close-icon:hover { + cursor: pointer; + color: #494c50; + } + + .chat-text-area .typing-area .chatbar { + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: auto; + padding: 5px 5px 5px 7px; + overflow: hidden; + } + + .chat-text-area .typing-area .emoji-button { + width: 45px; + height: 40px; + padding-top: 4px; + border: none; + outline: none; + background: transparent; + cursor: pointer; + max-height: 40px; + color: var(--black); + } + + .emoji-button-caption { + width: 45px; + height: 40px; + padding-top: 4px; + border: none; + outline: none; + background: transparent; + cursor: pointer; + max-height: 40px; + color: var(--black); + } + + .caption-container { + width: 100%; + display: flex; + height: auto; + overflow: hidden; + justify-content: center; + background-color: var(--white); + padding: 5px; + border-radius: 1px; + } + + .chatbar-caption { + font-family: Roboto, sans-serif; + width: 70%; + margin-right: 10px; + outline: none; + align-items: center; + font-size: 18px; + resize: none; + border-top: 0; + border-right: 0; + border-left: 0; + border-bottom: 1px solid #cac8c8; + padding: 3px; + } + + .message-size-container { + display: flex; + justify-content: flex-end; + width: 100%; + } + + .message-size { + font-family: Roboto, sans-serif; + font-size: 12px; + color: black; + } + + .lds-grid { + width: 120px; + height: 120px; + position: absolute; + left: 50%; + top: 40%; + } + + img { + border-radius: 25%; + } + + .dialogCustom { + position: fixed; + z-index: 10000; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + top: 10px; + right: 20px; + user-select: none; + } + + .dialogCustomInner { + min-width: 300px; + height: 40px; + background-color: var(--white); + box-shadow: rgb(119 119 119 / 32%) 0px 4px 12px; + padding: 10px; + border-radius: 4px; + } + + .dialogCustomInner ul { + padding-left: 0px + } + + .dialogCustomInner li { + margin-bottom: 10px; + } + + .marginLoader { + margin-right: 8px; + } + + .last-message-ref { + position: absolute; + font-size: 18px; + top: -40px; + right: 30px; + width: 50; + height: 50; + z-index: 5; + color: black; + background-color: white; + border-radius: 50%; + transition: all 0.1s ease-in-out; + } + + .last-message-ref:hover { + cursor: pointer; + transform: scale(1.1); + } + + .arrow-down-icon { + transform: scale(1.15); + } + + .chat-container { + display: grid; + max-height: 100%; + } + + .chat-text-area { + display: flex; + position: relative; + justify-content: center; + min-height: 60px; + max-height: 100%; + } + + .chat-text-area .typing-area { + display: flex; + flex-direction: column; + width: 98%; + box-sizing: border-box; + margin-bottom: 8px; + border: 1px solid var(--chat-bubble-bg); + border-radius: 10px; + background: var(--chat-bubble-bg); + } + + .chat-text-area .typing-area textarea { + display: none; + } + + .chat-text-area .typing-area .chat-editor { + display: flex; + max-height: -webkit-fill-available; + width: 100%; + border-color: transparent; + margin: 0; + padding: 0; + border: none; + } + + .repliedTo-container { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 10px 10px 8px 10px; + } + + .repliedTo-subcontainer { + display: flex; + flex-direction: row; + align-items: center; + gap: 15px; + width: 100%; + } + + .repliedTo-message { + display: flex; + flex-direction: column; + gap: 5px; + width: 100%; + word-break: break-all; + text-overflow: ellipsis; + overflow: hidden; + max-height: 60px; + } + .repliedTo-message p { + margin: 0px; + padding: 0px; + } + + .repliedTo-message pre { + white-space: pre-wrap; + } + + .repliedTo-message p mark { + background-color: #ffe066; + border-radius: 0.25em; + box-decoration-break: clone; + padding: 0.125em 0; + } + + .reply-icon { + width: 20px; + color: var(--mdc-theme-primary); + } + + .close-icon { + color: #676b71; + width: 18px; + transition: all 0.1s ease-in-out; + } + + .close-icon:hover { + cursor: pointer; + color: #494c50; + } + + .chatbar-container { + width: 100%; + display: flex; + height: auto; + overflow: hidden; + } + + .lds-grid { + width: 120px; + height: 120px; + position: absolute; + left: 50%; + top: 40%; + } + + .lds-grid div { + position: absolute; + width: 34px; + height: 34px; + border-radius: 50%; + background: #03a9f4; + animation: lds-grid 1.2s linear infinite; + } + + .lds-grid div:nth-child(1) { + top: 4px; + left: 4px; + animation-delay: 0s; + } + + .lds-grid div:nth-child(2) { + top: 4px; + left: 48px; + animation-delay: -0.4s; + } + + .lds-grid div:nth-child(3) { + top: 4px; + left: 90px; + animation-delay: -0.8s; + } + + .lds-grid div:nth-child(4) { + top: 50px; + left: 4px; + animation-delay: -0.4s; + } + + .lds-grid div:nth-child(5) { + top: 50px; + left: 48px; + animation-delay: -0.8s; + } + + .lds-grid div:nth-child(6) { + top: 50px; + left: 90px; + animation-delay: -1.2s; + } + + .lds-grid div:nth-child(7) { + top: 95px; + left: 4px; + animation-delay: -0.8s; + } + + .lds-grid div:nth-child(8) { + top: 95px; + left: 48px; + animation-delay: -1.2s; + } + + .lds-grid div:nth-child(9) { + top: 95px; + left: 90px; + animation-delay: -1.6s; + } + + @keyframes lds-grid { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } + } + + .float-left { + float: left; + } + + img { + border-radius: 25%; + } + + paper-dialog.warning { + width: 50%; + max-width: 50vw; + height: 30%; + max-height: 30vh; + text-align: center; + background-color: var(--white); + color: var(--black); + border: 1px solid var(--black); + border-radius: 15px; + line-height: 1.6; + overflow-y: auto; + } + .buttons { + text-align:right; + } + + .dialogCustom { + position: fixed; + z-index: 10000; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + top: 10px; + right: 20px; + user-select: none; + } + + .dialogCustom p { + color: var(--black) + } + + .dialogCustomInner { + min-width: 300px; + height: 40px; + background-color: var(--white); + box-shadow: rgb(119 119 119 / 32%) 0px 4px 12px; + padding: 10px; + border-radius: 4px; + } + + .dialogCustomInner ul { + padding-left: 0px + } + + .dialogCustomInner li { + margin-bottom: 10px; + } + + .marginLoader { + margin-right: 8px; + } + + .smallLoading, + .smallLoading:after { + border-radius: 50%; + width: 2px; + height: 2px; + } + + .smallLoading { + border-width: 0.8em; + border-style: solid; + border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2) + rgba(3, 169, 244, 0.2) rgb(3, 169, 244); + font-size: 10px; + position: relative; + text-indent: -9999em; + transform: translateZ(0px); + animation: 1.1s linear 0s infinite normal none running loadingAnimation; + } + + @-webkit-keyframes loadingAnimation { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } + } + + @keyframes loadingAnimation { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } + } + + /* Add Image Modal Dialog Styling */ + + .dialog-container { + position: relative; + display: flex; + align-items: center; + flex-direction: column; + padding: 0 10px; + gap: 10px; + height: 100%; + } + + .dialog-container-title { + font-family: Montserrat; + color: var(--black); + font-size: 20px; + margin: 15px 0 0 0; + } + + .divider { + height: 1px; + background-color: var(--chat-bubble-msg-color); + user-select: none; + width: 70%; + margin-bottom: 20px; + } + + .dialog-container-loader { + position: relative; + display: flex; + align-items: center; + padding: 0 10px; + gap: 10px; + height: 100%; + } + + .dialog-image { + width: 100%; + max-height: 300px; + border-radius: 0; + object-fit: contain; + } + + .chat-right-panel { + flex: 0; + border-left: 3px solid rgb(221, 221, 221); + height: 100%; + overflow-y: auto; + background: transparent; + } + + .movedin { + flex: 1 !important; + background: transparent; + } + + .main-container { + display: flex; + height: 100%; + } + + .group-nav-container { + display: flex; + height: 40px; + padding: 25px 5px 25px 20px; + margin: 0px; + background-color: var(--chat-bubble-bg); + box-sizing: border-box; + align-items: center; + justify-content: space-between; + box-shadow: var(--group-drop-shadow); + } + + .top-bar-icon { + border-radius: 50%; + color: var(--chat-bubble-msg-color); + transition: 0.3s all ease-in-out; + padding: 5px; + background-color: transparent; + } + + .top-bar-icon:hover { + background-color: #e6e6e69b; + cursor: pointer; + color: var(--black) + } + + .group-name { + font-family: Raleway, sans-serif; + font-size: 16px; + color: var(--black); + margin:0px; + padding:0px; + } + + .modal-button-row { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + } + + .modal-button { + font-family: Roboto, sans-serif; + font-size: 16px; + color: var(--mdc-theme-primary); + background-color: transparent; + padding: 8px 10px; + border-radius: 5px; + border: none; + transition: all 0.3s ease-in-out; + } + + .modal-button-red { + font-family: Roboto, sans-serif; + font-size: 16px; + color: #F44336; + background-color: transparent; + padding: 8px 10px; + border-radius: 5px; + border: none; + transition: all 0.3s ease-in-out; + } + + .modal-button-red:hover { + cursor: pointer; + background-color: #f4433663; + } + + .modal-button:hover { + cursor: pointer; + background-color: #03a8f475; + } + + .name-input { + width: 100%; + margin-bottom: 15px; + outline: 0; + border-width: 0 0 2px; + border-color: var(--mdc-theme-primary); + background-color: transparent; + padding: 10px; + font-family: Roboto, sans-serif; + font-size: 15px; + color: var(--chat-bubble-msg-color); + box-sizing: border-box; + } + + .name-input::selection { + background-color: var(--mdc-theme-primary); + color: white; + } + + .name-input::placeholder { + opacity: 0.9; + color: var(--black); + } + + .search-results-div { + position: absolute; + top: 25px; + right: 25px; + } + + .search-field { + width: 100%; + position: relative; + margin-bottom: 5px; + } + + .search-icon { + position: absolute; + right: 3px; + top: 0; + color: var(--chat-bubble-msg-color); + transition: all 0.3s ease-in-out; + background: none; + border-radius: 50%; + padding: 6px 3px; + font-size: 21px; + } + + .search-icon:hover { + cursor: pointer; + background: #d7d7d75c; + } + + .user-verified { + position: absolute; + top: 0; + right: 5px; display: flex; - justify-content: flex-start; - flex-direction: column; - height: 50vh; - overflow-y: auto; - overflow-x: hidden; - width: 100%; - } - - .repliedTo-container { + align-items: center; + gap: 10px; + color: #04aa2e; + font-size: 13px; + } + + .user-selected { display: flex; - flex-direction: row; justify-content: space-between; align-items: center; - padding: 10px 10px 8px 10px; - } - - .senderName { margin: 0; - color: var(--mdc-theme-primary); - font-weight: bold; - user-select: none; - } - - .original-message { + box-shadow: rgb(0 0 0 / 16%) 0px 3px 6px, rgb(0 0 0 / 23%) 0px 3px 6px; + padding: 18px 20px; color: var(--chat-bubble-msg-color); - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - margin: 0; - width: 800px; - } - - - .close-icon { - color: #676b71; - width: 18px; - transition: all 0.1s ease-in-out; - } - - .close-icon:hover { - cursor: pointer; - color: #494c50; - } + border-radius: 5px; + background-color: #ececec96; + } - .chat-text-area .typing-area .chatbar { + .user-selected-name { + font-family: Roboto, sans-serif; + margin: 0; + font-size: 16px; + } + + .forwarding-container { + display: flex; + gap: 15px; + } + + .user-selected-forwarding { + font-family: Livvic, sans-serif; + margin: 0; + font-size: 16px; + } + + .close-forwarding { + color: #676b71; + width: 14px; + transition: all 0.1s ease-in-out; + } + + .close-forwarding:hover { + cursor: pointer; + color: #4e5054; + } + + .gifs-backdrop { + height: 100vh; + width: 100vw; + background: transparent; + position: fixed; + } + + .gifs-container { position: relative; display: flex; - flex-direction: column; - justify-content: center; + padding: 10px 15px; + border-radius: 12px; + box-shadow: rgba(0, 0, 0, 0.09) 0px 3px 12px; + background-color: var(--chat-menu-bg); align-items: center; - height: auto; - padding: 5px 5px 5px 7px; - overflow: hidden; - } - - .chat-text-area .typing-area .emoji-button { - width: 45px; - height: 40px; - padding-top: 4px; - border: none; - outline: none; - background: transparent; - cursor: pointer; - max-height: 40px; - color: var(--black); - } - - .emoji-button-caption { - width: 45px; - height: 40px; - padding-top: 4px; - border: none; - outline: none; - background: transparent; - cursor: pointer; - max-height: 40px; - color: var(--black); - } - - .caption-container { - width: 100%; - display: flex; - height: auto; - overflow: hidden; - justify-content: center; - background-color: var(--white); - padding: 5px; - border-radius: 1px; - } - - .chatbar-caption { - font-family: Roboto, sans-serif; - width: 70%; - margin-right: 10px; - outline: none; - align-items: center; - font-size: 18px; - resize: none; - border-top: 0; - border-right: 0; - border-left: 0; - border-bottom: 1px solid #cac8c8; - padding: 3px; - } - - .message-size-container { - display: flex; justify-content: flex-end; - width: 100%; - } - - .message-size { - font-family: Roboto, sans-serif; - font-size: 12px; - color: black; - } - - .lds-grid { - width: 120px; - height: 120px; - position: absolute; - left: 50%; - top: 40%; - } - - img { - border-radius: 25%; - } - - .dialogCustom { - position: fixed; - z-index: 10000; - display: flex; - justify-content: center; - flex-direction: column; - align-items: center; - top: 10px; - right: 20px; - user-select: none; - } - - .dialogCustomInner { - min-width: 300px; - height: 40px; - background-color: var(--white); - box-shadow: rgb(119 119 119 / 32%) 0px 4px 12px; - padding: 10px; - border-radius: 4px; - } - - .dialogCustomInner ul { - padding-left: 0px - } - - .dialogCustomInner li { - margin-bottom: 10px; - } - - .marginLoader { - margin-right: 8px; - } - - .last-message-ref { - position: absolute; - font-size: 18px; - top: -40px; - right: 30px; - width: 50; - height: 50; + width: fit-content; + justify-self: flex-end; + margin-bottom: 8px; + margin-right: 5px; + box-shadow: var(--gifs-drop-shadow); z-index: 5; - color: black; - background-color: white; - border-radius: 50%; - transition: all 0.1s ease-in-out; } - - .last-message-ref:hover { - cursor: pointer; - transform: scale(1.1); + ` } - .arrow-down-icon { - transform: scale(1.15); - } - - .chat-container { - display: grid; - max-height: 100%; - } - - .chat-text-area { - display: flex; - position: relative; - justify-content: center; - min-height: 60px; - max-height: 100%; - } - - .chat-text-area .typing-area { - display: flex; - flex-direction: column; - width: 98%; - box-sizing: border-box; - margin-bottom: 8px; - border: 1px solid var(--chat-bubble-bg); - border-radius: 10px; - background: var(--chat-bubble-bg); - } - - .chat-text-area .typing-area textarea { - display: none; - } - - .chat-text-area .typing-area .chat-editor { - display: flex; - max-height: -webkit-fill-available; - width: 100%; - border-color: transparent; - margin: 0; - padding: 0; - border: none; - } - - .repliedTo-container { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - padding: 10px 10px 8px 10px; - } - - .repliedTo-subcontainer { - display: flex; - flex-direction: row; - align-items: center; - gap: 15px; - width: 100%; - } - - .repliedTo-message { - display: flex; - flex-direction: column; - gap: 5px; - width: 100%; - word-break: break-all; - text-overflow: ellipsis; - overflow: hidden; - max-height: 60px; - } - .repliedTo-message p { - margin: 0px; - padding: 0px; - } - - .repliedTo-message pre { - white-space: pre-wrap; - } - - .repliedTo-message p mark { - background-color: #ffe066; - border-radius: 0.25em; - box-decoration-break: clone; - padding: 0.125em 0; - } - - .reply-icon { - width: 20px; - color: var(--mdc-theme-primary); - } - - .close-icon { - color: #676b71; - width: 18px; - transition: all 0.1s ease-in-out; - } - - .close-icon:hover { - cursor: pointer; - color: #494c50; - } - - .chatbar-container { - width: 100%; - display: flex; - height: auto; - overflow: hidden; - } - - .lds-grid { - width: 120px; - height: 120px; - position: absolute; - left: 50%; - top: 40%; - } - - .lds-grid div { - position: absolute; - width: 34px; - height: 34px; - border-radius: 50%; - background: #03a9f4; - animation: lds-grid 1.2s linear infinite; - } - - .lds-grid div:nth-child(1) { - top: 4px; - left: 4px; - animation-delay: 0s; - } - - .lds-grid div:nth-child(2) { - top: 4px; - left: 48px; - animation-delay: -0.4s; - } - - .lds-grid div:nth-child(3) { - top: 4px; - left: 90px; - animation-delay: -0.8s; - } - - .lds-grid div:nth-child(4) { - top: 50px; - left: 4px; - animation-delay: -0.4s; - } - - .lds-grid div:nth-child(5) { - top: 50px; - left: 48px; - animation-delay: -0.8s; - } - - .lds-grid div:nth-child(6) { - top: 50px; - left: 90px; - animation-delay: -1.2s; - } - - .lds-grid div:nth-child(7) { - top: 95px; - left: 4px; - animation-delay: -0.8s; - } - - .lds-grid div:nth-child(8) { - top: 95px; - left: 48px; - animation-delay: -1.2s; - } - - .lds-grid div:nth-child(9) { - top: 95px; - left: 90px; - animation-delay: -1.6s; - } - - @keyframes lds-grid { - 0%, 100% { - opacity: 1; - } - 50% { - opacity: 0.5; - } -} - - .float-left { - float: left; - } - - img { - border-radius: 25%; - } - - paper-dialog.warning { - width: 50%; - max-width: 50vw; - height: 30%; - max-height: 30vh; - text-align: center; - background-color: var(--white); - color: var(--black); - border: 1px solid var(--black); - border-radius: 15px; - line-height: 1.6; - overflow-y: auto; - } - .buttons { - text-align:right; - } - - .dialogCustom { - position: fixed; - z-index: 10000; - display: flex; - justify-content: center; - flex-direction: column; - align-items: center; - top: 10px; - right: 20px; - user-select: none; - } - - .dialogCustom p { - color: var(--black) - } - - .dialogCustomInner { - min-width: 300px; - height: 40px; - background-color: var(--white); - box-shadow: rgb(119 119 119 / 32%) 0px 4px 12px; - padding: 10px; - border-radius: 4px; - } - - .dialogCustomInner ul { - padding-left: 0px - } - - .dialogCustomInner li { - margin-bottom: 10px; - } - - .marginLoader { - margin-right: 8px; - } - - .smallLoading, - .smallLoading:after { - border-radius: 50%; - width: 2px; - height: 2px; - } - - .smallLoading { - border-width: 0.8em; - border-style: solid; - border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2) - rgba(3, 169, 244, 0.2) rgb(3, 169, 244); - font-size: 10px; - position: relative; - text-indent: -9999em; - transform: translateZ(0px); - animation: 1.1s linear 0s infinite normal none running loadingAnimation; - } - - @-webkit-keyframes loadingAnimation { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loadingAnimation { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - /* Add Image Modal Dialog Styling */ - - .dialog-container { - position: relative; - display: flex; - align-items: center; - flex-direction: column; - padding: 0 10px; - gap: 10px; - height: 100%; - } - - .dialog-container-title { - font-family: Montserrat; - color: var(--black); - font-size: 20px; - margin: 15px 0 0 0; - } - - .divider { - height: 1px; - background-color: var(--chat-bubble-msg-color); - user-select: none; - width: 70%; - margin-bottom: 20px; - } - - .dialog-container-loader { - position: relative; - display: flex; - align-items: center; - padding: 0 10px; - gap: 10px; - height: 100%; - } - - .dialog-image { - width: 100%; - max-height: 300px; - border-radius: 0; - object-fit: contain; - } - - .chat-right-panel { - flex: 0; - border-left: 3px solid rgb(221, 221, 221); - height: 100%; - overflow-y: auto; - background: transparent; - } - - .movedin { - flex: 1 !important; - background: transparent; - } - - .main-container { - display: flex; - height: 100%; - } - - .group-nav-container { - display: flex; - height: 40px; - padding: 25px 5px 25px 20px; - margin: 0px; - background-color: var(--chat-bubble-bg); - box-sizing: border-box; - align-items: center; - justify-content: space-between; - box-shadow: var(--group-drop-shadow); - } - - .top-bar-icon { - border-radius: 50%; - color: var(--chat-bubble-msg-color); - transition: 0.3s all ease-in-out; - padding: 5px; - background-color: transparent; - } - - .top-bar-icon:hover { - background-color: #e6e6e69b; - cursor: pointer; - color: var(--black) - } - - .group-name { - font-family: Raleway, sans-serif; - font-size: 16px; - color: var(--black); - margin:0px; - padding:0px; - } - - .modal-button-row { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - } - - .modal-button { - font-family: Roboto, sans-serif; - font-size: 16px; - color: var(--mdc-theme-primary); - background-color: transparent; - padding: 8px 10px; - border-radius: 5px; - border: none; - transition: all 0.3s ease-in-out; - } - - .modal-button-red { - font-family: Roboto, sans-serif; - font-size: 16px; - color: #F44336; - background-color: transparent; - padding: 8px 10px; - border-radius: 5px; - border: none; - transition: all 0.3s ease-in-out; - } - - .modal-button-red:hover { - cursor: pointer; - background-color: #f4433663; - } - - .modal-button:hover { - cursor: pointer; - background-color: #03a8f475; - } - - .name-input { - width: 100%; - margin-bottom: 15px; - outline: 0; - border-width: 0 0 2px; - border-color: var(--mdc-theme-primary); - background-color: transparent; - padding: 10px; - font-family: Roboto, sans-serif; - font-size: 15px; - color: var(--chat-bubble-msg-color); - box-sizing: border-box; - } - - .name-input::selection { - background-color: var(--mdc-theme-primary); - color: white; - } - - .name-input::placeholder { - opacity: 0.9; - color: var(--black); - } - - .search-results-div { - position: absolute; - top: 25px; - right: 25px; - } - - .search-field { - width: 100%; - position: relative; - margin-bottom: 5px; - } - - .search-icon { - position: absolute; - right: 3px; - top: 0; - color: var(--chat-bubble-msg-color); - transition: all 0.3s ease-in-out; - background: none; - border-radius: 50%; - padding: 6px 3px; - font-size: 21px; - } - - .search-icon:hover { - cursor: pointer; - background: #d7d7d75c; - } - - .user-verified { - position: absolute; - top: 0; - right: 5px; - display: flex; - align-items: center; - gap: 10px; - color: #04aa2e; - font-size: 13px; - } - - .user-selected { - display: flex; - justify-content: space-between; - align-items: center; - margin: 0; - box-shadow: rgb(0 0 0 / 16%) 0px 3px 6px, rgb(0 0 0 / 23%) 0px 3px 6px; - padding: 18px 20px; - color: var(--chat-bubble-msg-color); - border-radius: 5px; - background-color: #ececec96; - } - - .user-selected-name { - font-family: Roboto, sans-serif; - margin: 0; - font-size: 16px; - } - - .forwarding-container { - display: flex; - gap: 15px; - } - - .user-selected-forwarding { - font-family: Livvic, sans-serif; - margin: 0; - font-size: 16px; - } - - .close-forwarding { - color: #676b71; - width: 14px; - transition: all 0.1s ease-in-out; - } - - .close-forwarding:hover { - cursor: pointer; - color: #4e5054; - } -` -} - constructor() { super() this.getOldMessage = this.getOldMessage.bind(this) @@ -897,8 +917,8 @@ class ChatPage extends LitElement { this.openGifModal = false } + setOpenGifModal(value){ - console.log({value}) this.openGifModal = value } @@ -994,6 +1014,7 @@ console.log({zipFileBlob}) } render() { + console.log(23, "chat page here"); return html`
+ +
{ + this.editor.commands.focus("end"); + this.setOpenGifModal(false); + }} style=${this.openGifModal ? "visibility: visible; z-index: 4" : "visibility: hidden; z-index: -100"}> +
+
+ + +
+
-
@@ -1053,12 +1087,11 @@ console.log({zipFileBlob}) ` : ''} ${this.repliedToMessageObj.toString() === '2' ? html` ${unsafeHTML(generateHTML(this.repliedToMessageObj.message, [ - StarterKit, - Underline, - Highlight - // other extensions … - ]))} ` : ''} - + StarterKit, + Underline, + Highlight + // other extensions … + ]))} ` : ''}

${translate("chatpage.cchange25")}

${unsafeHTML(generateHTML(this.editedMessageObj.message, [ - StarterKit, - Underline, - Highlight - // other extensions … - ]))} + StarterKit, + Underline, + Highlight + // other extensions … + ]))}
this.setOpenGifModal(val)} > @@ -1130,15 +1164,6 @@ console.log({zipFileBlob})
`: ''} - - { - this.setOpenGifModal(false) - // this.removeImage(); - }} - style=${this.openGifModal ? "visibility:visible;z-index:50" : "visibility: hidden;z-index:-100"}> - - { this.removeImage(); @@ -1499,7 +1524,7 @@ console.log({zipFileBlob}) } initialChat(e) { - if (this.editor && !this.editor.isFocused && this.currentEditor === '_chatEditorDOM' && !this.openForwardOpen && !this.openTipUser &&!this.openGifModal) { + if (this.editor && !this.editor.isFocused && this.currentEditor === '_chatEditorDOM' && !this.openForwardOpen && !this.openTipUser && !this.openGifModal) { // WARNING: Deprecated methods from KeyBoard Event if (e.code === "Space" || e.keyCode === 32 || e.which === 32) { } else if (inputKeyCodes.includes(e.keyCode)) { diff --git a/qortal-ui-plugins/plugins/core/components/ChatTextEditor.js b/qortal-ui-plugins/plugins/core/components/ChatTextEditor.js index 70a7d068..5393dfc2 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatTextEditor.js +++ b/qortal-ui-plugins/plugins/core/components/ChatTextEditor.js @@ -30,6 +30,7 @@ class ChatTextEditor extends LitElement { }, toggleEnableChatEnter: {attribute: false}, isEnabledChatEnter: {type: Boolean}, + openGifModal: { type: Boolean }, setOpenGifModal: {attribute: false} } } @@ -361,69 +362,63 @@ class ChatTextEditor extends LitElement { return html`
- + class=${["chatbar-container", "chatbar-buttons", this.iframeId !=="_chatEditorDOM" && 'hide-styling'].join(" ")} + style="align-items: center;"> - - - - - - - + @click=${() => this.editor.chain().focus().toggleBold().run()} + ?disabled=${ + this.editor && + !this.editor.can() + .chain() + .focus() + .toggleBold() + .run() + } + class=${["chatbar-button-single", (this.editedMessageObj || this.repliedToMessageObj || this.openGifModal) && 'show-chatbar-buttons', this.editor && this.editor.isActive('bold') ? 'is-active' : ''].join(" ")}> + + + + + + +