Reuse BoostCarousel for pinned posts
Now we can show *anything* into a carousel
This commit is contained in:
parent
a1edc142ae
commit
0430f4ae89
3 changed files with 85 additions and 54 deletions
47
src/app.css
47
src/app.css
|
@ -550,46 +550,44 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
||||||
filter: brightness(0.95);
|
filter: brightness(0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
.boost-carousel {
|
.status-carousel {
|
||||||
|
--carousel-faded-color: var(--bg-faded-color);
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
to bottom right,
|
to bottom right,
|
||||||
var(--reblog-faded-color),
|
var(--carousel-faded-color),
|
||||||
transparent 150%
|
transparent 150%
|
||||||
);
|
);
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.boost-carousel:after {
|
.status-carousel:after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background-image: radial-gradient(
|
background-image: radial-gradient(
|
||||||
ellipse 50% 32px at bottom center,
|
ellipse 50% 32px at bottom center,
|
||||||
var(--reblog-faded-color),
|
var(--carousel-faded-color),
|
||||||
transparent
|
transparent
|
||||||
),
|
),
|
||||||
linear-gradient(to top, var(--bg-color), transparent 64px);
|
linear-gradient(to top, var(--bg-color), transparent 64px);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: bottom center;
|
background-position: bottom center;
|
||||||
}
|
}
|
||||||
.boost-carousel .status-reblog {
|
.status-carousel header {
|
||||||
background-image: none;
|
|
||||||
}
|
|
||||||
.boost-carousel header {
|
|
||||||
padding: 8px 16px 0;
|
padding: 8px 16px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.boost-carousel h3 {
|
.status-carousel h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--reblog-color);
|
color: var(--carousel-color);
|
||||||
text-shadow: 0 1px var(--bg-color);
|
text-shadow: 0 1px var(--bg-color);
|
||||||
}
|
}
|
||||||
.boost-carousel ul {
|
.status-carousel ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
|
@ -601,7 +599,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
counter-reset: index;
|
counter-reset: index;
|
||||||
}
|
}
|
||||||
.boost-carousel ul > li {
|
.status-carousel ul > li {
|
||||||
scroll-snap-align: center;
|
scroll-snap-align: center;
|
||||||
scroll-snap-stop: always;
|
scroll-snap-stop: always;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
@ -616,12 +614,19 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
||||||
counter-increment: index;
|
counter-increment: index;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.boost-carousel ul > li:before {
|
.status-carousel.boosts-carousel {
|
||||||
|
--carousel-color: var(--reblog-color);
|
||||||
|
--carousel-faded-color: var(--reblog-faded-color);
|
||||||
|
}
|
||||||
|
.status-carousel.boosts-carousel .status-reblog {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.status-carousel.boosts-carousel ul > li:before {
|
||||||
content: counter(index);
|
content: counter(index);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: var(--reblog-color);
|
color: var(--carousel-color);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,7 +635,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-boost-link {
|
.status-carousel-link {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-decoration-line: none;
|
text-decoration-line: none;
|
||||||
|
@ -645,15 +650,15 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: 0 1px var(--bg-color);
|
box-shadow: 0 1px var(--bg-color);
|
||||||
}
|
}
|
||||||
.status-boost-link::focus {
|
.status-carousel-link::focus {
|
||||||
background-color: var(--link-bg-hover-color);
|
background-color: var(--link-bg-hover-color);
|
||||||
}
|
}
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
.status-boost-link:hover {
|
.status-carousel-link:hover {
|
||||||
background-color: var(--link-bg-hover-color);
|
background-color: var(--link-bg-hover-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.status-boost-link:active:not(:has(:is(.media, button):active)) {
|
.status-carousel-link:active:not(:has(:is(.media, button):active)) {
|
||||||
filter: brightness(0.95);
|
filter: brightness(0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1417,9 +1422,9 @@ ul.link-list li a .icon {
|
||||||
transform: translate3d(-2.5vw, 0, 0);
|
transform: translate3d(-2.5vw, 0, 0);
|
||||||
}
|
}
|
||||||
.timeline:not(.flat)
|
.timeline:not(.flat)
|
||||||
> li:not(:has(.boost-carousel)):has(+ li .status-link.is-active),
|
> li:not(:has(.status-carousel)):has(+ li .status-link.is-active),
|
||||||
.timeline:not(.flat)
|
.timeline:not(.flat)
|
||||||
> li:not(:has(.boost-carousel)):has(.status-link.is-active)
|
> li:not(:has(.status-carousel)):has(.status-link.is-active)
|
||||||
+ li {
|
+ li {
|
||||||
transition: var(--back-transition);
|
transition: var(--back-transition);
|
||||||
transform: translate3d(-1.25vw, 0, 0);
|
transform: translate3d(-1.25vw, 0, 0);
|
||||||
|
@ -1430,7 +1435,7 @@ ul.link-list li a .icon {
|
||||||
/* :is(.carousel-top-controls, .carousel-controls) {
|
/* :is(.carousel-top-controls, .carousel-controls) {
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
} */
|
} */
|
||||||
li:has(.boost-carousel) {
|
li:has(.status-carousel) {
|
||||||
width: 95vw;
|
width: 95vw;
|
||||||
max-width: calc(320px * 3.3);
|
max-width: calc(320px * 3.3);
|
||||||
transform: translateX(calc(-50% + 20em));
|
transform: translateX(calc(-50% + 20em));
|
||||||
|
|
|
@ -293,19 +293,51 @@ function Timeline({
|
||||||
<>
|
<>
|
||||||
<ul class="timeline">
|
<ul class="timeline">
|
||||||
{items.map((status) => {
|
{items.map((status) => {
|
||||||
const { id: statusID, reblog, boosts } = status;
|
const { id: statusID, reblog, items, type } = status;
|
||||||
const actualStatusID = reblog?.id || statusID;
|
const actualStatusID = reblog?.id || statusID;
|
||||||
const url = instance
|
const url = instance
|
||||||
? `/${instance}/s/${actualStatusID}`
|
? `/${instance}/s/${actualStatusID}`
|
||||||
: `/s/${actualStatusID}`;
|
: `/s/${actualStatusID}`;
|
||||||
if (boosts) {
|
let title = '';
|
||||||
|
if (type === 'boosts') {
|
||||||
|
title = `${items.length} Boosts`;
|
||||||
|
} else if (type === 'pinned') {
|
||||||
|
title = 'Pinned posts';
|
||||||
|
}
|
||||||
|
if (items) {
|
||||||
return (
|
return (
|
||||||
<li key={`timeline-${statusID}`}>
|
<li key={`timeline-${statusID}`}>
|
||||||
<BoostsCarousel
|
<StatusCarousel title={title} class={`${type}-carousel`}>
|
||||||
boosts={boosts}
|
{items.map((item) => {
|
||||||
useItemID={useItemID}
|
const { id: statusID, reblog } = item;
|
||||||
instance={instance}
|
const actualStatusID = reblog?.id || statusID;
|
||||||
/>
|
const url = instance
|
||||||
|
? `/${instance}/s/${actualStatusID}`
|
||||||
|
: `/s/${actualStatusID}`;
|
||||||
|
return (
|
||||||
|
<li key={statusID}>
|
||||||
|
<Link
|
||||||
|
class="status-carousel-link timeline-item-alt"
|
||||||
|
to={url}
|
||||||
|
>
|
||||||
|
{useItemID ? (
|
||||||
|
<Status
|
||||||
|
statusID={statusID}
|
||||||
|
instance={instance}
|
||||||
|
size="s"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Status
|
||||||
|
status={item}
|
||||||
|
instance={instance}
|
||||||
|
size="s"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</StatusCarousel>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -406,7 +438,10 @@ function groupBoosts(values) {
|
||||||
const boostStashID = boostStash.map((status) => status.id);
|
const boostStashID = boostStash.map((status) => status.id);
|
||||||
if (boostStash.length > (values.length * 3) / 4) {
|
if (boostStash.length > (values.length * 3) / 4) {
|
||||||
// insert boost array at the end of specialHome list
|
// insert boost array at the end of specialHome list
|
||||||
newValues = [...newValues, { id: boostStashID, boosts: boostStash }];
|
newValues = [
|
||||||
|
...newValues,
|
||||||
|
{ id: boostStashID, items: boostStash, type: 'boosts' },
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
// insert boosts array in the middle of specialHome list
|
// insert boosts array in the middle of specialHome list
|
||||||
const half = Math.floor(newValues.length / 2);
|
const half = Math.floor(newValues.length / 2);
|
||||||
|
@ -414,7 +449,8 @@ function groupBoosts(values) {
|
||||||
...newValues.slice(0, half),
|
...newValues.slice(0, half),
|
||||||
{
|
{
|
||||||
id: boostStashID,
|
id: boostStashID,
|
||||||
boosts: boostStash,
|
items: boostStash,
|
||||||
|
type: 'boosts',
|
||||||
},
|
},
|
||||||
...newValues.slice(half),
|
...newValues.slice(half),
|
||||||
];
|
];
|
||||||
|
@ -425,7 +461,7 @@ function groupBoosts(values) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function BoostsCarousel({ boosts, useItemID, instance }) {
|
function StatusCarousel({ title, class: className, children }) {
|
||||||
const carouselRef = useRef();
|
const carouselRef = useRef();
|
||||||
const { reachStart, reachEnd, init } = useScroll({
|
const { reachStart, reachEnd, init } = useScroll({
|
||||||
scrollableElement: carouselRef.current,
|
scrollableElement: carouselRef.current,
|
||||||
|
@ -436,9 +472,9 @@ function BoostsCarousel({ boosts, useItemID, instance }) {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="boost-carousel">
|
<div class={`status-carousel ${className}`}>
|
||||||
<header>
|
<header>
|
||||||
<h3>{boosts.length} Boosts</h3>
|
<h3>{title}</h3>
|
||||||
<span>
|
<span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -468,26 +504,7 @@ function BoostsCarousel({ boosts, useItemID, instance }) {
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
<ul ref={carouselRef}>
|
<ul ref={carouselRef}>{children}</ul>
|
||||||
{boosts.map((boost) => {
|
|
||||||
const { id: statusID, reblog } = boost;
|
|
||||||
const actualStatusID = reblog?.id || statusID;
|
|
||||||
const url = instance
|
|
||||||
? `/${instance}/s/${actualStatusID}`
|
|
||||||
: `/s/${actualStatusID}`;
|
|
||||||
return (
|
|
||||||
<li key={statusID}>
|
|
||||||
<Link class="status-boost-link timeline-item-alt" to={url}>
|
|
||||||
{useItemID ? (
|
|
||||||
<Status statusID={statusID} instance={instance} size="s" />
|
|
||||||
) : (
|
|
||||||
<Status status={boost} instance={instance} size="s" />
|
|
||||||
)}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,16 @@ function AccountStatuses() {
|
||||||
pinnedStatuses.forEach((status) => {
|
pinnedStatuses.forEach((status) => {
|
||||||
status._pinned = true;
|
status._pinned = true;
|
||||||
});
|
});
|
||||||
results.push(...pinnedStatuses);
|
if (pinnedStatuses.length > 1) {
|
||||||
|
const pinnedStatusesIds = pinnedStatuses.map((status) => status.id);
|
||||||
|
results.push({
|
||||||
|
id: pinnedStatusesIds,
|
||||||
|
items: pinnedStatuses,
|
||||||
|
type: 'pinned',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
results.push(...pinnedStatuses);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (firstLoad || !accountStatusesIterator.current) {
|
if (firstLoad || !accountStatusesIterator.current) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue