Merge branch 'upstream'

This commit is contained in:
Natsu Kagami 2023-08-01 17:18:03 +07:00
commit 3a8c13feac
Signed by: nki
GPG key ID: 55A032EB38B49ADB
12 changed files with 551 additions and 668 deletions

View file

@ -16,7 +16,7 @@
src = lib.cleanSource ./.;
npmDepsHash = "sha256-gkB7eb9/B3T5fNlF333CqRX8xh9a5EeOHOjlnIaf/Rw=";
npmDepsHash = "sha256-cgPhN3hlVob1V4cBQohfLykHqVCHcLOdGv+g5QC19Uc=";
# npmDepsHash = lib.fakeHash;
# DTTH-specific env variables

870
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -42,12 +42,12 @@
},
"devDependencies": {
"@preact/preset-vite": "~2.5.0",
"@trivago/prettier-plugin-sort-imports": "~4.1.1",
"postcss": "~8.4.26",
"@trivago/prettier-plugin-sort-imports": "~4.2.0",
"postcss": "~8.4.27",
"postcss-dark-theme-class": "~0.7.3",
"postcss-preset-env": "~9.0.0",
"postcss-preset-env": "~9.1.0",
"twitter-text": "~3.1.0",
"vite": "~4.4.4",
"vite": "~4.4.7",
"vite-plugin-generate-file": "~0.0.4",
"vite-plugin-html-config": "~1.0.11",
"vite-plugin-pwa": "~0.16.4",

View file

@ -264,7 +264,9 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
.timeline.contextual > li.descendant {
padding-bottom: 1em;
}
.timeline.contextual > li.descendant:not(.thread) > .status-link {
.timeline.contextual
> li.descendant:not(.thread)
> :is(.status-link, .status-focus) {
padding-left: 40px;
}
.timeline.contextual .replies[data-scroll-left]:not([data-scroll-left='0']) {
@ -292,7 +294,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
}
.timeline.contextual
> li.descendant.thread
> .status-link
> :is(.status-link, .status-focus)
+ .replies
.replies-summary {
margin-left: calc(
@ -325,9 +327,9 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
} */
.timeline.contextual
> li.descendant.thread
> .status-link
> :is(.status-link, .status-focus)
+ .replies
.status-link {
:is(.status-link, .status-focus) {
padding-left: calc(
var(--avatar-size) + var(--avatar-margin-start) + var(--avatar-margin-end) +
(var(--line-margin-end) * (var(--comments-level) - 1))
@ -358,7 +360,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
} */
.timeline.contextual
> li.descendant:not(.thread)
> .status-link
> :is(.status-link, .status-focus)
+ .replies
.replies-summary {
margin-left: calc(
@ -388,9 +390,9 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
} */
.timeline.contextual
> li.descendant:not(.thread)
> .status-link
> :is(.status-link, .status-focus)
+ .replies
.status-link {
:is(.status-link, .status-focus) {
padding-left: calc(
var(--thread-start) + var(--line-margin-end) * var(--comments-level)
);
@ -437,7 +439,10 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
var(--avatar-size) + var(--avatar-margin-start) + var(--avatar-margin-end)
);
}
.timeline.contextual > li.thread > .status-link .replies-link {
.timeline.contextual
> li.thread
> :is(.status-link, .status-focus)
.replies-link {
margin-left: calc(
var(--avatar-size) + var(--avatar-margin-start) + var(--avatar-margin-end)
);
@ -654,7 +659,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
}
.timeline:not(.flat)
> li.timeline-item-diff-author
> .status-link
> :is(.status-link, .status-focus)
> .status
> a
> .avatar {
@ -712,6 +717,14 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
animation: appear 0.2s ease-out;
-webkit-touch-callout: none;
}
@media (pointer: coarse) {
.status-focus:not(.hero .status-focus) {
/* Only the hero doesn't have context menu */
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
}
}
:is(.status-link, .status-focus):is(:focus, .is-active) {
background-color: var(--link-bg-hover-color);
outline-offset: -2px;
@ -2000,7 +2013,7 @@ ul.link-list li a .icon {
transform: none;
pointer-events: auto;
}
#columns li:has(.status-carousel) {
#columns li.timeline-item-carousel {
width: auto;
transform: none;
}
@ -2066,6 +2079,12 @@ ul.link-list li a .icon {
border-radius: 999px;
}
/* NOTIFICATION PEEK */
.notification-peek .notification {
padding-inline: 0 !important;
}
/* OTHERS */
@media (min-width: 40em) {
@ -2159,7 +2178,7 @@ ul.link-list li a .icon {
/* :is(.carousel-top-controls, .carousel-controls) {
padding: 32px;
} */
li:has(.status-carousel) {
li.timeline-item-carousel {
width: 95vw;
max-width: calc(320px * 3.3);
transform: translateX(calc(-50% + 20em));

View file

@ -116,6 +116,13 @@ function Media({ media, to, showOriginal, autoAnimate, onClick = () => {} }) {
if (smaller) setImageSmallerThanParent(smaller);
}, [width, height]);
const mediaStyles = {
'--width': `${width}px`,
'--height': `${height}px`,
aspectRatio: `${width} / ${height}`,
};
const fixedWidth = width > height * 2;
if (isImage) {
// Note: type: unknown might not have width/height
quickPinchZoomProps.containerProps.style.display = 'inherit';
@ -136,15 +143,18 @@ function Media({ media, to, showOriginal, autoAnimate, onClick = () => {} }) {
return (
<Parent
ref={parentRef}
class={`media media-image`}
class={`media media-image ${fixedWidth ? 'media-fixed-width' : ''}`}
onClick={onClick}
data-orientation={orientation}
style={
showOriginal && {
backgroundImage: `url(${previewUrl})`,
backgroundSize: imageSmallerThanParent
? `${width}px ${height}px`
: undefined,
}
showOriginal
? {
backgroundImage: `url(${previewUrl})`,
backgroundSize: imageSmallerThanParent
? `${width}px ${height}px`
: undefined,
}
: mediaStyles
}
>
{showOriginal ? (
@ -183,6 +193,13 @@ function Media({ media, to, showOriginal, autoAnimate, onClick = () => {} }) {
backgroundColor:
rgbAverageColor && `rgb(${rgbAverageColor.join(',')})`,
backgroundPosition: focalBackgroundPosition || 'center',
// Duration based on width or height in pixels
// 100px per second (rough estimate)
// Clamp between 5s and 120s
'--anim-duration': `${Math.min(
Math.max(Math.max(width, height) / 100, 5),
120,
)}s`,
}}
onLoad={(e) => {
e.target.closest('.media-image').style.backgroundImage = '';
@ -228,13 +245,15 @@ function Media({ media, to, showOriginal, autoAnimate, onClick = () => {} }) {
<Parent
class={`media media-${isGIF ? 'gif' : 'video'} ${
autoGIFAnimate ? 'media-contain' : ''
}`}
} ${fixedWidth ? 'media-fixed-width' : ''}`}
data-orientation={orientation}
data-formatted-duration={formattedDuration}
data-label={isGIF && !showOriginal && !autoGIFAnimate ? 'GIF' : ''}
// style={{
// backgroundColor:
// rgbAverageColor && `rgb(${rgbAverageColor.join(',')})`,
// }}
style={!showOriginal && mediaStyles}
onClick={(e) => {
if (hoverAnimate) {
try {
@ -314,6 +333,7 @@ function Media({ media, to, showOriginal, autoAnimate, onClick = () => {} }) {
class="media media-audio"
data-formatted-duration={formattedDuration}
onClick={onClick}
style={!showOriginal && mediaStyles}
>
{showOriginal ? (
<audio src={remoteUrl || url} preload="none" controls autoplay />

View file

@ -196,44 +196,43 @@ export default function Poll({
)}
</form>
)}
{!readOnly && (
<p class="poll-meta">
{!expired && (
<>
<button
type="button"
class="textual"
disabled={uiState === 'loading'}
onClick={(e) => {
e.preventDefault();
setUIState('loading');
<p class="poll-meta">
{!expired && !readOnly && (
<>
<button
type="button"
class="textual"
disabled={uiState === 'loading'}
onClick={(e) => {
e.preventDefault();
setUIState('loading');
(async () => {
await refresh();
setUIState('default');
})();
}}
>
Refresh
</button>{' '}
&bull;{' '}
</>
)}
<span title={votesCount}>{shortenNumber(votesCount)}</span> vote
{votesCount === 1 ? '' : 's'}
{!!votersCount && votersCount !== votesCount && (
<>
{' '}
&bull;{' '}
<span title={votersCount}>{shortenNumber(votersCount)}</span>{' '}
voter
{votersCount === 1 ? '' : 's'}
</>
)}{' '}
&bull; {expired ? 'Ended' : 'Ending'}{' '}
{!!expiresAtDate && <RelativeTime datetime={expiresAtDate} />}
</p>
)}
(async () => {
await refresh();
setUIState('default');
})();
}}
>
Refresh
</button>{' '}
&bull;{' '}
</>
)}
<span title={votesCount}>{shortenNumber(votesCount)}</span> vote
{votesCount === 1 ? '' : 's'}
{!!votersCount && votersCount !== votesCount && (
<>
{' '}
&bull; <span title={votersCount}>
{shortenNumber(votersCount)}
</span>{' '}
voter
{votersCount === 1 ? '' : 's'}
</>
)}{' '}
&bull; {expired ? 'Ended' : 'Ending'}{' '}
{!!expiresAtDate && <RelativeTime datetime={expiresAtDate} />}
</p>{' '}
</div>
);
}

View file

@ -87,6 +87,7 @@
}
.status-card-link:is(:hover, :focus) .status-card img {
animation: position-object 5s ease-in-out 1s 5;
animation-duration: var(--anim-duration, 5s);
}
.status-card-link:is(:active) .status-card {
background-color: var(--bg-faded-color);
@ -520,6 +521,10 @@
margin-inline: 0;
padding-inline-start: 1.5em;
}
.status .content > :is(ul, ol) li > :is(ul, ol),
.status .content > div > :is(ul, ol) li > :is(ul, ol) {
padding-inline-start: 1.5em;
}
.status .content ul {
list-style-type: disc;
}
@ -552,11 +557,11 @@
height: auto;
max-height: max(160px, 33vh);
}
/* .status .media-container.media-eq1 {
min-height: 44px;
height: auto;
max-height: 160px;
} */
.status .media-container.media-eq1 {
display: flex;
/* min-height: 0 !important; */
max-height: none !important;
}
.status:not(.large):not(.status-carousel .status)
.media-container.media-eq1:has([data-orientation='portrait']) {
width: 85%;
@ -569,43 +574,92 @@
}
.status.large :is(.media-container, .media-container.media-gt2) {
height: auto;
min-height: 160px;
/* min-height: 160px; */
max-height: 60vh;
}
.status .media-container .media {
--media-radius: 16px;
--media-radius-inner: 4px;
border-radius: var(--media-radius);
overflow: hidden;
min-height: 80px;
border: 1px solid var(--outline-color);
}
.status .media-container:not(.media-eq1) .media {
aspect-ratio: auto !important;
}
.status .media-container.media-eq1 {
width: auto !important;
max-width: 100%;
display: block;
}
.status .media-container.media-eq1 .media {
display: inline-block;
max-width: 100% !important;
min-width: 44px;
width: auto;
min-height: 44px;
/* width: min(var(--width), 100%); */
/* max-height: min(var(--height), 33vh); */
height: min(160px, var(--height), 33vh);
}
.status .media-container.media-eq1 .media.media-fixed-width {
width: min(var(--width), 100%);
height: auto;
max-height: min(var(--height), 33vh);
}
.status .media-container.media-eq1 .media[data-orientation='portrait'] {
width: auto;
height: min(var(--height), 45vh);
max-height: none;
}
.status.large .media-container.media-eq1 {
max-height: min(var(--height), 60vh);
}
.status.large .media-container.media-eq1 .media[data-orientation='portrait'] {
height: min(var(--height), 60vh);
}
.status-carousel .status .media-container.media-eq1 .media {
width: min(var(--width), 100%);
height: auto;
max-height: 60vh;
}
/* Special media borders */
.status .media-container.media-eq2 .media:first-of-type {
border-radius: var(--media-radius) 0 0 var(--media-radius);
border-radius: var(--media-radius) var(--media-radius-inner)
var(--media-radius-inner) var(--media-radius);
}
.status .media-container.media-eq2 .media:last-of-type {
border-radius: 0 var(--media-radius) var(--media-radius) 0;
border-radius: var(--media-radius-inner) var(--media-radius)
var(--media-radius) var(--media-radius-inner);
}
.status .media-container.media-eq3 .media:first-of-type {
border-radius: var(--media-radius) 0 0 var(--media-radius);
border-radius: var(--media-radius) var(--media-radius-inner)
var(--media-radius-inner) var(--media-radius);
}
.status .media-container.media-eq3 .media:nth-of-type(2) {
border-radius: 0 var(--media-radius) 0 0;
border-radius: var(--media-radius-inner) var(--media-radius)
var(--media-radius-inner) var(--media-radius-inner);
}
.status .media-container.media-eq3 .media:last-of-type {
border-radius: 0 0 var(--media-radius) 0;
border-radius: var(--media-radius-inner) var(--media-radius-inner)
var(--media-radius) var(--media-radius-inner);
}
.status .media-container.media-eq4 .media:first-of-type {
border-radius: var(--media-radius) 0 0 0;
border-radius: var(--media-radius) var(--media-radius-inner)
var(--media-radius-inner) var(--media-radius-inner);
}
.status .media-container.media-eq4 .media:nth-of-type(2) {
border-radius: 0 var(--media-radius) 0 0;
border-radius: var(--media-radius-inner) var(--media-radius)
var(--media-radius-inner) var(--media-radius-inner);
}
.status .media-container.media-eq4 .media:nth-of-type(3) {
border-radius: 0 0 0 var(--media-radius);
border-radius: var(--media-radius-inner) var(--media-radius-inner)
var(--media-radius-inner) var(--media-radius);
}
.status .media-container.media-eq4 .media:last-of-type {
border-radius: 0 0 var(--media-radius) 0;
border-radius: var(--media-radius-inner) var(--media-radius-inner)
var(--media-radius) var(--media-radius-inner);
}
.status .media:only-child {
grid-area: span 2 / span 2;
@ -613,7 +667,7 @@
.status:not(.large) .media:only-child {
max-width: 480px;
}
.status.large .media:only-child {
.status.large .media-container:not(.media-eq1) .media:only-child {
display: inline-block;
min-width: 160px;
min-height: 160px;
@ -646,6 +700,7 @@
width: 100%;
height: 100%;
object-fit: cover;
vertical-align: middle;
}
.status .media {
cursor: pointer;
@ -653,6 +708,7 @@
.status .media img:is(:hover, :focus),
a:focus-visible .status .media img {
animation: position-object 5s ease-in-out 1s 5;
animation-duration: var(--anim-duration, 5s);
}
body:has(#modal-container .carousel) .status .media img:hover {
animation: none;
@ -887,6 +943,7 @@ body:has(#modal-container .carousel) .status .media img:hover {
.card:is(:hover, :focus) img,
a:focus-visible .card img {
animation: position-object 5s ease-in-out 1s 5;
animation-duration: var(--anim-duration, 5s);
}
.card p {
margin: 0;
@ -975,6 +1032,7 @@ a.card:is(:hover, :focus) {
);
overflow: hidden;
box-shadow: inset 0 0 0 1px var(--bg-color);
min-width: 50%;
}
.poll.loading {
opacity: 0.5;

View file

@ -94,6 +94,7 @@ function Status({
allowFilters,
onMediaClick,
quoted,
onStatusLinkClick = () => {},
}) {
if (skeleton) {
return (
@ -172,7 +173,9 @@ function Status({
const debugHover = (e) => {
if (e.shiftKey) {
console.log(status);
console.log({
...status,
});
}
};
@ -524,7 +527,10 @@ function Status({
<br />
{createdDateText}
</MenuHeader>
<MenuLink to={instance ? `/${instance}/s/${id}` : `/s/${id}`}>
<MenuLink
to={instance ? `/${instance}/s/${id}` : `/s/${id}`}
onClick={onStatusLinkClick}
>
<Icon icon="arrow-right" />
<span>View post by @{username || acct}</span>
</MenuLink>
@ -942,6 +948,7 @@ function Status({
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onStatusLinkClick?.();
}}
class={`time ${open ? 'is-open' : ''}`}
>
@ -1127,7 +1134,9 @@ function Status({
}}
/>
)}
{(((enableTranslate || inlineTranslate) && !!content.trim() && differentLanguage) ||
{(((enableTranslate || inlineTranslate) &&
!!content.trim() &&
differentLanguage) ||
forceTranslate) && (
<TranslationBlock
forceTranslate={forceTranslate || inlineTranslate}

View file

@ -365,7 +365,10 @@ function Timeline({
return 0;
});
return (
<li key={`timeline-${statusID}`}>
<li
key={`timeline-${statusID}`}
class="timeline-item-carousel"
>
<StatusCarousel
title={title}
class={`${type}-carousel`}

View file

@ -111,18 +111,22 @@ function TranslationBlock({
detectedLang !== targetLangText
) {
return (
<div class="status-translation-block-mini">
<Icon
icon="translate"
alt={`Auto-translated from ${sourceLangText}`}
/>
<output
lang={targetLang}
dir="auto"
title={pronunciationContent || ''}
>
{translatedContent}
</output>
<div class="shazam-container">
<div class="shazam-container-inner">
<div class="status-translation-block-mini">
<Icon
icon="translate"
alt={`Auto-translated from ${sourceLangText}`}
/>
<output
lang={targetLang}
dir="auto"
title={pronunciationContent || ''}
>
{translatedContent}
</output>
</div>
</div>
</div>
);
}

View file

@ -843,6 +843,24 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
weight,
} = status;
const isHero = statusID === id;
const StatusParent = useCallback(
(props) =>
isThread || thread ? (
<Link
class="status-link"
to={
instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`
}
onClick={() => {
resetScrollPosition(statusID);
}}
{...props}
/>
) : (
<div class="status-focus" tabIndex={0} {...props} />
),
[isThread, thread],
);
return (
<li
key={statusID}
@ -923,15 +941,7 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
)}
</>
) : (
<Link
class="status-link"
to={
instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`
}
onClick={() => {
resetScrollPosition(statusID);
}}
>
<StatusParent>
<Status
statusID={statusID}
instance={instance}
@ -939,6 +949,9 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
size={thread || ancestor ? 'm' : 's'}
enableTranslate
onMediaClick={handleMediaClick}
onStatusLinkClick={() => {
resetScrollPosition(statusID);
}}
/>
{ancestor && isThread && repliesCount > 1 && (
<div class="replies-link">
@ -956,7 +969,7 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
</span>
</div>
)} */}
</Link>
</StatusParent>
)}
{descendant && replies?.length > 0 && (
<SubComments
@ -1171,13 +1184,14 @@ function SubComments({
<ul>
{replies.map((r) => (
<li key={r.id}>
<Link
{/* <Link
class="status-link"
to={instance ? `/${instance}/s/${r.id}` : `/s/${r.id}`}
onClick={() => {
resetScrollPosition(r.id);
}}
>
> */}
<div class="status-focus" tabIndex={0}>
<Status
statusID={r.id}
instance={instance}
@ -1194,7 +1208,8 @@ function SubComments({
</span>
</div>
)}
</Link>
</div>
{/* </Link> */}
{r.replies?.length && (
<SubComments
instance={instance}

View file

@ -1,7 +1,5 @@
const { locale } = Intl.NumberFormat().resolvedOptions();
export default function shortenNumber(num) {
return Intl.NumberFormat(locale, {
notation: 'compact',
}).format(num);
}
const shortenNumber = Intl.NumberFormat(locale, {
notation: 'compact',
}).format;
export default shortenNumber;