Truncate long posts on timeline, show "Read more"
10-line clamping for now
This commit is contained in:
parent
734a9b2b76
commit
400bc6f696
74
package-lock.json
generated
74
package-lock.json
generated
|
@ -19,6 +19,7 @@
|
|||
"preact-router": "~4.1.0",
|
||||
"react-intersection-observer": "~9.4.1",
|
||||
"string-length": "~5.0.1",
|
||||
"use-resize-observer": "~9.1.0",
|
||||
"valtio": "~1.7.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -27,7 +28,7 @@
|
|||
"autoprefixer": "~10.4.13",
|
||||
"postcss": "~8.4.20",
|
||||
"postcss-dark-theme-class": "~0.7.3",
|
||||
"vite": "4.0.1"
|
||||
"vite": "~4.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
|
@ -848,6 +849,11 @@
|
|||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@juggle/resize-observer": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
|
||||
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
|
||||
},
|
||||
"node_modules/@preact/preset-vite": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.5.0.tgz",
|
||||
|
@ -1996,6 +2002,19 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-intersection-observer": {
|
||||
"version": "9.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz",
|
||||
|
@ -2042,6 +2061,15 @@
|
|||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
|
@ -2205,6 +2233,18 @@
|
|||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/use-resize-observer": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz",
|
||||
"integrity": "sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==",
|
||||
"dependencies": {
|
||||
"@juggle/resize-observer": "^3.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "16.8.0 - 18",
|
||||
"react-dom": "16.8.0 - 18"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||
|
@ -2836,6 +2876,11 @@
|
|||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"@juggle/resize-observer": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
|
||||
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
|
||||
},
|
||||
"@preact/preset-vite": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.5.0.tgz",
|
||||
|
@ -3702,6 +3747,16 @@
|
|||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.0"
|
||||
}
|
||||
},
|
||||
"react-intersection-observer": {
|
||||
"version": "9.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz",
|
||||
|
@ -3733,6 +3788,15 @@
|
|||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
|
@ -3847,6 +3911,14 @@
|
|||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"use-resize-observer": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz",
|
||||
"integrity": "sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==",
|
||||
"requires": {
|
||||
"@juggle/resize-observer": "^3.3.1"
|
||||
}
|
||||
},
|
||||
"use-sync-external-store": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"preact-router": "~4.1.0",
|
||||
"react-intersection-observer": "~9.4.1",
|
||||
"string-length": "~5.0.1",
|
||||
"use-resize-observer": "~9.1.0",
|
||||
"valtio": "~1.7.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -28,7 +29,7 @@
|
|||
"autoprefixer": "~10.4.13",
|
||||
"postcss": "~8.4.20",
|
||||
"postcss-dark-theme-class": "~0.7.3",
|
||||
"vite": "4.0.1"
|
||||
"vite": "~4.0.1"
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
|
|
|
@ -174,6 +174,30 @@
|
|||
.status .content {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.timeline-deck .status .content {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 10;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
.timeline-deck .status .content.truncated:after {
|
||||
content: attr(data-read-more);
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
inset-block-end: 0;
|
||||
inset-inline-end: 0;
|
||||
color: var(--link-color);
|
||||
background-color: var(--link-faded-color);
|
||||
backdrop-filter: blur(4px) brightness(2);
|
||||
padding: 0.5em 0.5em 0.5em 2em;
|
||||
border-radius: 0 1em 1em 0;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
mask-image: linear-gradient(to right, transparent, black 2em);
|
||||
}
|
||||
.status .content p {
|
||||
margin-block: 0.75em;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { getBlurHashAverageColor } from 'fast-blurhash';
|
|||
import mem from 'mem';
|
||||
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
|
||||
import { InView } from 'react-intersection-observer';
|
||||
import useResizeObserver from 'use-resize-observer';
|
||||
import { useSnapshot } from 'valtio';
|
||||
|
||||
import Loader from '../components/loader';
|
||||
|
@ -619,6 +620,34 @@ function Status({
|
|||
const carouselRef = useRef(null);
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
const spoilerContentRef = useRef(null);
|
||||
useResizeObserver({
|
||||
ref: spoilerContentRef,
|
||||
onResize: () => {
|
||||
if (spoilerContentRef.current) {
|
||||
const { scrollHeight, clientHeight } = spoilerContentRef.current;
|
||||
spoilerContentRef.current.classList.toggle(
|
||||
'truncated',
|
||||
scrollHeight > clientHeight,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
const contentRef = useRef(null);
|
||||
useResizeObserver({
|
||||
ref: contentRef,
|
||||
onResize: () => {
|
||||
if (contentRef.current) {
|
||||
const { scrollHeight, clientHeight } = contentRef.current;
|
||||
contentRef.current.classList.toggle(
|
||||
'truncated',
|
||||
scrollHeight > clientHeight,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
const readMoreText = 'read more →';
|
||||
|
||||
return (
|
||||
<div
|
||||
class={`status ${
|
||||
|
@ -714,7 +743,12 @@ function Status({
|
|||
>
|
||||
{!!spoilerText && sensitive && (
|
||||
<>
|
||||
<div class="content">
|
||||
<div
|
||||
class="content"
|
||||
lang={language}
|
||||
ref={spoilerContentRef}
|
||||
data-read-more={readMoreText}
|
||||
>
|
||||
<p>{spoilerText}</p>
|
||||
</div>
|
||||
<button
|
||||
|
@ -733,6 +767,9 @@ function Status({
|
|||
)}
|
||||
<div
|
||||
class="content"
|
||||
lang={language}
|
||||
ref={contentRef}
|
||||
data-read-more={readMoreText}
|
||||
onClick={(e) => {
|
||||
let { target } = e;
|
||||
if (target.parentNode.tagName.toLowerCase() === 'a') {
|
||||
|
|
Loading…
Reference in a new issue