mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-02-11 17:55:51 +00:00
feed in separate palce
This commit is contained in:
parent
8eacfca4d1
commit
fac7ae9004
@ -1188,6 +1188,8 @@
|
||||
"friend8": "Send Q-Chat",
|
||||
"friend9": "Send Q-Mail",
|
||||
"friend10": "Edit friend",
|
||||
"friend11": "Following"
|
||||
"friend11": "Following",
|
||||
"friend12": "Friends",
|
||||
"friend13": "Feed"
|
||||
}
|
||||
}
|
@ -7,15 +7,23 @@ import axios from 'axios'
|
||||
import '@material/mwc-menu';
|
||||
import '@material/mwc-list/mwc-list-item.js'
|
||||
import { RequestQueueWithPromise } from '../../../../plugins/plugins/utils/queue';
|
||||
import '../../../../plugins/plugins/core/components/TimeAgo'
|
||||
import { connect } from 'pwa-helpers';
|
||||
import { store } from '../../store';
|
||||
import { setNewTab } from '../../redux/app/app-actions';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
|
||||
const requestQueue = new RequestQueueWithPromise(5);
|
||||
|
||||
export class FeedItem extends LitElement {
|
||||
export class FeedItem extends connect(store)(LitElement) {
|
||||
static get properties() {
|
||||
return {
|
||||
resource: { type: Object },
|
||||
isReady: { type: Boolean},
|
||||
status: {type: Object},
|
||||
feedItem: {type: Object}
|
||||
feedItem: {type: Object},
|
||||
appName: {type: String},
|
||||
link: {type: String}
|
||||
};
|
||||
}
|
||||
|
||||
@ -23,10 +31,15 @@ export class FeedItem extends LitElement {
|
||||
return css`
|
||||
* {
|
||||
--mdc-theme-text-primary-on-background: var(--black);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
img {
|
||||
max-width:45vh;
|
||||
max-height:40vh;
|
||||
width:100%;
|
||||
max-height:30vh;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
@ -51,9 +64,40 @@ export class FeedItem extends LitElement {
|
||||
}
|
||||
|
||||
.defaultSize {
|
||||
width: 45vh;
|
||||
height: 40vh;
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
}
|
||||
.parent-feed-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
background-color: var(--chat-bubble-bg);
|
||||
flex-grow: 0;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
border-radius: 5px;
|
||||
padding: 12px 15px 4px 15px;
|
||||
min-width: 150px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
.avatar {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
.feed-item-name {
|
||||
user-select: none;
|
||||
color: #03a9f4;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.app-name {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
mwc-menu {
|
||||
position: absolute;
|
||||
@ -102,6 +146,7 @@ export class FeedItem extends LitElement {
|
||||
this.myNode = this.getMyNode()
|
||||
this.hasCalledWhenDownloaded = false
|
||||
this.isFetching = false
|
||||
this.uid = new ShortUniqueId()
|
||||
|
||||
this.observer = new IntersectionObserver(entries => {
|
||||
for (const entry of entries) {
|
||||
@ -283,11 +328,93 @@ getMyNode(){
|
||||
|
||||
|
||||
|
||||
|
||||
async goToFeedLink(){
|
||||
try {
|
||||
console.log('this.link', this.link)
|
||||
let newQuery = this.link
|
||||
if (newQuery.endsWith('/')) {
|
||||
newQuery = newQuery.slice(0, -1)
|
||||
}
|
||||
const res = await this.extractComponents(newQuery)
|
||||
if (!res) return
|
||||
const { service, name, identifier, path } = res
|
||||
let query = `?service=${service}`
|
||||
if (name) {
|
||||
query = query + `&name=${name}`
|
||||
}
|
||||
if (identifier) {
|
||||
query = query + `&identifier=${identifier}`
|
||||
}
|
||||
if (path) {
|
||||
query = query + `&path=${path}`
|
||||
}
|
||||
|
||||
store.dispatch(setNewTab({
|
||||
url: `qdn/browser/index.html${query}`,
|
||||
id: this.uid.rnd(),
|
||||
myPlugObj: {
|
||||
"url": "myapp",
|
||||
"domain": "core",
|
||||
"page": `qdn/browser/index.html${query}`,
|
||||
"title": name,
|
||||
"icon": 'vaadin:external-browser',
|
||||
"mwcicon": 'open_in_browser',
|
||||
"menus": [],
|
||||
"parent": false
|
||||
},
|
||||
openExisting: true
|
||||
}))
|
||||
} catch (error) {
|
||||
console.log({error})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
async extractComponents(url) {
|
||||
if (!url.startsWith("qortal://")) {
|
||||
return null
|
||||
}
|
||||
|
||||
url = url.replace(/^(qortal\:\/\/)/, "")
|
||||
if (url.includes("/")) {
|
||||
let parts = url.split("/")
|
||||
const service = parts[0].toUpperCase()
|
||||
parts.shift()
|
||||
const name = parts[0]
|
||||
parts.shift()
|
||||
let identifier
|
||||
|
||||
if (parts.length > 0) {
|
||||
identifier = parts[0] // Do not shift yet
|
||||
// Check if a resource exists with this service, name and identifier combination
|
||||
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||
const url = `${nodeUrl}/arbitrary/resource/status/${service}/${name}/${identifier}?apiKey=${myNode.apiKey}}`
|
||||
|
||||
const res = await fetch(url);
|
||||
const data = await res.json();
|
||||
if (data.totalChunkCount > 0) {
|
||||
// Identifier exists, so don't include it in the path
|
||||
parts.shift()
|
||||
}
|
||||
else {
|
||||
identifier = null
|
||||
}
|
||||
}
|
||||
|
||||
const path = parts.join("/")
|
||||
|
||||
const components = {}
|
||||
components["service"] = service
|
||||
components["name"] = name
|
||||
components["identifier"] = identifier
|
||||
components["path"] = path
|
||||
return components
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -297,6 +424,20 @@ getMyNode(){
|
||||
|
||||
render() {
|
||||
console.log('this.feedItem', this.feedItem)
|
||||
let avatarImg
|
||||
const avatarUrl = `${this.nodeUrl}/arbitrary/THUMBNAIL/${this.resource.name}/qortal_avatar?async=true&apiKey=${this.myNode.apiKey}`;
|
||||
avatarImg = html`<img
|
||||
src="${avatarUrl}"
|
||||
style="max-width:100%; max-height:100%;"
|
||||
onerror="this.onerror=null; this.src='/img/incognito.png';"
|
||||
/>`;
|
||||
let avatarImgApp
|
||||
const avatarUrl2 = `${this.nodeUrl}/arbitrary/THUMBNAIL/${this.appName}/qortal_avatar?async=true&apiKey=${this.myNode.apiKey}`;
|
||||
avatarImgApp = html`<img
|
||||
src="${avatarUrl2}"
|
||||
style="max-width:100%; max-height:100%;"
|
||||
onerror="this.onerror=null; this.src='/img/incognito.png';"
|
||||
/>`;
|
||||
return html`
|
||||
<div
|
||||
class=${[
|
||||
@ -308,12 +449,13 @@ getMyNode(){
|
||||
? 'hideImg'
|
||||
: '',
|
||||
].join(' ')}
|
||||
style=" box-sizing: border-box;"
|
||||
>
|
||||
${
|
||||
this.status.status !== 'READY'
|
||||
? html`
|
||||
<div
|
||||
style="display:flex;flex-direction:column;width:100%;height:100%;justify-content:center;align-items:center;"
|
||||
style="display:flex;flex-direction:column;width:100%;height:100%;justify-content:center;align-items:center; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class=${`smallLoading`}
|
||||
@ -325,8 +467,24 @@ getMyNode(){
|
||||
: ''
|
||||
}
|
||||
${this.status.status === 'READY' && this.feedItem ? html`
|
||||
<div style="position:relative">
|
||||
ready
|
||||
<div class="parent-feed-item" style="position:relative" @click=${this.goToFeedLink}>
|
||||
<div style="display:flex;gap:10px;margin-bottom:20px">
|
||||
<div class="avatar">
|
||||
${avatarImg}</div> <span class="feed-item-name">${this.resource.name}</span>
|
||||
</div>
|
||||
<div>
|
||||
<p>${this.feedItem.title}</p>
|
||||
</div>
|
||||
<div class="app-name">
|
||||
<div class="avatar">
|
||||
${avatarImgApp}
|
||||
</div>
|
||||
<message-time
|
||||
timestamp=${this
|
||||
.resource
|
||||
.created}
|
||||
></message-time>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import { friendsViewStyles } from './friends-view-css';
|
||||
import { connect } from 'pwa-helpers';
|
||||
import { store } from '../../store';
|
||||
import './feed-item'
|
||||
|
||||
const perEndpointCount = 20;
|
||||
const totalDesiredCount = 100;
|
||||
const maxResultsInMemory = 300;
|
||||
@ -17,18 +18,25 @@ class FriendsFeed extends connect(store)(LitElement) {
|
||||
constructor(){
|
||||
super()
|
||||
this.feed = []
|
||||
this.feedToRender = []
|
||||
this.nodeUrl = this.getNodeUrl();
|
||||
this.myNode = this.getMyNode();
|
||||
this.endpoints = []
|
||||
this.endpointOffsets = [] // Initialize offsets for each endpoint to 0
|
||||
|
||||
|
||||
this.loadAndMergeData = this.loadAndMergeData.bind(this)
|
||||
this.hasInitialFetch = false
|
||||
this.observerHandler = this.observerHandler.bind(this);
|
||||
this.elementObserver = this.elementObserver.bind(this)
|
||||
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return [friendsViewStyles];
|
||||
}
|
||||
|
||||
|
||||
|
||||
getNodeUrl() {
|
||||
const myNode =
|
||||
store.getState().app.nodeConfig.knownNodes[
|
||||
@ -49,45 +57,27 @@ class FriendsFeed extends connect(store)(LitElement) {
|
||||
}
|
||||
|
||||
async firstUpdated(){
|
||||
console.log('sup')
|
||||
this.viewElement = this.shadowRoot.getElementById('viewElement');
|
||||
this.downObserverElement =
|
||||
this.shadowRoot.getElementById('downObserver');
|
||||
this.elementObserver();
|
||||
const feedData = schema.feed[0]
|
||||
let schemaObj = {...schema}
|
||||
const dynamicVars = {
|
||||
name: 'Phil'
|
||||
|
||||
}
|
||||
const getMail = async () => {
|
||||
const getEndpoints = async () => {
|
||||
|
||||
const baseurl = `${this.nodeUrl}/arbitrary/resources/search?reverse=true`
|
||||
const fullUrl = constructUrl(baseurl, feedData.search, dynamicVars);
|
||||
this.endpoints= ['http://127.0.0.1:12391/arbitrary/resources/search?reverse=true&query=-post-&identifier=q-blog-&service=BLOG_POST&exactmatchnames=true&limit=20']
|
||||
this.endpointOffsets = Array(this.endpoints.length).fill(0); // Initialize offsets for each endpoint to 0
|
||||
this.endpoints= [{url: fullUrl, schemaName: schema.name, schema: feedData }]
|
||||
this.endpointOffsets = Array(this.endpoints.length).fill(0);
|
||||
|
||||
console.log('this.endpoints', this.endpoints)
|
||||
const response = await fetch(fullUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
return data;
|
||||
|
||||
}
|
||||
try {
|
||||
getMail()
|
||||
const resource = {
|
||||
name: 'Phil',
|
||||
identifier: 'q-blog-Mugician-post-Love-Explosion-Festival--yJ8kuo'
|
||||
}
|
||||
// First, evaluate methods to get values for customParams
|
||||
await updateCustomParamsWithMethods(schemaObj, resource);
|
||||
console.log({schemaObj})
|
||||
// Now, generate your final URLs
|
||||
let clickValue1 = schemaObj.feed[0].click;
|
||||
getEndpoints()
|
||||
|
||||
const resolvedClickValue1 = replacePlaceholders(clickValue1, resource, schemaObj.feed[0].customParams);
|
||||
|
||||
console.log(resolvedClickValue1);
|
||||
this.loadAndMergeData();
|
||||
|
||||
|
||||
@ -96,10 +86,59 @@ this.loadAndMergeData();
|
||||
}
|
||||
}
|
||||
|
||||
getMoreFeed(){
|
||||
if(!this.hasInitialFetch) return
|
||||
console.log('getting more feed')
|
||||
if(this.feedToRender.length === this.feed.length ) return
|
||||
this.feedToRender = this.feed.slice(0, this.feedToRender.length + 20)
|
||||
this.requestUpdate()
|
||||
}
|
||||
|
||||
|
||||
elementObserver() {
|
||||
const options = {
|
||||
rootMargin: '0px',
|
||||
threshold: 1,
|
||||
};
|
||||
// identify an element to observe
|
||||
console.log('this', this.viewElement, this.downObserverElement)
|
||||
const elementToObserve = this.downObserverElement;
|
||||
// passing it a callback function
|
||||
const observer = new IntersectionObserver(
|
||||
this.observerHandler,
|
||||
options
|
||||
);
|
||||
// call `observe()` on that MutationObserver instance,
|
||||
// passing it the element to observe, and the options object
|
||||
observer.observe(elementToObserve);
|
||||
}
|
||||
|
||||
observerHandler(entries) {
|
||||
console.log({entries})
|
||||
if (!entries[0].isIntersecting) {
|
||||
return;
|
||||
} else {
|
||||
console.log('this.feedToRender', this.feedToRender)
|
||||
if (this.feedToRender.length < 20) {
|
||||
return;
|
||||
}
|
||||
this.getMoreFeed();
|
||||
}
|
||||
}
|
||||
|
||||
async fetchDataFromEndpoint(endpointIndex, count) {
|
||||
const offset = this.endpointOffsets[endpointIndex];
|
||||
const url = `${this.endpoints[endpointIndex]}&limit=${count}&offset=${offset}`;
|
||||
return fetch(url).then(res => res.json());
|
||||
const url = `${this.endpoints[endpointIndex].url}&limit=${count}&offset=${offset}`;
|
||||
const res = await fetch(url)
|
||||
const data = await res.json()
|
||||
console.log({data})
|
||||
return data.map((i)=> {
|
||||
return {
|
||||
...this.endpoints[endpointIndex],
|
||||
...i
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -165,17 +204,55 @@ this.loadAndMergeData();
|
||||
const uniqueNewData = newData.filter(item => !existingIds.has(item.identifier));
|
||||
return uniqueNewData.concat(existingData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
async addExtraData(data){
|
||||
let newData = []
|
||||
for (let item of data) {
|
||||
let newItem = {
|
||||
...item,
|
||||
schema: {
|
||||
...item.schema,
|
||||
customParams: {...item.schema.customParams}
|
||||
|
||||
}
|
||||
}
|
||||
let newResource = {
|
||||
identifier: newItem.identifier,
|
||||
service: newItem.service,
|
||||
name: newItem.name
|
||||
}
|
||||
if(newItem.schema){
|
||||
const resource = newItem
|
||||
// First, evaluate methods to get values for customParams
|
||||
await updateCustomParamsWithMethods(newItem.schema, newResource);
|
||||
// Now, generate your final URLs
|
||||
let clickValue1 = newItem.schema.click;
|
||||
|
||||
const resolvedClickValue1 = replacePlaceholders(clickValue1, resource, newItem.schema.customParams);
|
||||
newItem.link = resolvedClickValue1
|
||||
newData.push(newItem)
|
||||
}
|
||||
}
|
||||
return newData
|
||||
|
||||
}
|
||||
|
||||
async loadAndMergeData() {
|
||||
let allData = this.feed
|
||||
const newData = await this.initialLoad();
|
||||
allData = await this.addExtraData(newData)
|
||||
allData = this.mergeData(newData, allData);
|
||||
allData.sort((a, b) => new Date(b.created) - new Date(a.created)); // Sort by timestamp, most recent first
|
||||
allData = this.trimDataToLimit(allData, maxResultsInMemory); // Trim to the maximum allowed in memory
|
||||
this.feed = [...allData]
|
||||
this.feedToRender = this.feed.slice(0,20)
|
||||
this.hasInitialFetch = true
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
console.log('ron', this.feed)
|
||||
@ -183,13 +260,11 @@ this.loadAndMergeData();
|
||||
<div class="container">
|
||||
<div id="viewElement" class="container-body" style=${"position: relative"}>
|
||||
|
||||
${this.feed.map((item) => {
|
||||
${this.feedToRender.map((item) => {
|
||||
return html`<feed-item
|
||||
.resource=${{
|
||||
name: item.name,
|
||||
service: item.service,
|
||||
identifier: item.identifier,
|
||||
}}
|
||||
.resource=${item}
|
||||
appName=${'Q-Blog'}
|
||||
link=${item.link}
|
||||
></feed-item>`;
|
||||
})}
|
||||
<div id="downObserver"></div>
|
||||
@ -223,13 +298,43 @@ export function constructUrl(base, search, dynamicVars) {
|
||||
return queryStrings.length > 0 ? `${base}&${queryStrings.join('&')}` : base;
|
||||
}
|
||||
|
||||
function validateMethodString(methodString) {
|
||||
// Check for IIFE
|
||||
const iifePattern = /^\(.*\)\s*\(\)/;
|
||||
if (iifePattern.test(methodString)) {
|
||||
throw new Error("IIFE detected!");
|
||||
}
|
||||
|
||||
// Check for disallowed keywords
|
||||
const disallowed = ["eval", "Function", "fetch", "XMLHttpRequest"];
|
||||
for (const keyword of disallowed) {
|
||||
if (methodString.includes(keyword)) {
|
||||
throw new Error(`Disallowed keyword detected: ${keyword}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ... Add more validation steps here ...
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function executeMethodInWorker(methodString, externalArgs) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!validateMethodString(methodString)) {
|
||||
reject(new Error("Invalid method string provided."));
|
||||
return;
|
||||
}
|
||||
|
||||
const workerFunction = `
|
||||
self.onmessage = function(event) {
|
||||
const method = ${methodString};
|
||||
const result = method(event.data.externalArgs);
|
||||
self.postMessage(result);
|
||||
const methodFunction = new Function("resource", "${methodString}");
|
||||
const result = methodFunction(event.data.externalArgs);
|
||||
|
||||
if (typeof result === 'string' || typeof result === 'number') {
|
||||
self.postMessage(result);
|
||||
} else {
|
||||
self.postMessage('');
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -238,9 +343,16 @@ function executeMethodInWorker(methodString, externalArgs) {
|
||||
const worker = new Worker(blobURL);
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
resolve(event.data);
|
||||
worker.terminate();
|
||||
URL.revokeObjectURL(blobURL);
|
||||
if (typeof event.data === 'string' || typeof event.data === 'number') {
|
||||
resolve(event.data);
|
||||
worker.terminate();
|
||||
URL.revokeObjectURL(blobURL);
|
||||
} else {
|
||||
resolve("");
|
||||
worker.terminate();
|
||||
URL.revokeObjectURL(blobURL);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
worker.onerror = function(error) {
|
||||
@ -256,17 +368,24 @@ function executeMethodInWorker(methodString, externalArgs) {
|
||||
|
||||
|
||||
export async function updateCustomParamsWithMethods(schema,resource) {
|
||||
for (const key in schema.feed[0].customParams) {
|
||||
const value = schema.feed[0].customParams[key];
|
||||
|
||||
console.log({schema, resource})
|
||||
for (const key in schema.customParams) {
|
||||
const value = schema.customParams[key];
|
||||
console.log({value})
|
||||
if (value.startsWith("**methods.") && value.endsWith("**")) {
|
||||
const methodInvocation = value.slice(10, -2).split('(');
|
||||
const methodName = methodInvocation[0];
|
||||
|
||||
if (schema.feed[0].methods[methodName]) {
|
||||
const methodResult = await executeMethodInWorker(schema.feed[0].methods[methodName].toString(), resource);
|
||||
if (schema.methods[methodName]) {
|
||||
const newResource = {
|
||||
identifier: resource.identifier,
|
||||
name: resource.name,
|
||||
service: resource.service
|
||||
}
|
||||
console.log({newResource})
|
||||
const methodResult = await executeMethodInWorker(schema.methods[methodName], newResource);
|
||||
console.log({methodResult})
|
||||
schema.feed[0].customParams[key] = methodResult;
|
||||
schema.customParams[key] = methodResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -292,9 +411,9 @@ export function replacePlaceholders(template, resource, customParams) {
|
||||
|
||||
|
||||
|
||||
// export const schemaList = [schema]
|
||||
|
||||
|
||||
export const schema = {
|
||||
const schema = {
|
||||
name: "Q-Blog",
|
||||
defaultFeedIndex: 0,
|
||||
feed: [
|
||||
@ -305,7 +424,6 @@ export const schema = {
|
||||
title: "Q-Blog Post creations",
|
||||
description: "blablabla",
|
||||
search: {
|
||||
name:"$${name}$$",
|
||||
query: "-post-",
|
||||
identifier: "q-blog-",
|
||||
service: "BLOG_POST",
|
||||
@ -321,27 +439,35 @@ export const schema = {
|
||||
blogId: "**methods.getBlogId(resource)**",
|
||||
shortIdentifier: "**methods.getShortId(resource)**"
|
||||
},
|
||||
methods: {
|
||||
getShortId: function(resource) {
|
||||
const str = resource.identifier
|
||||
const arr = str.split('-post-')
|
||||
const shortIdentifier = arr[1]
|
||||
|
||||
return shortIdentifier
|
||||
},
|
||||
getBlogId: function(resource) {
|
||||
const str = resource.identifier
|
||||
const arr = str.split('-post-')
|
||||
const id = arr[0]
|
||||
let blogId = ""
|
||||
if (id.startsWith('q-blog-')) {
|
||||
blogId = id.substring(7);
|
||||
} else {
|
||||
blogId= id;
|
||||
}
|
||||
return blogId
|
||||
}
|
||||
"methods": {
|
||||
"getShortId": "return resource.identifier.split('-post-')[1];",
|
||||
"getBlogId": "const arr = resource.identifier.split('-post-'); const id = arr[0]; return id.startsWith('q-blog-') ? id.substring(7) : id;"
|
||||
}
|
||||
// methods: {
|
||||
// getShortId: function(resource) {
|
||||
// console.log({resource})
|
||||
// const str = resource.identifier
|
||||
// const arr = str.split('-post-')
|
||||
// const shortIdentifier = arr[1]
|
||||
|
||||
// return shortIdentifier
|
||||
// },
|
||||
// getBlogId: function(resource) {
|
||||
// console.log({resource})
|
||||
// const str = resource.identifier
|
||||
// const arr = str.split('-post-')
|
||||
// const id = arr[0]
|
||||
// let blogId = ""
|
||||
// if (id.startsWith('q-blog-')) {
|
||||
// blogId = id.substring(7);
|
||||
// } else {
|
||||
// blogId= id;
|
||||
// }
|
||||
// return blogId
|
||||
// }
|
||||
// }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// export const schema = JSON.stringify(schema2, null, 2); // 2 spaces indentation
|
||||
|
@ -2,13 +2,20 @@ import { LitElement, html, css } from 'lit';
|
||||
import '@material/mwc-icon';
|
||||
import './friends-view'
|
||||
import './friends-feed'
|
||||
import { translate } from 'lit-translate';
|
||||
class FriendsSidePanel extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
setIsOpen: { attribute: false},
|
||||
isOpen: {type: Boolean}
|
||||
isOpen: {type: Boolean},
|
||||
selected: {type: String}
|
||||
};
|
||||
}
|
||||
|
||||
constructor(){
|
||||
super()
|
||||
this.selected = 'friends'
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
@ -21,7 +28,6 @@ class FriendsSidePanel extends LitElement {
|
||||
height: calc(100vh - 55px);
|
||||
background-color: var(--white);
|
||||
border-left: 1px solid rgb(224, 224, 224);
|
||||
overflow-y: auto;
|
||||
z-index: 1;
|
||||
transform: translateX(100%); /* start from outside the right edge */
|
||||
transition: transform 0.3s ease-in-out;
|
||||
@ -40,23 +46,85 @@ class FriendsSidePanel extends LitElement {
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
.content::-webkit-scrollbar-track {
|
||||
background-color: whitesmoke;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.content::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
border-radius: 7px;
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
.content::-webkit-scrollbar-thumb {
|
||||
background-color: rgb(180, 176, 176);
|
||||
border-radius: 7px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
.parent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.active {
|
||||
font-size: 16px;
|
||||
background: var(--black);
|
||||
color: var(--white);
|
||||
padding: 5px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.default {
|
||||
font-size: 16px;
|
||||
color: var(--black);
|
||||
padding: 5px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.default-content {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
z-index: -50;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="parent">
|
||||
<div class="header">
|
||||
<span>Panel Title</span>
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span @click=${()=> this.selected = 'friends'} class="${this.selected === 'friends' ? 'active' : 'default'}">${translate('friends.friend12')}</span>
|
||||
<span @click=${()=> this.selected = 'feed'} class="${this.selected === 'feed' ? 'active' : 'default'}">${translate('friends.friend13')}</span>
|
||||
</div>
|
||||
<mwc-icon style="cursor:pointer" @click=${()=> {
|
||||
this.setIsOpen(false)
|
||||
}}>close</mwc-icon>
|
||||
</div>
|
||||
<div class="content">
|
||||
<friends-view></friends-view>
|
||||
<friends-feed></friends-feed>
|
||||
<div class="${this.selected === 'friends' ? 'active-content' : 'default-content'}">
|
||||
<friends-view></friends-view>
|
||||
</div>
|
||||
<div class="${this.selected === 'feed' ? 'active-content' : 'default-content'}">
|
||||
<friends-feed></friends-feed>
|
||||
</div>
|
||||
<!-- ${this.selected === 'friends' ? html`<friends-view></friends-view>` : ''}
|
||||
|
||||
${this.selected === 'feed' ? html`<friends-feed></friends-feed>` : ''} -->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { css } from 'lit'
|
||||
|
||||
export const friendsViewStyles = css`
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.top-bar-icon {
|
||||
cursor: pointer;
|
||||
height: 18px;
|
||||
@ -41,6 +44,7 @@ export const friendsViewStyles = css`
|
||||
padding: 0px 6px;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.container-body::-webkit-scrollbar-track {
|
||||
@ -164,7 +168,7 @@ export const friendsViewStyles = css`
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
color: var(--chat-bubble-msg-color);
|
||||
transition: all 0.3s ease-in-out;
|
||||
transition: hover 0.3s ease-in-out;
|
||||
background: none;
|
||||
border-radius: 50%;
|
||||
padding: 6px 3px;
|
||||
|
@ -270,7 +270,7 @@ class FriendsView extends connect(store)(LitElement) {
|
||||
?loading=${this.isLoading}>
|
||||
</chat-search-results>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
|
||||
${this.friendList.map((item) => {
|
||||
return html`<chat-side-nav-heads
|
||||
|
@ -281,10 +281,7 @@ class WebBrowser extends LitElement {
|
||||
else {
|
||||
identifier = null;
|
||||
}
|
||||
}
|
||||
|
||||
const path = parts.join("/");
|
||||
|
||||
}extractComponents
|
||||
const components = {};
|
||||
components["service"] = service;
|
||||
components["name"] = name;
|
||||
|
Loading…
x
Reference in New Issue
Block a user