mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-03-14 04:08:32 +03:00
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);
|
||||
}
|
||||
|
||||
.boost-carousel {
|
||||
.status-carousel {
|
||||
--carousel-faded-color: var(--bg-faded-color);
|
||||
background: linear-gradient(
|
||||
to bottom right,
|
||||
var(--reblog-faded-color),
|
||||
var(--carousel-faded-color),
|
||||
transparent 150%
|
||||
);
|
||||
position: relative;
|
||||
}
|
||||
.boost-carousel:after {
|
||||
.status-carousel:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background-image: radial-gradient(
|
||||
ellipse 50% 32px at bottom center,
|
||||
var(--reblog-faded-color),
|
||||
var(--carousel-faded-color),
|
||||
transparent
|
||||
),
|
||||
linear-gradient(to top, var(--bg-color), transparent 64px);
|
||||
background-repeat: no-repeat;
|
||||
background-position: bottom center;
|
||||
}
|
||||
.boost-carousel .status-reblog {
|
||||
background-image: none;
|
||||
}
|
||||
.boost-carousel header {
|
||||
.status-carousel header {
|
||||
padding: 8px 16px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.boost-carousel h3 {
|
||||
.status-carousel h3 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
color: var(--reblog-color);
|
||||
color: var(--carousel-color);
|
||||
text-shadow: 0 1px var(--bg-color);
|
||||
}
|
||||
.boost-carousel ul {
|
||||
.status-carousel ul {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
@ -601,7 +599,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
|||
align-items: flex-start;
|
||||
counter-reset: index;
|
||||
}
|
||||
.boost-carousel ul > li {
|
||||
.status-carousel ul > li {
|
||||
scroll-snap-align: center;
|
||||
scroll-snap-stop: always;
|
||||
flex-shrink: 0;
|
||||
|
@ -616,12 +614,19 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
|||
counter-increment: index;
|
||||
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);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
font-size: 10px;
|
||||
color: var(--reblog-color);
|
||||
color: var(--carousel-color);
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
|
@ -630,7 +635,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.status-boost-link {
|
||||
.status-carousel-link {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-decoration-line: none;
|
||||
|
@ -645,15 +650,15 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
|
|||
overflow: hidden;
|
||||
box-shadow: 0 1px var(--bg-color);
|
||||
}
|
||||
.status-boost-link::focus {
|
||||
.status-carousel-link::focus {
|
||||
background-color: var(--link-bg-hover-color);
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.status-boost-link:hover {
|
||||
.status-carousel-link:hover {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1417,9 +1422,9 @@ ul.link-list li a .icon {
|
|||
transform: translate3d(-2.5vw, 0, 0);
|
||||
}
|
||||
.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)
|
||||
> li:not(:has(.boost-carousel)):has(.status-link.is-active)
|
||||
> li:not(:has(.status-carousel)):has(.status-link.is-active)
|
||||
+ li {
|
||||
transition: var(--back-transition);
|
||||
transform: translate3d(-1.25vw, 0, 0);
|
||||
|
@ -1430,7 +1435,7 @@ ul.link-list li a .icon {
|
|||
/* :is(.carousel-top-controls, .carousel-controls) {
|
||||
padding: 32px;
|
||||
} */
|
||||
li:has(.boost-carousel) {
|
||||
li:has(.status-carousel) {
|
||||
width: 95vw;
|
||||
max-width: calc(320px * 3.3);
|
||||
transform: translateX(calc(-50% + 20em));
|
||||
|
|
|
@ -293,19 +293,51 @@ function Timeline({
|
|||
<>
|
||||
<ul class="timeline">
|
||||
{items.map((status) => {
|
||||
const { id: statusID, reblog, boosts } = status;
|
||||
const { id: statusID, reblog, items, type } = status;
|
||||
const actualStatusID = reblog?.id || statusID;
|
||||
const url = instance
|
||||
? `/${instance}/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 (
|
||||
<li key={`timeline-${statusID}`}>
|
||||
<BoostsCarousel
|
||||
boosts={boosts}
|
||||
useItemID={useItemID}
|
||||
instance={instance}
|
||||
/>
|
||||
<StatusCarousel title={title} class={`${type}-carousel`}>
|
||||
{items.map((item) => {
|
||||
const { id: statusID, reblog } = item;
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
@ -406,7 +438,10 @@ function groupBoosts(values) {
|
|||
const boostStashID = boostStash.map((status) => status.id);
|
||||
if (boostStash.length > (values.length * 3) / 4) {
|
||||
// insert boost array at the end of specialHome list
|
||||
newValues = [...newValues, { id: boostStashID, boosts: boostStash }];
|
||||
newValues = [
|
||||
...newValues,
|
||||
{ id: boostStashID, items: boostStash, type: 'boosts' },
|
||||
];
|
||||
} else {
|
||||
// insert boosts array in the middle of specialHome list
|
||||
const half = Math.floor(newValues.length / 2);
|
||||
|
@ -414,7 +449,8 @@ function groupBoosts(values) {
|
|||
...newValues.slice(0, half),
|
||||
{
|
||||
id: boostStashID,
|
||||
boosts: boostStash,
|
||||
items: boostStash,
|
||||
type: 'boosts',
|
||||
},
|
||||
...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 { reachStart, reachEnd, init } = useScroll({
|
||||
scrollableElement: carouselRef.current,
|
||||
|
@ -436,9 +472,9 @@ function BoostsCarousel({ boosts, useItemID, instance }) {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div class="boost-carousel">
|
||||
<div class={`status-carousel ${className}`}>
|
||||
<header>
|
||||
<h3>{boosts.length} Boosts</h3>
|
||||
<h3>{title}</h3>
|
||||
<span>
|
||||
<button
|
||||
type="button"
|
||||
|
@ -468,26 +504,7 @@ function BoostsCarousel({ boosts, useItemID, instance }) {
|
|||
</button>
|
||||
</span>
|
||||
</header>
|
||||
<ul ref={carouselRef}>
|
||||
{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>
|
||||
<ul ref={carouselRef}>{children}</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,16 @@ function AccountStatuses() {
|
|||
pinnedStatuses.forEach((status) => {
|
||||
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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue