Catch-up (beta)

This commit is contained in:
Lim Chee Aun 2024-02-26 14:02:58 +08:00
parent a419bb9b61
commit 201ca6ce4a
9 changed files with 2267 additions and 47 deletions

View file

@ -103,6 +103,10 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
max-width: 100%; max-width: 100%;
background-color: var(--bg-color); background-color: var(--bg-color);
overflow-anchor: auto; overflow-anchor: auto;
&.wide {
width: 60em;
}
} }
.deck.contained { .deck.contained {
overflow: auto; overflow: auto;

View file

@ -24,6 +24,7 @@ import Shortcuts from './components/shortcuts';
import NotFound from './pages/404'; import NotFound from './pages/404';
import AccountStatuses from './pages/account-statuses'; import AccountStatuses from './pages/account-statuses';
import Bookmarks from './pages/bookmarks'; import Bookmarks from './pages/bookmarks';
import Catchup from './pages/catchup';
import Favourites from './pages/favourites'; import Favourites from './pages/favourites';
import FollowedHashtags from './pages/followed-hashtags'; import FollowedHashtags from './pages/followed-hashtags';
import Following from './pages/following'; import Following from './pages/following';
@ -394,7 +395,7 @@ function PrimaryRoutes({ isLoggedIn, loading }) {
const location = useLocation(); const location = useLocation();
const nonRootLocation = useMemo(() => { const nonRootLocation = useMemo(() => {
const { pathname } = location; const { pathname } = location;
return !/^\/(login|welcome)/.test(pathname); return !/^\/(login|welcome)/i.test(pathname);
}, [location]); }, [location]);
return ( return (
@ -457,6 +458,7 @@ function SecondaryRoutes({ isLoggedIn }) {
<Route path=":id" element={<List />} /> <Route path=":id" element={<List />} />
</Route> </Route>
<Route path="/ft" element={<FollowedHashtags />} /> <Route path="/ft" element={<FollowedHashtags />} />
<Route path="/catchup" element={<Catchup />} />
</> </>
)} )}
<Route path="/:instance?/t/:hashtag" element={<Hashtag />} /> <Route path="/:instance?/t/:hashtag" element={<Hashtag />} />

View file

@ -12,7 +12,8 @@ body.cloak,
.account-container :is(header, main > *:not(.actions)), .account-container :is(header, main > *:not(.actions)),
.account-container :is(header, main > *:not(.actions)) *, .account-container :is(header, main > *:not(.actions)) *,
.header-double-lines, .header-double-lines,
.account-block { .account-block,
.post-peek-html * {
text-decoration-thickness: 1.1em; text-decoration-thickness: 1.1em;
text-decoration-line: line-through; text-decoration-line: line-through;
/* text-rendering: optimizeSpeed; */ /* text-rendering: optimizeSpeed; */
@ -26,9 +27,10 @@ body.cloak,
.status :is(img, video, audio), .status :is(img, video, audio),
.media-post .media, .media-post .media,
.avatar, .avatar *,
.emoji, .emoji,
.header-banner { .header-banner,
.post-peek-media {
filter: contrast(0) !important; filter: contrast(0) !important;
background-color: #000 !important; background-color: #000 !important;
} }

View file

@ -15,7 +15,7 @@
text-shadow: 0 1px var(--bg-blur-color); text-shadow: 0 1px var(--bg-blur-color);
transition: opacity 0.3s ease-out; transition: opacity 0.3s ease-out;
&:not(#columns &) { #trending-page &:not(#columns &) {
@media (min-width: 40em) { @media (min-width: 40em) {
width: 95vw; width: 95vw;
max-width: calc(320px * 3.3); max-width: calc(320px * 3.3);
@ -96,6 +96,7 @@
} }
article { article {
width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
@ -113,34 +114,34 @@
margin: 0 0 -16px; margin: 0 0 -16px;
padding: 0; padding: 0;
position: relative; position: relative;
}
img { img {
position: absolute; position: absolute;
inset: 0; inset: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
vertical-align: top; vertical-align: top;
mask-image: linear-gradient( mask-image: linear-gradient(
to bottom, to bottom,
hsl(0, 0%, 0%) 0%, hsl(0, 0%, 0%) 0%,
hsla(0, 0%, 0%, 0.987) 14%, hsla(0, 0%, 0%, 0.987) 14%,
hsla(0, 0%, 0%, 0.951) 26.2%, hsla(0, 0%, 0%, 0.951) 26.2%,
hsla(0, 0%, 0%, 0.896) 36.8%, hsla(0, 0%, 0%, 0.896) 36.8%,
hsla(0, 0%, 0%, 0.825) 45.9%, hsla(0, 0%, 0%, 0.825) 45.9%,
hsla(0, 0%, 0%, 0.741) 53.7%, hsla(0, 0%, 0%, 0.741) 53.7%,
hsla(0, 0%, 0%, 0.648) 60.4%, hsla(0, 0%, 0%, 0.648) 60.4%,
hsla(0, 0%, 0%, 0.55) 66.2%, hsla(0, 0%, 0%, 0.55) 66.2%,
hsla(0, 0%, 0%, 0.45) 71.2%, hsla(0, 0%, 0%, 0.45) 71.2%,
hsla(0, 0%, 0%, 0.352) 75.6%, hsla(0, 0%, 0%, 0.352) 75.6%,
hsla(0, 0%, 0%, 0.259) 79.6%, hsla(0, 0%, 0%, 0.259) 79.6%,
hsla(0, 0%, 0%, 0.175) 83.4%, hsla(0, 0%, 0%, 0.175) 83.4%,
hsla(0, 0%, 0%, 0.104) 87.2%, hsla(0, 0%, 0%, 0.104) 87.2%,
hsla(0, 0%, 0%, 0.049) 91.1%, hsla(0, 0%, 0%, 0.049) 91.1%,
hsla(0, 0%, 0%, 0.013) 95.3%, hsla(0, 0%, 0%, 0.013) 95.3%,
hsla(0, 0%, 0%, 0) 100% hsla(0, 0%, 0%, 0) 100%
); );
}
} }
} }
@ -187,5 +188,9 @@
overflow: hidden; overflow: hidden;
font-size: 90%; font-size: 90%;
} }
hr {
margin: 4px 0;
}
} }
} }

View file

@ -176,6 +176,10 @@ function NavMenu(props) {
<Icon icon="following" size="l" /> <span>Following</span> <Icon icon="following" size="l" /> <span>Following</span>
</MenuLink> </MenuLink>
)} )}
<MenuLink to="/catchup">
<Icon icon="history" />
<span>Catch-up</span>
</MenuLink>
<MenuLink to="/mentions"> <MenuLink to="/mentions">
<Icon icon="at" size="l" /> <span>Mentions</span> <Icon icon="at" size="l" /> <span>Mentions</span>
</MenuLink> </MenuLink>

832
src/pages/catchup.css Normal file
View file

@ -0,0 +1,832 @@
#catchup-page {
transform: none;
padding-bottom: 0 !important;
.deck {
background-color: var(--bg-faded-color);
}
/* Hide the shortcuts nav + adjustments */
~ :is(#shortcuts, #compose-button) {
display: none;
}
.timeline-deck {
margin-top: 0 !important;
}
header {
/* --margin-top: 8px !important; */
position: static;
}
h1 sup {
font-size: 12px;
text-transform: uppercase;
font-weight: 500;
color: var(--text-insignificant-color);
}
.catchup-start {
padding: 16px;
padding-top: 15vh;
text-align: center;
max-width: 40em;
margin-inline: auto;
.catchup-info {
animation: appear 0.3s ease-out;
display: flex;
gap: 0.25em;
align-items: center;
justify-content: center;
}
}
.catchup-prev {
margin: 2em auto;
padding: 1em;
width: fit-content;
color: var(--text-insignificant-color);
border-top: 1px solid var(--bg-color);
ul,
ul li {
margin: 0;
padding: 0;
list-style: none;
}
ul li {
display: flex;
margin-bottom: 8px;
align-items: center;
gap: 8px;
text-align: left;
justify-content: space-between;
a {
display: flex;
gap: 0.25em;
align-items: center;
}
}
}
}
.catchup-form {
display: inline-flex;
align-items: center;
gap: 16px;
padding: 16px 16px;
background-color: var(--link-bg-color);
border-radius: 32px;
flex-wrap: wrap;
* {
flex-grow: 1;
}
input[type='range'] {
accent-color: var(--link-color);
direction: rtl;
}
}
.catchup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
gap: 8px;
aside {
display: flex;
align-items: center;
gap: 8px;
font-size: 90%;
button[hidden] {
display: inline;
opacity: 0;
pointer-events: none;
}
}
}
.catchup-posts-viz-bar {
margin: 0 16px;
border-radius: 3px;
border: 1px solid var(--bg-color);
display: flex;
gap: 1px;
pointer-events: none;
justify-content: stretch;
height: 3px;
&:has(.post-dot:nth-child(320)) {
gap: 0;
}
.post-dot {
display: block;
width: 100%;
height: 3px;
border-radius: 3px;
opacity: 0.5;
background-color: var(--link-color);
transition: 0.25s ease-in-out;
transition-property: opacity, transform;
&.post-dot-highlight {
opacity: 1;
}
}
&:has(.post-dot:not(.post-dot-highlight)) .post-dot-highlight {
/* transform: scaleY(2); */
transform: scale3d(1, 2, 1);
}
}
.catchup-filters {
padding: 8px 16px;
display: flex;
/* flex-wrap: wrap; */
gap: 8px;
align-items: center;
overflow-x: auto;
overflow-y: hidden;
max-width: 100%;
mask-image: linear-gradient(
to right,
transparent,
black 16px calc(100% - 16px),
transparent
);
padding-inline-end: 25%;
.filter-label {
text-transform: uppercase;
font-size: 12px;
font-weight: 500;
color: var(--text-insignificant-color);
}
label {
font-size: 80%;
white-space: nowrap;
cursor: pointer;
user-select: none;
color: var(--text-insignificant-color);
position: relative;
select {
/* appearance: none;
background-color: var(--bg-faded-color);
color: var(--link-color);
border: 0;
border-radius: 12px; */
padding: 4px;
margin: 0;
}
input[type] {
left: 0;
position: absolute;
opacity: 0;
pointer-events: none;
}
&.filter-cat {
padding: 8px 12px;
background-color: var(--bg-blur-color);
border-radius: 24px;
display: inline-block;
display: flex;
align-items: center;
gap: 4px;
&:is(:hover, :focus) {
background-color: var(--link-bg-color);
}
&:has(:checked) {
color: var(--link-color);
background-color: var(--link-bg-color);
box-shadow: inset 0 0 0 2px var(--link-color);
}
.count {
font-size: 70%;
margin-left: 4px;
background-color: var(--bg-color);
padding: 4px 6px;
border-radius: 12px;
display: inline-block;
}
}
&.filter-author {
flex-direction: column;
padding: 0;
background-color: transparent;
position: relative;
width: 50px;
/* transition: filter 0.15s ease; */
.avatar {
margin-bottom: 2px;
/* transition: box-shadow 0.15s ease; */
}
&:is(:hover, :focus) {
filter: none;
.avatar {
box-shadow: 0 0 0 0.5px var(--bg-color),
0 0 0 3px var(--link-faded-color) !important;
img {
filter: none;
}
}
.count {
color: var(--text-color);
}
}
.avatar {
&.has-alpha {
border-radius: 2px;
}
img {
transition: filter 0.15s ease;
}
}
&:has(:checked) {
box-shadow: none;
filter: none;
.avatar {
box-shadow: 0 0 0 1px var(--bg-color), 0 0 0 3px var(--link-color);
}
.username {
color: var(--link-color);
font-weight: 500;
}
.count {
color: var(--link-color);
border-color: var(--link-color);
box-shadow: 0 0 0 1px var(--link-color);
}
}
.count {
position: absolute;
right: -4px;
top: -4px;
font-size: 10px;
background-color: var(--bg-color);
border-radius: 12px;
display: inline-block;
border: 1px solid var(--link-faded-color);
padding: 0 2px;
min-width: 16px;
min-height: 16px;
text-align: center;
line-height: 14px;
}
.username {
display: block;
width: 100%;
overflow: hidden;
text-align: center;
mask-image: linear-gradient(
to right,
black calc(100% - 0.5em),
transparent 100%
);
}
}
}
&:has(.filter-author :checked)
.filter-author:not(:has(:checked)):not(:is(:hover, :focus)) {
.avatar img {
filter: grayscale(1) contrast(2) opacity(0.5);
}
}
.radio-field-group {
display: flex;
border: 0;
padding: 0;
margin: 0;
border-radius: 4px;
overflow: hidden;
gap: 1px;
label {
padding: 4px 8px;
line-height: 2em;
min-width: 32px;
text-align: center;
background-color: var(--bg-blur-color);
margin: 0;
cursor: pointer;
&:is(:hover, :focus) {
background-color: var(--link-bg-color);
}
&:has(:checked) {
font-weight: 500;
color: var(--text-color);
background-color: var(--link-bg-color);
box-shadow: inset 0 -2px 0 var(--link-color);
}
&:has(:disabled) {
opacity: 0.5;
cursor: not-allowed;
}
}
}
}
.catchup-list {
margin: 0;
padding: 0;
list-style: none;
/* background-color: var(--bg-color); */
border-top: var(--hairline-width) solid var(--bg-faded-color);
--corner-radius: 8px;
@media (min-width: 40em) {
border-radius: var(--corner-radius);
/* border: var(--hairline-width) solid var(--outline-color); */
> li {
&:first-child > a {
border-top-left-radius: var(--corner-radius);
border-top-right-radius: var(--corner-radius);
}
&:last-child > a {
border-bottom-left-radius: var(--corner-radius);
border-bottom-right-radius: var(--corner-radius);
}
}
}
> li {
margin: 0 0 1px;
padding: 0;
list-style: none;
/* border-bottom: var(--hairline-width) solid var(--outline-color); */
&.separator {
height: 16px;
pointer-events: none;
@media (min-width: 40em) {
height: 32px;
}
}
@media (min-width: 40em) {
&.separator + li a {
border-top-left-radius: var(--corner-radius);
border-top-right-radius: var(--corner-radius);
}
&:has(+ .separator) a {
border-bottom-left-radius: var(--corner-radius);
border-bottom-right-radius: var(--corner-radius);
}
}
> a {
background-color: var(--bg-color);
text-decoration: none;
color: inherit;
display: block;
/* transition: background-color 0.3s ease; */
&:is(:hover, :focus) {
position: relative;
z-index: 1;
background-color: var(--bg-faded-color);
box-shadow: 0 8px 16px -8px var(--drop-shadow-color),
inset 0 1px var(--bg-color);
outline: 1px solid var(--outline-color);
text-shadow: 0 1px var(--bg-color);
}
&:active {
filter: brightness(0.95);
box-shadow: none;
text-shadow: none;
}
&:visited {
color: var(--outline-color);
*,
.post-peek-html * a[href] {
color: var(--outline-color) !important;
* {
color: var(--outline-color) !important;
}
}
}
}
}
.post-line {
border-radius: inherit;
animation: appear-smooth 0.3s ease-in-out both;
--pad: 16px;
min-height: 44px;
padding: var(--pad);
column-gap: calc(0.5 * var(--pad));
row-gap: 4px;
width: 100%;
/* display: flex;
flex-direction: column; */
display: grid;
grid-template-columns: 1fr auto;
grid-template-rows: auto auto;
grid-template-areas:
'author meta'
'content content';
/* align-items: center; */
background-image: linear-gradient(
160deg,
var(--post-bg-color),
transparent min(80px, 50%)
);
/* background-image: linear-gradient(
90deg,
var(--post-bg-color),
var(--post-bg-color) 8px,
transparent 8px
); */
@media (min-width: 40em) {
/* flex-direction: row;
align-items: center; */
grid-template-columns: auto 1fr auto;
grid-template-rows: 1fr;
grid-template-areas: 'author content meta';
}
&.reblog {
--post-bg-color: var(--reblog-faded-color);
}
&.group {
--post-bg-color: var(--group-faded-color);
}
&.reply-to {
--post-bg-color: var(--reply-to-faded-color);
}
&.followed-tags {
--post-bg-color: var(--hashtag-faded-color);
}
&.filtered {
filter: grayscale(1);
background-image: none;
.post-author {
opacity: 0.5;
}
}
&.visibility-direct {
--yellow-stripes: repeating-linear-gradient(
-45deg,
var(--reply-to-faded-color),
var(--reply-to-faded-color) 10px,
var(--reply-to-faded-color) 10px,
transparent 10px,
transparent 20px
);
background-image: var(--yellow-stripes);
}
.post-reblog-avatar {
display: flex;
gap: 4px;
align-items: center;
flex-shrink: 0;
.icon {
color: var(--reblog-color);
}
}
.post-author {
grid-area: author;
flex-shrink: 0;
white-space: nowrap;
overflow: hidden;
mask-image: linear-gradient(
to right,
black calc(100% - 1em),
transparent 100%
);
@media (min-width: 40em) {
--width: 25vw;
width: var(--width);
min-width: 9em;
max-width: 13em;
}
b {
font-weight: normal;
/* font-weight: 500; */
opacity: 0.7;
}
i {
opacity: 0.5;
}
}
}
> li:nth-child(10) ~ li .post-line {
animation: none;
}
.post-peek {
grid-area: content;
display: flex;
flex: 1;
column-gap: 8px;
row-gap: 4px;
align-self: stretch;
/* align-items: center; */
/* margin-left: 24px; */
flex-direction: row-reverse;
flex-wrap: wrap;
justify-content: flex-end;
/* CLOAK - uncomment when taking screenshots */
/* text-decoration-thickness: 1.1em;
text-decoration-line: line-through;
text-rendering: optimizeSpeed;
filter: opacity(0.5);
pointer-events: none;
img {
filter: contrast(0) !important;
background-color: #000 !important;
} */
.post-peek-content {
flex-shrink: 1;
flex-grow: 1;
flex-basis: 20em;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 1.3;
opacity: 0.9;
/* font-size: 0.9em; */
text-wrap: balance;
&:empty {
display: none;
}
.post-peek-html {
pointer-events: none;
* {
margin: 0;
padding: 0;
display: inline;
white-space: normal;
}
pre,
code {
font-size: 0.9em;
color: var(--green-color);
}
strong,
b {
font-weight: 500;
}
br {
content: ' ';
}
/* all block level elements */
p,
div,
blockquote,
h1,
h2,
h3,
h4,
h5,
h6,
li,
pre,
br {
&:after {
content: ' ';
}
}
br:after {
font-size: 0.75em;
content: ' ↵ ';
opacity: 0.35;
}
.ellipsis:after {
content: '...';
}
.invisible {
display: none;
}
/* Links are not clickable, so remove the underlines */
a {
text-decoration: none;
text-decoration-color: transparent;
color: var(--link-text-color);
}
}
.post-peek-spoiler {
line-height: 1.5;
border-radius: 1em;
padding-inline: 0.5em;
border: 1px dashed var(--button-bg-color);
.icon {
vertical-align: middle;
color: var(--button-bg-color);
}
}
.post-peek-filtered {
border-radius: 1em;
padding-inline: 0.5em;
border: 1px dashed var(--outline-hover-color);
.icon {
vertical-align: middle;
color: var(--outline-hover-color);
}
}
}
.post-peek-post-content {
flex-shrink: 0;
display: flex;
gap: 4px;
align-self: center;
transition: transform 0.05s ease-in-out;
&:empty {
display: none;
}
&:has(.post-peek-media):hover {
transform: scale(1.5);
}
img {
border-radius: 2px;
outline: var(--hairline-width) solid var(--outline-color);
vertical-align: middle;
object-fit: cover;
box-shadow: 0 0 0 1px var(--outline-color);
object-fit: cover;
transition: transform 0.05s ease-in-out;
background-color: var(--bg-color);
&:hover {
transform: scale(1.5);
position: relative;
z-index: 1;
animation: position-object 5s ease-in-out 5;
/* @media (min-width: 40em) and (min-height: 600px) {
transform: scale(3);
} */
}
}
@media (max-width: 40em) {
&:has(.post-peek-media),
.post-peek-media:first-child img {
transform-origin: left center;
}
}
.post-peek-faux-media {
width: 48px;
height: 48px;
border-radius: 4px;
background-color: var(--bg-faded-color);
display: inline-flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 0 1px var(--outline-color);
}
.post-peek-card img {
outline: 3px double var(--link-faded-color);
}
}
.post-peek-tag {
display: inline-block;
border-radius: 4px;
font-size: 12px;
color: var(--text-insignificant-color);
font-weight: 500;
text-transform: uppercase;
border: 1px solid var(--outline-color);
padding: 2px !important;
align-self: center;
background-color: var(--bg-faded-color);
line-height: 1;
&.post-peek-poll {
display: inline-flex;
align-items: center;
gap: 2px;
flex-direction: column;
color: var(--text-color);
}
&.post-peek-thread {
font-size: 10px;
/* padding: 2px 4px; */
font-weight: 700;
background-color: var(--bg-color);
color: var(--reply-to-text-color) !important;
border-color: var(--reply-to-color);
background-image: repeating-linear-gradient(
-70deg,
transparent,
transparent 3px,
var(--reply-to-faded-color) 3px,
var(--reply-to-faded-color) 4px
);
}
}
}
> li > a:is(:hover, :focus) .post-peek-content {
opacity: 1;
}
.post-meta {
grid-area: meta;
font-size: 90%;
color: var(--text-insignificant-color);
white-space: nowrap;
display: flex;
align-items: center;
align-self: flex-start;
column-gap: 8px;
}
.post-stats {
opacity: 0;
display: inline-flex;
gap: 2px;
align-items: center;
transform: translateX(4px);
/* transition: all 0.25s ease-out; */
&:empty {
display: none;
}
}
.post-line:hover .post-stats {
opacity: 1;
transform: translateX(0);
}
+ footer {
min-height: 15vh;
color: var(--text-insignificant-color);
padding-block: 15vh;
text-align: center;
}
}

1371
src/pages/catchup.jsx Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
import './trending.css'; import '../components/links-bar.css';
import { MenuItem } from '@szhsin/react-menu'; import { MenuItem } from '@szhsin/react-menu';
import { getBlurHashAverageColor } from 'fast-blurhash'; import { getBlurHashAverageColor } from 'fast-blurhash';

View file

@ -9,20 +9,20 @@ import {
set, set,
} from 'idb-keyval'; } from 'idb-keyval';
const draftsStore = createStore('drafts-db', 'drafts-store'); function initDB(dbName, storeName) {
const store = createStore(dbName, storeName);
// Add additonal `draftsStore` parameter to all methods return {
set: (key, val) => set(key, val, store),
const drafts = { get: (key) => get(key, store),
set: (key, val) => set(key, val, draftsStore), getMany: (keys) => getMany(keys, store),
get: (key) => get(key, draftsStore), del: (key) => del(key, store),
getMany: (keys) => getMany(keys, draftsStore), delMany: (keys) => delMany(keys, store),
del: (key) => del(key, draftsStore), clear: () => clear(store),
delMany: (keys) => delMany(keys, draftsStore), keys: () => keys(store),
clear: () => clear(draftsStore), };
keys: () => keys(draftsStore), }
};
export default { export default {
drafts, drafts: initDB('drafts-db', 'drafts-store'),
catchup: initDB('catchup-db', 'catchup-store'),
}; };