aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2023-08-23 15:44:33 +0300
committerGravatar Vitaly Takmazov2023-08-23 15:44:33 +0300
commitf8ac2f39dbce6c523a61971da804bccf28ecae8a (patch)
tree9a3d2feb8dffec004ac9ef2853ab568113664c49
parente0225bc87f36161090e1954cefd6611e0f534a8a (diff)
Dynamic feeds WIPx
-rw-r--r--src/main/assets/scripts.js48
-rw-r--r--src/main/resources/templates/layouts/default.html30
-rw-r--r--src/main/resources/templates/views/index.html4
-rw-r--r--vnext/src/ui/Avatar.js9
-rw-r--r--vnext/src/ui/Feeds.js2
-rw-r--r--vnext/src/ui/Message.js31
-rw-r--r--vnext/src/ui/UserInfo.js23
-rw-r--r--vnext/src/utils/embed.js4
8 files changed, 88 insertions, 63 deletions
diff --git a/src/main/assets/scripts.js b/src/main/assets/scripts.js
index 94f79424..2acc5502 100644
--- a/src/main/assets/scripts.js
+++ b/src/main/assets/scripts.js
@@ -6,6 +6,12 @@ import 'core-js/stable'
import { embedLinksToX, embedAll, format } from '../../../vnext/src/utils/embed'
import renderIcons from './icon'
import svg4everybody from 'svg4everybody'
+import { createRoot } from 'react-dom/client'
+import { useState, useEffect } from 'react'
+
+import Message from '../../../vnext/src/ui/Message'
+import { VisitorProvider } from '../../../vnext/src/ui/VisitorContext'
+import { CookiesProvider } from 'react-cookie'
/**
* Autosize textarea
@@ -590,6 +596,31 @@ function notificationsCheckPermissions(button) {
}
}
+const Feed = () => {
+ const [messages, setMessages] = useState(/** @type { import('../../../vnext/src/api').Message[]? } */ (null))
+ useEffect(() => {
+ let url = new URL(window.location.href)
+ fetch(url, {
+ headers: {
+ 'Accept': 'application/json'
+ },
+ credentials: 'same-origin'
+ })
+ .then(response => response.json())
+ .then(json => {
+ setMessages(json)
+ })
+ .catch(console.error)
+ }, [])
+ return messages ? (
+ <>
+ {
+ messages.map(message => <Message key={message.mid} data={message} isThread={false} onToggleSubscription={() => {}} /> )
+ }
+ </>
+ ) : 'Loading...'
+}
+
/******************************************************************************/
function ready(fn) {
@@ -601,12 +632,6 @@ function ready(fn) {
}
ready(() => {
- elementClosest(window)
- Array.from(document.querySelectorAll('textarea')).forEach((ta) => {
- autosize(ta)
- })
- svg4everybody()
- renderIcons()
var insertPMButtons = function(e) {
e.target.classList.add('narrowpm')
e.target.parentNode.insertAdjacentHTML('afterend', '<input type="submit" class="Button" value="OK"/>')
@@ -629,6 +654,10 @@ ready(() => {
if (content) {
var pageMID = +content.getAttribute('data-mid')
if (pageMID > 0) {
+ embedAll()
+ Array.from(document.querySelectorAll('textarea')).forEach((ta) => {
+ autosize(ta)
+ })
Array.from(document.querySelectorAll('li.msg')).forEach(li => {
let showReplyFormBtn = li.querySelector('.a-thread-comment')
if (showReplyFormBtn) {
@@ -823,7 +852,6 @@ ready(() => {
es.close()
}
})
- embedAll()
const button = document.getElementById('notifications_toggle')
if (button) {
button.addEventListener('click', () => {
@@ -831,4 +859,10 @@ ready(() => {
})
notificationsCheckPermissions(button)
}
+ let root = document.getElementById('feed')
+ createRoot(root).render(
+ <VisitorProvider>
+ <Feed />
+ </VisitorProvider>
+ )
})
diff --git a/src/main/resources/templates/layouts/default.html b/src/main/resources/templates/layouts/default.html
index c3dac5d4..77bdac9b 100644
--- a/src/main/resources/templates/layouts/default.html
+++ b/src/main/resources/templates/layouts/default.html
@@ -15,24 +15,24 @@
<meta property="fb:app_id" content="130568668304" />
<meta property="fb:pages" content="270127573154958" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
- <meta name="msapplication-config" content="//i.juick.com/browserconfig.xml" />
+ <meta name="msapplication-config" content="https://i.juick.com/browserconfig.xml" />
<meta name="msapplication-TileColor" content="#ffffff" />
- <meta name="msapplication-TileImage" content="//i.juick.com/ms-icon-144x144.png" />
+ <meta name="msapplication-TileImage" content="https://i.juick.com/ms-icon-144x144.png" />
<meta name="theme-color" content="#ffffff" />
<meta name="apple-mobile-web-app-capable" content="yes" />
- <link rel="apple-touch-icon" sizes="57x57" href="//i.juick.com/apple-icon-57x57.png" />
- <link rel="apple-touch-icon" sizes="60x60" href="//i.juick.com/apple-icon-60x60.png" />
- <link rel="apple-touch-icon" sizes="72x72" href="//i.juick.com/apple-icon-72x72.png" />
- <link rel="apple-touch-icon" sizes="76x76" href="//i.juick.com/apple-icon-76x76.png" />
- <link rel="apple-touch-icon" sizes="114x114" href="//i.juick.com/apple-icon-114x114.png" />
- <link rel="apple-touch-icon" sizes="120x120" href="//i.juick.com/apple-icon-120x120.png" />
- <link rel="apple-touch-icon" sizes="144x144" href="//i.juick.com/apple-icon-144x144.png" />
- <link rel="apple-touch-icon" sizes="152x152" href="//i.juick.com/apple-icon-152x152.png" />
- <link rel="apple-touch-icon" sizes="180x180" href="//i.juick.com/apple-icon-180x180.png" />
- <link rel="icon" type="image/png" sizes="32x32" href="//i.juick.com/favicon-32x32.png" />
- <link rel="icon" type="image/png" sizes="96x96" href="//i.juick.com/favicon-96x96.png" />
- <link rel="icon" type="image/png" sizes="16x16" href="//i.juick.com/favicon-16x16.png" />
- <link rel="manifest" href="//i.juick.com/manifest.json" />
+ <link rel="apple-touch-icon" sizes="57x57" href="https://i.juick.com/apple-icon-57x57.png" />
+ <link rel="apple-touch-icon" sizes="60x60" href="https://i.juick.com/apple-icon-60x60.png" />
+ <link rel="apple-touch-icon" sizes="72x72" href="https://i.juick.com/apple-icon-72x72.png" />
+ <link rel="apple-touch-icon" sizes="76x76" href="https://i.juick.com/apple-icon-76x76.png" />
+ <link rel="apple-touch-icon" sizes="114x114" href="https://i.juick.com/apple-icon-114x114.png" />
+ <link rel="apple-touch-icon" sizes="120x120" href="https://i.juick.com/apple-icon-120x120.png" />
+ <link rel="apple-touch-icon" sizes="144x144" href="https://i.juick.com/apple-icon-144x144.png" />
+ <link rel="apple-touch-icon" sizes="152x152" href="https://i.juick.com/apple-icon-152x152.png" />
+ <link rel="apple-touch-icon" sizes="180x180" href="https://i.juick.com/apple-icon-180x180.png" />
+ <link rel="icon" type="image/png" sizes="32x32" href="https://i.juick.com/favicon-32x32.png" />
+ <link rel="icon" type="image/png" sizes="96x96" href="https://i.juick.com/favicon-96x96.png" />
+ <link rel="icon" type="image/png" sizes="16x16" href="https://i.juick.com/favicon-16x16.png" />
+ <link rel="manifest" href="https://i.juick.com/manifest.json" />
</head>
<body id="body" {% if visitor.uid > 0 %}data-hash="{{visitor.authHash}}"{% endif %}>
diff --git a/src/main/resources/templates/views/index.html b/src/main/resources/templates/views/index.html
index e85a3aa1..acb4685a 100644
--- a/src/main/resources/templates/views/index.html
+++ b/src/main/resources/templates/views/index.html
@@ -4,9 +4,7 @@
{% if noindex %}
<!--noindex-->
{% endif %}
-{% for msg in msgs %}
-{% include "views/partial/message" %}
-{% endfor %}
+<div id="feed">...</div>
{% if nextpage | default('') is not empty %}
<p class="page"><a href="{{ nextpage | raw }}" rel="prev">{{ i18n("messages","messages.next") }} →</a></p>
{% endif %}
diff --git a/vnext/src/ui/Avatar.js b/vnext/src/ui/Avatar.js
index 1a8db0c3..20e4e133 100644
--- a/vnext/src/ui/Avatar.js
+++ b/vnext/src/ui/Avatar.js
@@ -1,5 +1,4 @@
import { memo } from 'react'
-import { Link } from 'react-router-dom'
import Icon from './Icon'
@@ -21,19 +20,19 @@ function Avatar({ user, style, link, children }) {
<div className="msg-avatar">
{
user.uname ?
- <Link to={{ pathname: link || `/${user.uname}/` }}>
+ <a href={ link || `/${user.uname}/` }>
{user.avatar ?
<img src={user.avatar} alt={`${user.uname}`} />
: <Icon name="ei-spinner" size="m" />}
- </Link>
+ </a>
: <Icon name="ei-spinner" size="m" />
}
</div>
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
<span>
- <Link to={{ pathname: link || `/${user.uname}/` }}>
+ <a href={ link || `/${user.uname}/` }>
<span>{user.uname}</span>
- </Link>
+ </a>
</span>
{children}
</div>
diff --git a/vnext/src/ui/Feeds.js b/vnext/src/ui/Feeds.js
index 086a910e..51e0209e 100644
--- a/vnext/src/ui/Feeds.js
+++ b/vnext/src/ui/Feeds.js
@@ -216,7 +216,7 @@ function Feed({ query }) {
}
{
state.msgs.map(msg =>
- <Message key={msg.mid} data={msg} visitor={visitor} />)
+ <Message key={msg.mid} data={msg} />)
}
{
state.msgs.length >= 20 && (
diff --git a/vnext/src/ui/Message.js b/vnext/src/ui/Message.js
index e4135700..ec9af46f 100644
--- a/vnext/src/ui/Message.js
+++ b/vnext/src/ui/Message.js
@@ -6,7 +6,6 @@ dayjs.extend(utc)
import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)
-import { Link } from 'react-router-dom'
import Icon from './Icon'
import Avatar from './Avatar'
import { UserLink } from './UserInfo'
@@ -63,19 +62,17 @@ export default function Message({ data, isThread, onToggleSubscription, children
data.user &&
<Avatar user={data.user}>
<div className="msg-ts">
- <Link to={`/${data.user.uname}/${data.mid}`} state={{ data: data }}>
+ <a href={`/${data.user.uname}/${data.mid}`}>
<time dateTime={data.timestamp}
title={dayjs.utc(data.timestamp).local().format('lll')}>
{dayjs.utc(data.timestamp).fromNow()}
</time>
- </Link>
+ </a>
{
visitor.uid == data.user.uid &&
<>
<span>&nbsp;&middot;&nbsp;</span>
- <Link to={{
- pathname: '/post',
- }} state={{ data: data }}>Edit</Link>
+ <a href={'/post'}>Edit</a>
</>
}
</div>
@@ -101,21 +98,20 @@ export default function Message({ data, isThread, onToggleSubscription, children
{canComment &&
<nav className="l">
{data.user && visitor.uid === data.user.uid ? (
- <Link to={`/${data.user.uname}/${data.mid}`} className="a-like msg-button"
- state={{ data: data }}>
+ <a href={`/${data.user.uname}/${data.mid}`} className="a-like msg-button">
<Icon name="ei-heart" size="s" />
<span>{likesSummary}</span>
- </Link>
+ </a>
) : visitor.uid > 0 ? (
- <Link to={'/post'} className="a-like msg-button">
+ <a href={'/post'} className="a-like msg-button">
<Icon name="ei-heart" size="s" />
<span>{likesSummary}</span>
- </Link>
+ </a>
) : (
- <Link to="/login" className="a-login msg-button">
+ <a href="/login" className="a-login msg-button">
<Icon name="ei-heart" size="s" />
<span>{likesSummary}</span>
- </Link>
+ </a>
)}
{
data.user && canComment && ((
@@ -131,11 +127,10 @@ export default function Message({ data, isThread, onToggleSubscription, children
</>)}
</a>
) : (
- <Link to={`/${data.user.uname}/${data.mid}`} className="a-comment msg-button"
- state={{ data: data }}>
+ <a href={`/${data.user.uname}/${data.mid}`} className="a-comment msg-button">
<Icon name="ei-comment" size="s" />
<span>{commentsSummary}</span>
- </Link>
+ </a>
)
))
}
@@ -164,9 +159,9 @@ function Tags({ data, user }) {
data.map((tag, index) => (
<Fragment key={tag}>
{index > 0 && ' '}
- <Link key={tag} to={`/${user.uname}?tag=${tag}`} title={tag}>
+ <a key={tag} href={`/${user.uname}?tag=${tag}`} title={tag}>
{tag}
- </Link>
+ </a>
</Fragment>
))
}
diff --git a/vnext/src/ui/UserInfo.js b/vnext/src/ui/UserInfo.js
index f71dfcdc..ac9c6c69 100644
--- a/vnext/src/ui/UserInfo.js
+++ b/vnext/src/ui/UserInfo.js
@@ -1,5 +1,4 @@
import { memo, useState, useEffect, useRef } from 'react'
-import { Link } from 'react-router-dom'
import { info, fetchUserUri } from '../api'
@@ -42,18 +41,18 @@ export default function UserInfo({ uname, onUpdate, children }) {
{
user.uid > 0 &&
<>
- <Link to={`/pm/${user.uname}`}>
+ <a href={`/pm/${user.uname}`}>
<Icon name="ei-envelope" size="s" />
<span className="desktop">PM</span>
- </Link>
- <Link to={`/${user.uname}/?show=recomm`} rel="nofollow">
+ </a>
+ <a href={`/${user.uname}/?show=recomm`} rel="nofollow">
<Icon name="ei-heart" size="s" />
<span className="desktop">Recommendations</span>
- </Link>
- <Link to={`/${user.uname}/?media=1`} rel="nofollow">
+ </a>
+ <a href={`/${user.uname}/?media=1`} rel="nofollow">
<Icon name="ei-camera" size="s" />
<span className="desktop">Photos</span>
- </Link>
+ </a>
</>
}
</div>
@@ -70,9 +69,9 @@ function Summary({ user }) {
const readUrl = `/${user.uname}/friends`
const readersUrl = `/${user.uname}/readers`
const blUrl = `/${user.uname}/bl`
- let read = user.read && <Link key={readUrl} to={readUrl}>I read: {user.read.length}</Link>
- let readers = user.readers && <Link key={readersUrl} to={readersUrl}>My readers: {user.readers.length}</Link>
- let mybl = user.statsMyBL && <Link key={blUrl} to={blUrl}>My blacklist: {user.statsMyBL}</Link>
+ let read = user.read && <a key={readUrl} href={readUrl}>I read: {user.read.length}</a>
+ let readers = user.readers && <a key={readersUrl} href={readersUrl}>My readers: {user.readers.length}</a>
+ let mybl = user.statsMyBL && <a key={blUrl} href={blUrl}>My blacklist: {user.statsMyBL}</a>
let presentItems = [read, readers, mybl].filter(Boolean)
return (
<div className="msg-summary">
@@ -119,9 +118,9 @@ export function UserLink(props) {
}, [props.user])
return (
user.uid ?
- <Link key={user.uid} to={`/${user.uname}/`} className="info-avatar">
+ <a key={user.uid} href={`/${user.uname}/`} className="info-avatar">
<img src={user.avatar} />{user.uname}
- </Link>
+ </a>
: <a href={user.uri} className="info-avatar">
<img src={user.avatar || defaultAvatar} />{user.uname}
</a>
diff --git a/vnext/src/utils/embed.js b/vnext/src/utils/embed.js
index 3020058a..19636a5a 100644
--- a/vnext/src/utils/embed.js
+++ b/vnext/src/utils/embed.js
@@ -223,7 +223,7 @@ function getEmbeddableLinkTypes() {
let [, v, args, plist] = reResult
let iframeUrl
if (plist) {
- iframeUrl = '//www.youtube-nocookie.com/embed/videoseries?list=' + plist
+ iframeUrl = 'https://www.youtube-nocookie.com/embed/videoseries?list=' + plist
} else {
let pp = {}; args.replace(/^\?/, '')
.split('&')
@@ -246,7 +246,7 @@ function getEmbeddableLinkTypes() {
let argsStr = Object.keys(embedArgs)
.map(k => `${k}=${embedArgs[k]}`)
.join('&')
- iframeUrl = `//www.youtube-nocookie.com/embed/${v}?${argsStr}`
+ iframeUrl = `https://www.youtube-nocookie.com/embed/${v}?${argsStr}`
}
let iframe = makeIframe(iframeUrl, '100%', '360px')
iframe.onload = () => makeResizableToRatio(iframe, 9.0 / 16.0)