feat: Improved mobile detail view

This commit is contained in:
florian 2023-08-16 13:40:36 +02:00
parent 4f490c1e06
commit 11ceac70c3
10 changed files with 86 additions and 30 deletions

View File

@ -1,11 +1,17 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/slidestr.svg" /> <link rel="icon" type="image/svg+xml" href="/slidestr.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="manifest" href="manifest.json" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>slidestr.net</title> <title>slidestr.net</title>
<link href="/fonts/outfit/outfit.css" rel="stylesheet"> <link href="/fonts/outfit/outfit.css" rel="stylesheet" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- possible content values: default, black or black-translucent -->
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

10
public/manifest.json Normal file
View File

@ -0,0 +1,10 @@
{
"name": "slidestr.net",
"short_name": "slidestr",
"theme_color": "#4a49ff",
"background_color": "#7600ff",
"display": "standalone",
"scope": "/",
"start_url": "/"
}

View File

@ -158,15 +158,25 @@
.details { .details {
overflow-y: scroll; overflow-y: scroll;
align-items: normal; align-items: normal;
overflow-x: hidden;
padding: 0;
overscroll-behavior: none;
} }
.details-contents { .details-contents {
grid-template-columns: 1fr; grid-template-columns: 1fr;
grid-template-rows: auto 1fr; grid-template-rows: auto 1fr;
} }
.details-contents .detail-image {
border-radius: 0px;
}
.detail-description { .detail-description {
max-width: 100%; max-width: 100%;
width: 100%; width: 100%;
overflow: visible; overflow: visible;
padding-left: 2em;
}
.closeButton {
top: 1.5em;
} }
} }

View File

@ -6,6 +6,7 @@ import GridImage from './GridImage';
import { Settings } from '../../utils/useNav'; import { Settings } from '../../utils/useNav';
import { useNDK } from '@nostr-dev-kit/ndk-react'; import { useNDK } from '@nostr-dev-kit/ndk-react';
import AuthorProfile from '../AuthorProfile'; import AuthorProfile from '../AuthorProfile';
import { useSwipeable } from 'react-swipeable';
type GridViewProps = { type GridViewProps = {
settings: Settings; settings: Settings;
@ -24,20 +25,37 @@ const GridView = ({ settings, images }: GridViewProps) => {
[images, settings] // settings is not used here, but we need to include it to trigger a re-render when it changes [images, settings] // settings is not used here, but we need to include it to trigger a re-render when it changes
); );
const showNextImage = () => {
setActiveImageIdx(idx => (idx !== undefined ? idx + 1 : 0));
};
const showPreviousImage = () => {
setActiveImageIdx(idx => (idx !== undefined && idx > 0 ? idx - 1 : idx));
};
const onKeyDown = (event: KeyboardEvent) => { const onKeyDown = (event: KeyboardEvent) => {
console.log(event); console.log(event);
if (event.key === 'ArrowRight') { if (event.key === 'ArrowRight') {
setActiveImageIdx(idx => idx !== undefined ? idx + 1 : 0); showNextImage();
} }
if (event.key === 'ArrowLeft') { if (event.key === 'ArrowLeft') {
setActiveImageIdx(idx => (idx !== undefined && idx > 0 ? idx - 1 : idx)); showPreviousImage();
} }
if (event.key === 'Escape') { if (event.key === 'Escape') {
setActiveImageIdx(undefined); setActiveImageIdx(undefined);
} }
}; };
const swipeHandlers = useSwipeable({
onSwipedLeft: () => {
showNextImage();
},
onSwipedRight: () => {
showPreviousImage();
},
});
useEffect(() => { useEffect(() => {
document.body.addEventListener('keydown', onKeyDown); document.body.addEventListener('keydown', onKeyDown);
return () => { return () => {
@ -48,7 +66,7 @@ const GridView = ({ settings, images }: GridViewProps) => {
const activeProfile = settings.npubs.length == 1 && getProfile(settings.npubs[0]); const activeProfile = settings.npubs.length == 1 && getProfile(settings.npubs[0]);
return ( return (
<div className="gridview"> <div className="gridview" {...swipeHandlers}>
{activeImageIdx !== undefined ? ( {activeImageIdx !== undefined ? (
<DetailsView images={sortedImages} activeImageIdx={activeImageIdx} setActiveImageIdx={setActiveImageIdx} /> <DetailsView images={sortedImages} activeImageIdx={activeImageIdx} setActiveImageIdx={setActiveImageIdx} />
) : null} ) : null}

View File

@ -214,3 +214,9 @@
animation-iteration-count: infinite; animation-iteration-count: infinite;
animation-timing-function: linear; animation-timing-function: linear;
} }
@media screen and (max-width: 768px) {
.controls {
top: 2em;
}
}

View File

@ -3,18 +3,20 @@ import { nip19 } from 'nostr-tools';
export const appName = 'slidestr.net'; export const appName = 'slidestr.net';
export const defaultHashTags = [ export const defaultHashTags = [
'art',
'artstr', 'artstr',
'catstr', 'catstr',
'dogstr', 'dogstr',
'nature', 'flowerstr',
'naturephotography', 'foodstr',
'gardenstr',
'grownostr',
'nostr',
'photography', 'photography',
'photostr', 'photostr',
'streetphotography', 'picstr',
'plebchain',
'tavelstr', 'tavelstr',
'gardening', 'zapathon',
'gardenstr',
]; ];
export const visibleHashTags = [ export const visibleHashTags = [
@ -27,6 +29,8 @@ export const visibleHashTags = [
'cute', 'cute',
'dogstr', 'dogstr',
'fashion', 'fashion',
'flowerstr',
'foodstr',
'freedom', 'freedom',
'gardening', 'gardening',
'gardenstr', 'gardenstr',
@ -47,8 +51,10 @@ export const visibleHashTags = [
'psychedelic', 'psychedelic',
'streetphotography', 'streetphotography',
'style', 'style',
'travelstr', 'tavelstr',
'travel', 'travel',
'travelstr',
'zapathon',
]; ];
/* All posts with the following hashtags are flagged as adult / NSFW are not shown /* All posts with the following hashtags are flagged as adult / NSFW are not shown
@ -150,6 +156,7 @@ export const adultNPubs = [
'npub1apr6dy5z4f0qs4cnswxj0gf37g46jxvh7xgwgs4wvzm6stu8f0asd4996r', // Anime Girl 'npub1apr6dy5z4f0qs4cnswxj0gf37g46jxvh7xgwgs4wvzm6stu8f0asd4996r', // Anime Girl
'npub1acwrv7aqgu949mw0zxmw2akgsjqp574nnq4vcl9wln5355q79w5ssv9qxg', // Arianna 'npub1acwrv7aqgu949mw0zxmw2akgsjqp574nnq4vcl9wln5355q79w5ssv9qxg', // Arianna
'npub1v3rnmlms82wgxejxwn7rr6kjruy3ty0l4084dx2zp3tn8dlxv28sjnp6pf', // High Elf Archer 'npub1v3rnmlms82wgxejxwn7rr6kjruy3ty0l4084dx2zp3tn8dlxv28sjnp6pf', // High Elf Archer
'npub1jvp6kfs2d3m98lyw5wcyr4fnctr83s0rc3mj5p0f75ach6vcd8rst6wqnu', // VelectBlue Art
]; ];
export const adultPublicKeys = adultNPubs.map(npub => (nip19.decode(npub).data as string).toLowerCase()); export const adultPublicKeys = adultNPubs.map(npub => (nip19.decode(npub).data as string).toLowerCase());

View File

@ -4,7 +4,6 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;
color-scheme: dark; color-scheme: dark;
color: rgba(255, 255, 255, 0.87); color: rgba(255, 255, 255, 0.87);
background-color: #111111; background-color: #111111;
@ -51,19 +50,6 @@ button {
outline: none; outline: none;
} }
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
input[type='checkbox'] { input[type='checkbox'] {
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;

View File

@ -28,6 +28,10 @@ const MainInner = () => {
path: 'p/:npub', path: 'p/:npub',
element: <App />, element: <App />,
}, },
{
path: '/followers',
element: <App />,
},
{ {
path: '/:npub', path: '/:npub',
element: <App />, element: <App />,

View File

@ -7,7 +7,9 @@ declare global {
} }
const useAutoLogin = () => { const useAutoLogin = () => {
const [autoLogin, setAutoLogin] = useState(JSON.parse(localStorage.getItem('autoLogin') as string) as boolean | undefined); const [autoLogin, setAutoLogin] = useState(
JSON.parse(localStorage.getItem('autoLogin') as string) as boolean | undefined
);
useEffect(() => { useEffect(() => {
const autoLogin = JSON.parse(localStorage.getItem('autoLogin') as string) as boolean | undefined; const autoLogin = JSON.parse(localStorage.getItem('autoLogin') as string) as boolean | undefined;

View File

@ -7,6 +7,7 @@ export type Settings = {
showReposts: boolean; showReposts: boolean;
tags: string[]; tags: string[];
npubs: string[]; npubs: string[];
followers: boolean;
}; };
const useNav = () => { const useNav = () => {
@ -18,8 +19,11 @@ const useNav = () => {
const adult = searchParams.get('adult') === 'true' || searchParams.get('nsfw') === 'true'; const adult = searchParams.get('adult') === 'true' || searchParams.get('nsfw') === 'true';
const replies = searchParams.get('replies') === 'true'; const replies = searchParams.get('replies') === 'true';
const reposts = searchParams.get('reposts') === 'true'; const reposts = searchParams.get('reposts') === 'true';
const followers = window.location.pathname.startsWith('/followers');
console.log(`tags = ${tags}, npub = ${npub}, adult = ${adult}, replies = ${replies}, reposts = ${reposts}`); console.log(
`tags = ${tags}, npub = ${npub}, adult = ${adult}, replies = ${replies}, reposts = ${reposts}, followers = ${followers}`
);
const useTags = tags?.split(',') || []; const useTags = tags?.split(',') || [];
@ -29,6 +33,7 @@ const useNav = () => {
showAdult: adult, showAdult: adult,
showReplies: replies, showReplies: replies,
showReposts: reposts, showReposts: reposts,
followers,
}; };
}, [tags, npub, searchParams]); }, [tags, npub, searchParams]);
@ -49,7 +54,9 @@ const useNav = () => {
const postfix = searchParams.length > 0 ? `?${searchParams.join('&')}` : ''; const postfix = searchParams.length > 0 ? `?${searchParams.join('&')}` : '';
if (validTags.length > 0) { if (settings.followers) {
navigate(`/followers${postfix}`);
} else if (validTags.length > 0) {
navigate(`/tags/${validTags.join('%2C')}${postfix}`); navigate(`/tags/${validTags.join('%2C')}${postfix}`);
} else if (validNpubs.length == 1) { } else if (validNpubs.length == 1) {
navigate(`/p/${validNpubs[0]}${postfix}`); navigate(`/p/${validNpubs[0]}${postfix}`);