feat: Topic header and link, disabled disclaimer

This commit is contained in:
florian 2024-02-28 19:11:43 +00:00
parent 62b56da827
commit 9eb0f5bf27
17 changed files with 135 additions and 60 deletions

View File

@ -3,10 +3,10 @@
# delete the events when the filter changes # delete the events when the filter changes
- Improve Login dialog - mobile view for profile does not fit follow button
- Fix/Test zaps
- repair auto login - repair auto login
- store NIP46 secret key - store NIP46 secret key
- Fix/Test zaps
- Reimplement Likes/Zaps based in ngine code - Reimplement Likes/Zaps based in ngine code
- Investigate profile caching - Investigate profile caching
- build masonary view only for desktop / window->columns - build masonary view only for desktop / window->columns

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

Before

Width:  |  Height:  |  Size: 510 KiB

After

Width:  |  Height:  |  Size: 510 KiB

View File

@ -39,6 +39,10 @@ const App = () => {
path: 'tags/:tags', path: 'tags/:tags',
element: <SlideShow />, element: <SlideShow />,
}, },
{
path: 'topic/:topic',
element: <SlideShow />,
},
{ {
path: 'profile/:npub', path: 'profile/:npub',
element: <SlideShow />, element: <SlideShow />,

View File

@ -8,7 +8,6 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 8px; gap: 8px;
align-items: center;
} }
.author-info a { .author-info a {
@ -50,8 +49,27 @@
} }
} }
.author-identity {
display: flex;
flex-direction: row;
gap: 8px;
align-items: center;
}
.author-actions {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
}
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.author-name { .author-name {
display: none; max-width: 14em;
line-height: 24px;
}
.author-info {
flex-direction: column;
} }
} }

View File

@ -34,36 +34,38 @@ const AuthorProfile = ({
return ( return (
<div className="author-info"> <div className="author-info">
<div <div className="author-identity">
className="author-image" <div
onClick={() => { className="author-image"
setViewMode && setViewMode('grid'); onClick={() => {
npub && nav({ ...currentSettings, tags: [], npubs: [npub], list: undefined }); setViewMode && setViewMode('grid');
}} npub && nav({ ...currentSettings, tags: [], npubs: [npub], list: undefined, topic: undefined });
style={{ }}
backgroundImage: avatarLoaded && src ? `url(${createImgProxyUrl(src, 80, 80)})` : 'none', style={{
}} backgroundImage: avatarLoaded && src ? `url(${createImgProxyUrl(src, 80, 80)})` : 'none',
></div> }}
></div>
<span
className="author-name"
onClick={() => {
setViewMode && setViewMode('grid');
npub && nav({ ...currentSettings, tags: [], npubs: [npub], list: undefined, topic: undefined });
}}
>
{author}
</span>
</div>
<div className="author-actions">
{followButtonAvailable && npub && (
<FollowButton pubkey={nip19.decode(npub).data as string} className="btn btn-primary" />
)}
<span {externalLink && npub && (
className="author-name" <a target="_blank" href={`https://nostrapp.link/#${npub}`}>
onClick={() => { <IconLink></IconLink>
setViewMode && setViewMode('grid'); </a>
npub && nav({ ...currentSettings, tags: [], npubs: [npub] }); )}
}} </div>
>
{author}
</span>
{followButtonAvailable && npub && (
<FollowButton pubkey={nip19.decode(npub).data as string} className="btn btn-primary" />
)}
{externalLink && npub && (
<a target="_blank" href={`https://nostrapp.link/#${npub}`}>
<IconLink></IconLink>
</a>
)}
</div> </div>
); );
}; };

View File

@ -30,7 +30,6 @@
.home .topic-title { .home .topic-title {
font-size: 30px; font-size: 30px;
padding-bottom: 0.5em; padding-bottom: 0.5em;
text-transform: capitalize;
} }
.home .tag { .home .tag {

View File

@ -21,9 +21,9 @@ const Home = () => {
style={{ style={{
backgroundImage: `linear-gradient(170deg, rgba(0, 0, 0, .8) 0%, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0) 100%), url('/images/${tk}.jpg')`, backgroundImage: `linear-gradient(170deg, rgba(0, 0, 0, .8) 0%, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0) 100%), url('/images/${tk}.jpg')`,
}} }}
onClick={() => nav({ ...currentSettings, tags: topics[tk].tags })} onClick={() => nav({ ...currentSettings, topic: tk, npubs: [], tags: [], list: undefined })}
> >
<div className="topic-title">{tk}</div> <div className="topic-title">{topics[tk].name || tk}</div>
</div> </div>
))} ))}
</div> </div>
@ -37,7 +37,7 @@ const Home = () => {
style={{ style={{
background: `linear-gradient(to bottom, rgba(0, 0, 0, .8) 0%, rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 0) 100%), red)`, background: `linear-gradient(to bottom, rgba(0, 0, 0, .8) 0%, rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 0) 100%), red)`,
}} }}
onClick={() => nav({ ...currentSettings, tags: [], npubs: [], list: l.nevent })} onClick={() => nav({ ...currentSettings, tags: [], npubs: [], list: l.nevent, topic: undefined })}
> >
<div className="topic-title">{l.name}</div> <div className="topic-title">{l.name}</div>
</div> </div>

View File

@ -16,7 +16,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 4px;
padding-top: 8px; padding-top: 16px;
} }
.info-panel .link svg { .info-panel .link svg {

View File

@ -57,7 +57,7 @@ const InfoPanel = ({ image, onClose, setViewMode, settings }: InfoPanelProps) =>
onClick={() => { onClick={() => {
//setCurrentImage(undefined); //setCurrentImage(undefined);
setViewMode('grid'); setViewMode('grid');
nav({ ...currentSettings, tags: [t], npubs: [] }); nav({ ...currentSettings, tags: [t], npubs: [], list: undefined, topic: undefined });
}} }}
> >
{t} {t}

View File

@ -41,11 +41,14 @@ const Layout = () => {
)} )}
</div> </div>
<Outlet />
{/*
{disclaimerAccepted ? ( {disclaimerAccepted ? (
<Outlet /> <Outlet />
) : ( ) : (
<Disclaimer disclaimerAccepted={disclaimerAccepted} setDisclaimerAccepted={setDisclaimerAccepted} /> <Disclaimer disclaimerAccepted={disclaimerAccepted} setDisclaimerAccepted={setDisclaimerAccepted} />
)} )}
*/}
</> </>
); );
}; };

View File

@ -17,10 +17,10 @@ const MasonryImage = ({ image, onClick, index }: MasonryImageProps) => {
const { nav, currentSettings } = useNav(); const { nav, currentSettings } = useNav();
const tagClick = (tag: string) => { const tagClick = (tag: string) => {
nav({ ...currentSettings, tags: [tag], npubs: [], list: undefined }); nav({ ...currentSettings, tags: [tag], npubs: [], list: undefined, topic: undefined });
}; };
const profileClick = (npub: string) => { const profileClick = (npub: string) => {
nav({ ...currentSettings, tags: [], npubs: [npub], list: undefined }); nav({ ...currentSettings, tags: [], npubs: [npub], list: undefined, topic: undefined });
}; };
const mediaIsVideo = isVideo(image.url); const mediaIsVideo = isVideo(image.url);

View File

@ -10,6 +10,7 @@ import { ViewMode } from '../SlideShow';
import { useGlobalState } from '../../utils/globalState'; import { useGlobalState } from '../../utils/globalState';
import MasonryImage from './MasonryImage'; import MasonryImage from './MasonryImage';
import useWindowSize from '../../utils/useWindowSize'; import useWindowSize from '../../utils/useWindowSize';
import { topics } from '../env';
type MasonryViewProps = { type MasonryViewProps = {
settings: Settings; settings: Settings;
@ -112,7 +113,7 @@ const MasonryView = ({ settings, images, currentImage, setCurrentImage, setViewM
<Helmet> <Helmet>
<title>{title}</title> <title>{title}</title>
</Helmet> </Helmet>
{(activeProfile || settings.tags.length == 1) && ( {(activeProfile || settings.topic || settings.tags.length == 1) && (
<div className="profile-header"> <div className="profile-header">
{activeProfile ? ( {activeProfile ? (
<AuthorProfile <AuthorProfile
@ -123,6 +124,8 @@ const MasonryView = ({ settings, images, currentImage, setCurrentImage, setViewM
followButton followButton
externalLink externalLink
></AuthorProfile> ></AuthorProfile>
) : settings.topic ? (
<h2>Topic: {topics[settings.topic].name || settings.topic}</h2>
) : ( ) : (
settings.tags.map(t => <h2>#{t}</h2>) settings.tags.map(t => <h2>#{t}</h2>)
)} )}

View File

@ -44,22 +44,58 @@ const SettingsDialog = ({ onClose, setViewMode }: SettingsProps) => {
// If the mode is 'user' and there is exactly one validNpubs // If the mode is 'user' and there is exactly one validNpubs
if (mode == 'user' && validNpubs.length == 1) { if (mode == 'user' && validNpubs.length == 1) {
// Navigate with the current settings, but only keep the validNpubs, and reset tags // Navigate with the current settings, but only keep the validNpubs, and reset tags
nav({ ...currentSettings, tags: [], npubs: validNpubs, showAdult, showReplies, showReposts }); nav({
...currentSettings,
tags: [],
list: undefined,
topic: undefined,
npubs: validNpubs,
showAdult,
showReplies,
showReposts,
});
} }
// If the mode is 'tags' and there is at least one valid tag // If the mode is 'tags' and there is at least one valid tag
else if (mode == 'tags' && validTags.length > 0) { else if (mode == 'tags' && validTags.length > 0) {
// Navigate with the current settings, but only keep the validTags, and reset npubs // Navigate with the current settings, but only keep the validTags, and reset npubs
nav({ ...currentSettings, tags: validTags, npubs: [], showAdult, showReplies, showReposts }); nav({
...currentSettings,
tags: validTags,
list: undefined,
topic: undefined,
npubs: [],
showAdult,
showReplies,
showReposts,
});
} }
// If the mode is 'tags' but there are no valid tags // If the mode is 'tags' but there are no valid tags
else if (mode == 'tags') { else if (mode == 'tags') {
// Navigate with the current settings, but reset npubs and use defaultHashTags as tags // Navigate with the current settings, but reset npubs and use defaultHashTags as tags
nav({ ...currentSettings, tags: defaultHashTags, npubs: [], showAdult, showReplies, showReposts }); nav({
...currentSettings,
tags: defaultHashTags,
list: undefined,
topic: undefined,
npubs: [],
showAdult,
showReplies,
showReposts,
});
} }
// If none of the above conditions are met // If none of the above conditions are met
else { else {
// Navigate with the current settings, but reset both tags and npubs // Navigate with the current settings, but reset both tags and npubs
nav({ ...currentSettings, tags: [], npubs: [], showAdult, showReplies, showReposts }); nav({
...currentSettings,
tags: [],
npubs: [],
list: undefined,
topic: undefined,
showAdult,
showReplies,
showReposts,
});
} }
onClose(); onClose();

View File

@ -11,7 +11,7 @@ import {
isReply, isReply,
isAdultRelated, isAdultRelated,
} from './nostrImageDownload'; } from './nostrImageDownload';
import { adultContentTags, adultNPubs, blockedPublicKeys, mixedAdultNPubs } from './env'; import { adultContentTags, adultNPubs, blockedPublicKeys, mixedAdultNPubs, topics } from './env';
import Settings from './Settings'; import Settings from './Settings';
import SlideView from './SlideView'; import SlideView from './SlideView';
import { nip19 } from 'nostr-tools'; import { nip19 } from 'nostr-tools';
@ -91,7 +91,9 @@ const SlideShow = () => {
const authorsToQuery = const authorsToQuery =
listAuthors && listAuthors.length > 0 ? listAuthors : settings.npubs.map(p => nip19.decode(p).data as string); listAuthors && listAuthors.length > 0 ? listAuthors : settings.npubs.map(p => nip19.decode(p).data as string);
const { events } = useEvents(buildFilter(settings.tags, authorsToQuery, settings.showReposts), { const filterTags = settings.topic ? topics[settings.topic].tags : settings.tags;
const { events } = useEvents(buildFilter(filterTags, authorsToQuery, settings.showReposts), {
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL, cacheUsage: NDKSubscriptionCacheUsage.PARALLEL,
}); });
@ -236,7 +238,7 @@ const SlideShow = () => {
setViewMode('grid'); setViewMode('grid');
} }
if (event.key.toLowerCase() === 'h') { if (event.key.toLowerCase() === 'h') {
nav({ ...settings, npubs: [], tags: [] }); nav({ ...settings, npubs: [], list: undefined, topic: undefined, tags: [] });
} }
if (event.key.toLowerCase() === 'x') { if (event.key.toLowerCase() === 'x') {
setViewMode('scroll'); setViewMode('scroll');
@ -282,10 +284,6 @@ const SlideShow = () => {
return <AdultContentInfo></AdultContentInfo>; return <AdultContentInfo></AdultContentInfo>;
} }
const toggleViewMode = () => {
setViewMode(view => (view == 'grid' ? 'scroll' : 'grid'));
};
return ( return (
<> <>
{showSettings && <Settings onClose={() => setShowSettings(false)} setViewMode={setViewMode}></Settings>} {showSettings && <Settings onClose={() => setShowSettings(false)} setViewMode={setViewMode}></Settings>}

View File

@ -2,11 +2,17 @@ import { nip19 } from 'nostr-tools';
export const appName = 'slidestr.net'; export const appName = 'slidestr.net';
type Topic = { type Topic = {
name?: string;
tags: string[]; tags: string[];
}; };
export const topics: { [key: string]: Topic } = { export const topics: { [key: string]: Topic } = {
bitcoinatlantis: {
name: 'Bitcoin Atlantis / Madeira',
tags: ['bitcoinatlantis', 'madeira', 'btcatlantis', 'soveng', 'funchal', 'freemadeira'],
},
art: { art: {
name: 'Art',
tags: [ tags: [
'art', 'art',
'artstr', 'artstr',
@ -22,10 +28,11 @@ export const topics: { [key: string]: Topic } = {
'zeichnen', 'zeichnen',
], ],
}, },
bitcoin: { tags: ['bitcoin', 'plebchain'] }, bitcoin: { name: '₿itcoin', tags: ['bitcoin', 'plebchain'] },
nostr: { tags: ['coffeechain', 'nostr', 'zapathon', 'grownostr', 'freedom', 'purple'] }, nostr: { name: 'Nostr', tags: ['coffeechain', 'nostr', 'zapathon', 'grownostr', 'freedom', 'purple'] },
animals: { tags: ['catstr', 'dogstr', 'animal', 'animals', 'bird', 'birds', 'pets'] }, animals: { name: 'Animals', tags: ['catstr', 'dogstr', 'animal', 'animals', 'bird', 'birds', 'pets'] },
photography: { photography: {
name: 'Photography',
tags: [ tags: [
'naturephotography', 'naturephotography',
'photo', 'photo',
@ -39,9 +46,10 @@ export const topics: { [key: string]: Topic } = {
], ],
}, },
lifestyle: { lifestyle: {
name: 'Lifestyle',
tags: ['fashion', 'flowerstr', 'foodstr', 'style', 'weedstr', 'travel', 'travelstr', 'happy', 'life', 'love'], tags: ['fashion', 'flowerstr', 'foodstr', 'style', 'weedstr', 'travel', 'travelstr', 'happy', 'life', 'love'],
}, },
gardening: { tags: ['gardening', 'gardenstr', 'nature'] }, gardenandfarm: { name: 'Gardening und Farming', tags: ['gardening', 'gardenstr', 'nature', 'farming', 'farmstr'] },
}; };
export const defaultHashTags = [ export const defaultHashTags = [

View File

@ -9,10 +9,11 @@ export type Settings = {
npubs: string[]; npubs: string[];
followers: boolean; followers: boolean;
list?: string; list?: string;
topic?: string;
}; };
const useNav = () => { const useNav = () => {
const { tags, npub, list } = useParams(); const { tags, npub, list, topic } = useParams();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const navigate = useNavigate(); const navigate = useNavigate();
@ -31,8 +32,9 @@ const useNav = () => {
showReposts: reposts, showReposts: reposts,
followers, followers,
list, list,
topic,
}; };
}, [tags, npub, searchParams, list]); }, [tags, npub, searchParams, list, topic]);
const nav = (settings: Settings) => { const nav = (settings: Settings) => {
const validTags = settings.tags.filter(t => t.length > 0); const validTags = settings.tags.filter(t => t.length > 0);
@ -50,7 +52,9 @@ const useNav = () => {
} }
const postfix = searchParams.length > 0 ? `?${searchParams.join('&')}` : ''; const postfix = searchParams.length > 0 ? `?${searchParams.join('&')}` : '';
if (settings.followers) { if (settings.topic) {
navigate(`/topic/${settings.topic}${postfix}`);
} else if (settings.followers) {
navigate(`/followers${postfix}`); navigate(`/followers${postfix}`);
} else if (settings.list !== undefined) { } else if (settings.list !== undefined) {
navigate(`/list/${settings.list}${postfix}`); navigate(`/list/${settings.list}${postfix}`);