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
- Improve Login dialog
- Fix/Test zaps
- mobile view for profile does not fit follow button
- repair auto login
- store NIP46 secret key
- Fix/Test zaps
- Reimplement Likes/Zaps based in ngine code
- Investigate profile caching
- 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',
element: <SlideShow />,
},
{
path: 'topic/:topic',
element: <SlideShow />,
},
{
path: 'profile/:npub',
element: <SlideShow />,

View File

@ -8,7 +8,6 @@
display: flex;
flex-direction: row;
gap: 8px;
align-items: center;
}
.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) {
.author-name {
display: none;
max-width: 14em;
line-height: 24px;
}
.author-info {
flex-direction: column;
}
}

View File

@ -34,36 +34,38 @@ const AuthorProfile = ({
return (
<div className="author-info">
<div
className="author-image"
onClick={() => {
setViewMode && setViewMode('grid');
npub && nav({ ...currentSettings, tags: [], npubs: [npub], list: undefined });
}}
style={{
backgroundImage: avatarLoaded && src ? `url(${createImgProxyUrl(src, 80, 80)})` : 'none',
}}
></div>
<div className="author-identity">
<div
className="author-image"
onClick={() => {
setViewMode && setViewMode('grid');
npub && nav({ ...currentSettings, tags: [], npubs: [npub], list: undefined, topic: undefined });
}}
style={{
backgroundImage: avatarLoaded && src ? `url(${createImgProxyUrl(src, 80, 80)})` : 'none',
}}
></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
className="author-name"
onClick={() => {
setViewMode && setViewMode('grid');
npub && nav({ ...currentSettings, tags: [], npubs: [npub] });
}}
>
{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>
)}
{externalLink && npub && (
<a target="_blank" href={`https://nostrapp.link/#${npub}`}>
<IconLink></IconLink>
</a>
)}
</div>
</div>
);
};

View File

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

View File

@ -21,9 +21,9 @@ const Home = () => {
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')`,
}}
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>
@ -37,7 +37,7 @@ const Home = () => {
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)`,
}}
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>

View File

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

View File

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

View File

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

View File

@ -17,10 +17,10 @@ const MasonryImage = ({ image, onClick, index }: MasonryImageProps) => {
const { nav, currentSettings } = useNav();
const tagClick = (tag: string) => {
nav({ ...currentSettings, tags: [tag], npubs: [], list: undefined });
nav({ ...currentSettings, tags: [tag], npubs: [], list: undefined, topic: undefined });
};
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);

View File

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

View File

@ -11,7 +11,7 @@ import {
isReply,
isAdultRelated,
} from './nostrImageDownload';
import { adultContentTags, adultNPubs, blockedPublicKeys, mixedAdultNPubs } from './env';
import { adultContentTags, adultNPubs, blockedPublicKeys, mixedAdultNPubs, topics } from './env';
import Settings from './Settings';
import SlideView from './SlideView';
import { nip19 } from 'nostr-tools';
@ -91,7 +91,9 @@ const SlideShow = () => {
const authorsToQuery =
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,
});
@ -236,7 +238,7 @@ const SlideShow = () => {
setViewMode('grid');
}
if (event.key.toLowerCase() === 'h') {
nav({ ...settings, npubs: [], tags: [] });
nav({ ...settings, npubs: [], list: undefined, topic: undefined, tags: [] });
}
if (event.key.toLowerCase() === 'x') {
setViewMode('scroll');
@ -282,10 +284,6 @@ const SlideShow = () => {
return <AdultContentInfo></AdultContentInfo>;
}
const toggleViewMode = () => {
setViewMode(view => (view == 'grid' ? 'scroll' : 'grid'));
};
return (
<>
{showSettings && <Settings onClose={() => setShowSettings(false)} setViewMode={setViewMode}></Settings>}

View File

@ -2,11 +2,17 @@ import { nip19 } from 'nostr-tools';
export const appName = 'slidestr.net';
type Topic = {
name?: string;
tags: string[];
};
export const topics: { [key: string]: Topic } = {
bitcoinatlantis: {
name: 'Bitcoin Atlantis / Madeira',
tags: ['bitcoinatlantis', 'madeira', 'btcatlantis', 'soveng', 'funchal', 'freemadeira'],
},
art: {
name: 'Art',
tags: [
'art',
'artstr',
@ -22,10 +28,11 @@ export const topics: { [key: string]: Topic } = {
'zeichnen',
],
},
bitcoin: { tags: ['bitcoin', 'plebchain'] },
nostr: { tags: ['coffeechain', 'nostr', 'zapathon', 'grownostr', 'freedom', 'purple'] },
animals: { tags: ['catstr', 'dogstr', 'animal', 'animals', 'bird', 'birds', 'pets'] },
bitcoin: { name: '₿itcoin', tags: ['bitcoin', 'plebchain'] },
nostr: { name: 'Nostr', tags: ['coffeechain', 'nostr', 'zapathon', 'grownostr', 'freedom', 'purple'] },
animals: { name: 'Animals', tags: ['catstr', 'dogstr', 'animal', 'animals', 'bird', 'birds', 'pets'] },
photography: {
name: 'Photography',
tags: [
'naturephotography',
'photo',
@ -39,9 +46,10 @@ export const topics: { [key: string]: Topic } = {
],
},
lifestyle: {
name: 'Lifestyle',
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 = [

View File

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