mirror of
https://github.com/PrimalHQ/primal-web-app.git
synced 2024-10-01 17:31:13 +00:00
Redesigned Primary note
This commit is contained in:
parent
20b4bf76da
commit
33e7efdc02
@ -7,6 +7,11 @@
|
||||
background-color: var(--text-tertiary);
|
||||
-webkit-mask: url(../../assets/icons/bookmark_empty.svg) no-repeat 0 / 16px;
|
||||
mask: url(../../assets/icons/bookmark_empty.svg) no-repeat 0 / 16px;
|
||||
|
||||
&.large {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.fullBookmark {
|
||||
@ -17,6 +22,11 @@
|
||||
background-color: var(--active-bookmarked);
|
||||
-webkit-mask: url(../../assets/icons/bookmark_filled.svg) no-repeat 0 / 16px;
|
||||
mask: url(../../assets/icons/bookmark_filled.svg) no-repeat 0 / 16px;
|
||||
|
||||
&.large {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -16,7 +16,7 @@ import styles from './BookmarkNote.module.scss';
|
||||
import { saveBookmarks } from '../../lib/localStore';
|
||||
import { importEvents, triggerImportEvents } from '../../lib/notes';
|
||||
|
||||
const BookmarkNote: Component<{ note: PrimalNote }> = (props) => {
|
||||
const BookmarkNote: Component<{ note: PrimalNote, large?: boolean }> = (props) => {
|
||||
const account = useAccountContext();
|
||||
const app = useAppContext();
|
||||
const intl = useIntl();
|
||||
@ -147,10 +147,10 @@ const BookmarkNote: Component<{ note: PrimalNote }> = (props) => {
|
||||
<Show
|
||||
when={isBookmarked()}
|
||||
fallback={
|
||||
<div class={styles.emptyBookmark}></div>
|
||||
<div class={`${styles.emptyBookmark} ${props.large ? styles.large : ''}`}></div>
|
||||
}
|
||||
>
|
||||
<div class={styles.fullBookmark}></div>
|
||||
<div class={`${styles.fullBookmark} ${props.large ? styles.large : ''}`}></div>
|
||||
</Show>
|
||||
</ButtonGhost>
|
||||
</div>
|
||||
|
@ -245,8 +245,9 @@
|
||||
background-color: var(--background-card);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 12px;
|
||||
padding-inline: 12px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 12px;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
|
||||
@ -286,6 +287,29 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.time {
|
||||
padding-block: 20px;
|
||||
border-bottom: 1px solid var(--devider);
|
||||
margin-bottom: 16px;
|
||||
color: var(--text-tertiary);
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
|
||||
.reactSummary {
|
||||
&::before {
|
||||
content: ' · ';
|
||||
}
|
||||
|
||||
.number {
|
||||
color: var(--text-primary);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ import NoteHeader from './NoteHeader/NoteHeader';
|
||||
import { createStore } from 'solid-js/store';
|
||||
import { CustomZapInfo, useAppContext } from '../../contexts/AppContext';
|
||||
import NoteContextTrigger from './NoteContextTrigger';
|
||||
import { date, longDate, veryLongDate } from '../../lib/dates';
|
||||
|
||||
export type NoteFooterState = {
|
||||
likes: number,
|
||||
@ -146,6 +147,12 @@ const Note: Component<{
|
||||
);
|
||||
}
|
||||
|
||||
const reactionSum = () => {
|
||||
const { likes, zaps, reposts } = props.note.post;
|
||||
|
||||
return (likes || 0) + (zaps || 0) + (reposts || 0);
|
||||
};
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={noteType() === 'notification'}>
|
||||
@ -200,12 +207,25 @@ const Note: Component<{
|
||||
<ParsedNote note={props.note} width={Math.min(574, window.innerWidth)} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class={styles.time}
|
||||
title={date(props.note.post?.created_at).date.toLocaleString()}
|
||||
>
|
||||
<span>
|
||||
{veryLongDate(props.note.post?.created_at).replace('at', '·')}
|
||||
</span>
|
||||
<span class={styles.reactSummary}>
|
||||
<span class={styles.number}>{reactionSum()}</span> Reactions
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<NoteFooter
|
||||
note={props.note}
|
||||
state={footerState}
|
||||
updateState={updateFooterState}
|
||||
customZapInfo={customZapInfo}
|
||||
wide={true}
|
||||
large={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,18 +1,11 @@
|
||||
import { A } from '@solidjs/router';
|
||||
import { Component, createSignal, Show } from 'solid-js';
|
||||
import { PrimalNote, PrimalUser } from '../../types/primal';
|
||||
import ParsedNote from '../ParsedNote/ParsedNote';
|
||||
import NoteFooter from './NoteFooter/NoteFooter';
|
||||
import NoteHeader from './NoteHeader/NoteHeader';
|
||||
import { Component, Show } from 'solid-js';
|
||||
import { PrimalUser } from '../../types/primal';
|
||||
|
||||
import styles from './Note.module.scss';
|
||||
import { useThreadContext } from '../../contexts/ThreadContext';
|
||||
import { useIntl } from '@cookbook/solid-intl';
|
||||
import { authorName, nip05Verification, truncateNpub } from '../../stores/profile';
|
||||
import { note as t } from '../../translations';
|
||||
import { authorName, nip05Verification } from '../../stores/profile';
|
||||
import { hookForDev } from '../../lib/devTools';
|
||||
import NoteReplyHeader from './NoteHeader/NoteReplyHeader';
|
||||
import Avatar from '../Avatar/Avatar';
|
||||
import { date } from '../../lib/dates';
|
||||
import VerificationCheck from '../VerificationCheck/VerificationCheck';
|
||||
|
||||
|
@ -1,27 +1,17 @@
|
||||
import { A } from '@solidjs/router';
|
||||
import { Component, createEffect, createSignal, Show } from 'solid-js';
|
||||
import { MenuItem, NostrRelaySignedEvent, PrimalNote, PrimalRepost, PrimalUser } from '../../types/primal';
|
||||
import ParsedNote from '../ParsedNote/ParsedNote';
|
||||
import NoteFooter from './NoteFooter/NoteFooter';
|
||||
import NoteHeader from './NoteHeader/NoteHeader';
|
||||
import { Component, createEffect, createSignal } from 'solid-js';
|
||||
import { MenuItem, NostrRelaySignedEvent } from '../../types/primal';
|
||||
|
||||
import styles from './Note.module.scss';
|
||||
import { useThreadContext } from '../../contexts/ThreadContext';
|
||||
import { useIntl } from '@cookbook/solid-intl';
|
||||
import { authorName, nip05Verification, truncateNpub, userName } from '../../stores/profile';
|
||||
import { authorName, userName } from '../../stores/profile';
|
||||
import { note as t, actions as tActions, toast as tToast } from '../../translations';
|
||||
import { hookForDev } from '../../lib/devTools';
|
||||
import NoteReplyHeader from './NoteHeader/NoteReplyHeader';
|
||||
import Avatar from '../Avatar/Avatar';
|
||||
import { date } from '../../lib/dates';
|
||||
import VerificationCheck from '../VerificationCheck/VerificationCheck';
|
||||
import PrimalMenu from '../PrimalMenu/PrimalMenu';
|
||||
import { useAccountContext } from '../../contexts/AccountContext';
|
||||
import { APP_ID } from '../../App';
|
||||
import { reportUser } from '../../lib/profile';
|
||||
import { useToastContext } from '../Toaster/Toaster';
|
||||
import { broadcastEvent } from '../../lib/notes';
|
||||
import { getScreenCordinates } from '../../utils';
|
||||
import { NoteContextMenuInfo } from '../../contexts/AppContext';
|
||||
import ConfirmModal from '../ConfirmModal/ConfirmModal';
|
||||
|
||||
|
@ -2,11 +2,23 @@
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-color: var(--text-tertiary-2);
|
||||
|
||||
&.large {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin typeDiv {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
|
||||
&.large {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.contextButton {
|
||||
@ -59,9 +71,6 @@
|
||||
}
|
||||
|
||||
.stat {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
align-items: center;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
|
@ -30,6 +30,7 @@ const NoteFooter: Component<{
|
||||
state: NoteFooterState,
|
||||
updateState: SetStoreFunction<NoteFooterState>,
|
||||
customZapInfo: CustomZapInfo,
|
||||
large?: boolean,
|
||||
}> = (props) => {
|
||||
|
||||
const account = useAccountContext();
|
||||
@ -321,6 +322,7 @@ const NoteFooter: Component<{
|
||||
highlighted={props.state.replied}
|
||||
label={props.state.replies === 0 ? '' : truncateNumber(props.state.replies, 2)}
|
||||
title={props.state.replies.toLocaleString()}
|
||||
large={props.large}
|
||||
/>
|
||||
|
||||
<NoteFooterActionButton
|
||||
@ -335,6 +337,7 @@ const NoteFooter: Component<{
|
||||
label={props.state.satsZapped === 0 ? '' : truncateNumber(props.state.satsZapped, 2)}
|
||||
hidden={props.state.hideZapIcon}
|
||||
title={props.state.satsZapped.toLocaleString()}
|
||||
large={props.large}
|
||||
/>
|
||||
|
||||
<NoteFooterActionButton
|
||||
@ -344,6 +347,7 @@ const NoteFooter: Component<{
|
||||
highlighted={props.state.liked}
|
||||
label={props.state.likes === 0 ? '' : truncateNumber(props.state.likes, 2)}
|
||||
title={props.state.likes.toLocaleString()}
|
||||
large={props.large}
|
||||
/>
|
||||
|
||||
<button
|
||||
@ -357,7 +361,7 @@ const NoteFooter: Component<{
|
||||
ref={repostMenu}
|
||||
>
|
||||
<div
|
||||
class={styles.icon}
|
||||
class={`${styles.icon} ${props.large ? styles.large : ''}`}
|
||||
style={'visibility: visible'}
|
||||
></div>
|
||||
<div class={styles.statNumber}>
|
||||
@ -373,7 +377,10 @@ const NoteFooter: Component<{
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<BookmarkNote note={props.note} />
|
||||
<BookmarkNote
|
||||
note={props.note}
|
||||
large={props.large}
|
||||
/>
|
||||
|
||||
</div>
|
||||
)
|
||||
|
@ -23,6 +23,7 @@ const NoteFooterActionButton: Component<{
|
||||
label: string | number,
|
||||
hidden?: boolean,
|
||||
title?: string,
|
||||
large?: boolean,
|
||||
}> = (props) => {
|
||||
|
||||
return (
|
||||
@ -36,9 +37,9 @@ const NoteFooterActionButton: Component<{
|
||||
onTouchEnd={props.onTouchEnd ?? (() => {})}
|
||||
disabled={props.disabled}
|
||||
>
|
||||
<div class={`${buttonTypeClasses[props.type]}`}>
|
||||
<div class={`${buttonTypeClasses[props.type]} ${props.large ? styles.large : ''}`}>
|
||||
<div
|
||||
class={styles.icon}
|
||||
class={`${styles.icon} ${props.large ? styles.large : ''}`}
|
||||
style={props.hidden ? 'visibility: hidden': 'visibility: visible'}
|
||||
></div>
|
||||
<div class={styles.statNumber}>{props.label || ''}</div>
|
||||
|
@ -222,17 +222,7 @@ const NoteHeader: Component<{
|
||||
|
||||
<VerificationCheck
|
||||
user={props.note.user}
|
||||
fallback={<div class={styles.ellipsisIcon}></div>}
|
||||
/>
|
||||
|
||||
<span
|
||||
class={styles.time}
|
||||
title={date(props.note.post?.created_at).date.toLocaleString()}
|
||||
>
|
||||
{props.primary ?
|
||||
longDate(props.note.post?.created_at) :
|
||||
date(props.note.post?.created_at).label}
|
||||
</span>
|
||||
</div>
|
||||
<Show
|
||||
when={props.note.user?.nip05}
|
||||
|
@ -1,14 +1,9 @@
|
||||
import { A } from '@solidjs/router';
|
||||
import { Component, createMemo, createSignal, Show } from 'solid-js';
|
||||
import { PrimalNote, PrimalRepost, PrimalUser } from '../../types/primal';
|
||||
import ParsedNote from '../ParsedNote/ParsedNote';
|
||||
import NoteFooter from './NoteFooter/NoteFooter';
|
||||
import NoteHeader from './NoteHeader/NoteHeader';
|
||||
import { Component, createMemo, Show } from 'solid-js';
|
||||
import { PrimalNote } from '../../types/primal';
|
||||
|
||||
|
||||
import styles from './Note.module.scss';
|
||||
import { useThreadContext } from '../../contexts/ThreadContext';
|
||||
import { useIntl } from '@cookbook/solid-intl';
|
||||
import { authorName, nip05Verification, truncateNpub, userName } from '../../stores/profile';
|
||||
import { note as t } from '../../translations';
|
||||
import { hookForDev } from '../../lib/devTools';
|
||||
import MentionedUserLink from './MentionedUserLink/MentionedUserLink';
|
||||
|
@ -86,7 +86,7 @@
|
||||
padding: 12px;
|
||||
background-color: var(--background-card);
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--devider);
|
||||
border-block: 1px solid var(--devider);
|
||||
border-radius: 0;
|
||||
outline: none;
|
||||
display: flex;
|
||||
|
@ -18,6 +18,16 @@ export const longDate = (timestamp: number | undefined) => {
|
||||
return dtf.format(date);
|
||||
};
|
||||
|
||||
export const veryLongDate = (timestamp: number | undefined) => {
|
||||
if (!timestamp || timestamp < 0) {
|
||||
return '';
|
||||
}
|
||||
const date = new Date(timestamp * 1000);
|
||||
const dtf = new Intl.DateTimeFormat('en-US', { dateStyle: 'full', timeStyle: 'short'});
|
||||
|
||||
return dtf.format(date);
|
||||
};
|
||||
|
||||
export const date = (postTimestamp: number, style: Intl.RelativeTimeFormatStyle = 'short', since?: number) => {
|
||||
const today = since ?? Math.floor((new Date()).getTime() / 1000);
|
||||
const date = new Date(postTimestamp * 1000);
|
||||
|
@ -3,9 +3,7 @@ import Note from '../components/Note/Note';
|
||||
import styles from './Thread.module.scss';
|
||||
import { useNavigate, useParams } from '@solidjs/router';
|
||||
import { PrimalNote, SendNoteResult } from '../types/primal';
|
||||
import NotePrimary from '../components/Note/NotePrimary/NotePrimary';
|
||||
import PeopleList from '../components/PeopleList/PeopleList';
|
||||
import PageNav from '../components/PageNav/PageNav';
|
||||
import ReplyToNote from '../components/ReplyToNote/ReplyToNote';
|
||||
|
||||
import { nip19 } from 'nostr-tools';
|
||||
@ -13,7 +11,6 @@ import { useThreadContext } from '../contexts/ThreadContext';
|
||||
import Wormhole from '../components/Wormhole/Wormhole';
|
||||
import { useAccountContext } from '../contexts/AccountContext';
|
||||
import { sortByRecency } from '../stores/note';
|
||||
import { scrollWindowTo } from '../lib/scroll';
|
||||
import { useIntl } from '@cookbook/solid-intl';
|
||||
import Search from '../components/Search/Search';
|
||||
import { placeholders as tPlaceholders, thread as t } from '../translations';
|
||||
|
Loading…
Reference in New Issue
Block a user