diff options
-rw-r--r-- | src/main/assets/scripts.js | 48 | ||||
-rw-r--r-- | src/main/resources/templates/layouts/default.html | 30 | ||||
-rw-r--r-- | src/main/resources/templates/views/index.html | 4 | ||||
-rw-r--r-- | vnext/src/ui/Avatar.js | 9 | ||||
-rw-r--r-- | vnext/src/ui/Feeds.js | 2 | ||||
-rw-r--r-- | vnext/src/ui/Message.js | 31 | ||||
-rw-r--r-- | vnext/src/ui/UserInfo.js | 23 | ||||
-rw-r--r-- | vnext/src/utils/embed.js | 4 |
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> · </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) |