mirror of
https://github.com/PrimalHQ/primal-web-app.git
synced 2024-10-03 02:10:55 +00:00
Add emoji's to custom zaps and messages to default zaps
This commit is contained in:
parent
0a40efeb57
commit
5277b01a4e
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
.feedsRestoreModal {
|
.feedsRestoreModal {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 420px;
|
width: 420px;
|
||||||
|
@ -109,6 +109,10 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.emoji, .amount {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.sats {
|
.sats {
|
||||||
color: var(--text-tertiary);
|
color: var(--text-tertiary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { useIntl } from '@cookbook/solid-intl';
|
import { useIntl } from '@cookbook/solid-intl';
|
||||||
import { Component, createEffect, createSignal, For } from 'solid-js';
|
import { Component, createEffect, createSignal, For } from 'solid-js';
|
||||||
|
import { defaultZap, defaultZapOptions } from '../../constants';
|
||||||
import { useAccountContext } from '../../contexts/AccountContext';
|
import { useAccountContext } from '../../contexts/AccountContext';
|
||||||
import { useSettingsContext } from '../../contexts/SettingsContext';
|
import { useSettingsContext } from '../../contexts/SettingsContext';
|
||||||
import { hookForDev } from '../../lib/devTools';
|
import { hookForDev } from '../../lib/devTools';
|
||||||
import { zapNote } from '../../lib/zap';
|
import { zapNote } from '../../lib/zap';
|
||||||
import { userName } from '../../stores/profile';
|
import { userName } from '../../stores/profile';
|
||||||
import { toastZapFail, zapCustomOption, actions as tActions, placeholders as tPlaceholders } from '../../translations';
|
import { toastZapFail, zapCustomOption, actions as tActions, placeholders as tPlaceholders } from '../../translations';
|
||||||
import { PrimalNote } from '../../types/primal';
|
import { PrimalNote, ZapOption } from '../../types/primal';
|
||||||
import { debounce } from '../../utils';
|
import { debounce } from '../../utils';
|
||||||
import ButtonPrimary from '../Buttons/ButtonPrimary';
|
import ButtonPrimary from '../Buttons/ButtonPrimary';
|
||||||
import Modal from '../Modal/Modal';
|
import Modal from '../Modal/Modal';
|
||||||
@ -19,9 +20,9 @@ const CustomZap: Component<{
|
|||||||
id?: string,
|
id?: string,
|
||||||
open?: boolean,
|
open?: boolean,
|
||||||
note: PrimalNote,
|
note: PrimalNote,
|
||||||
onConfirm: (amount?: number) => void,
|
onConfirm: (zapOption?: ZapOption) => void,
|
||||||
onSuccess: (amount?: number) => void,
|
onSuccess: (zapOption?: ZapOption) => void,
|
||||||
onFail: (amount?: number) => void
|
onFail: (zapOption?: ZapOption) => void
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
|
|
||||||
const toast = useToastContext();
|
const toast = useToastContext();
|
||||||
@ -29,14 +30,17 @@ const CustomZap: Component<{
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const settings = useSettingsContext();
|
const settings = useSettingsContext();
|
||||||
|
|
||||||
const [selectedValue, setSelectedValue] = createSignal(settings?.availableZapOptions[0] || 10);
|
const [selectedValue, setSelectedValue] = createSignal(settings?.availableZapOptions[0] || defaultZapOptions[0]);
|
||||||
const [comment, setComment] = createSignal('');
|
const [comment, setComment] = createSignal(defaultZapOptions[0].message || '');
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
setSelectedValue(settings?.availableZapOptions[0] || 10)
|
setSelectedValue(settings?.availableZapOptions[0] || defaultZapOptions[0])
|
||||||
});
|
});
|
||||||
|
|
||||||
const isSelected = (value: number) => value === selectedValue();
|
const isSelected = (value: ZapOption) => {
|
||||||
|
const sel = selectedValue();
|
||||||
|
return value.amount === sel.amount && value.emoji === sel.emoji && value.message === sel.message;
|
||||||
|
};
|
||||||
|
|
||||||
const truncateNumber = (amount: number) => {
|
const truncateNumber = (amount: number) => {
|
||||||
const t = 1000;
|
const t = 1000;
|
||||||
@ -78,7 +82,7 @@ const CustomZap: Component<{
|
|||||||
const success = await zapNote(
|
const success = await zapNote(
|
||||||
props.note,
|
props.note,
|
||||||
account.publicKey,
|
account.publicKey,
|
||||||
selectedValue(),
|
selectedValue().amount || 0,
|
||||||
comment(),
|
comment(),
|
||||||
account.relays,
|
account.relays,
|
||||||
);
|
);
|
||||||
@ -105,7 +109,7 @@ const CustomZap: Component<{
|
|||||||
{intl.formatMessage(tActions.zap)}
|
{intl.formatMessage(tActions.zap)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class={styles.close} onClick={() => props.onFail(0)}>
|
<button class={styles.close} onClick={() => props.onFail({ amount: 0, message: '' })}>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -115,7 +119,7 @@ const CustomZap: Component<{
|
|||||||
})}
|
})}
|
||||||
|
|
||||||
<span class={styles.amount}>
|
<span class={styles.amount}>
|
||||||
{truncateNumber(selectedValue())}
|
{truncateNumber(selectedValue().amount || 0)}
|
||||||
</span>
|
</span>
|
||||||
<span class={styles.units}>sats</span>
|
<span class={styles.units}>sats</span>
|
||||||
</div>
|
</div>
|
||||||
@ -125,10 +129,19 @@ const CustomZap: Component<{
|
|||||||
{(value) =>
|
{(value) =>
|
||||||
<button
|
<button
|
||||||
class={`${styles.zapOption} ${isSelected(value) ? styles.selected : ''}`}
|
class={`${styles.zapOption} ${isSelected(value) ? styles.selected : ''}`}
|
||||||
onClick={() => setSelectedValue(value)}
|
onClick={() => {
|
||||||
|
setComment(value.message || '')
|
||||||
|
setSelectedValue(value);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{truncateNumber(value)} <span class={styles.sats}>sats</span>
|
<span class={styles.emoji}>
|
||||||
|
{value.emoji}
|
||||||
|
</span>
|
||||||
|
<span class={styles.amount}>
|
||||||
|
{truncateNumber(value.amount || 0)}
|
||||||
|
</span>
|
||||||
|
<span class={styles.sats}>sats</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
34
src/components/EmojiPicker/EmojiPicker.module.scss
Normal file
34
src/components/EmojiPicker/EmojiPicker.module.scss
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
.emojiSuggestions {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50px 50px 50px 50px 50px 50px;
|
||||||
|
width: 322px;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 4px;
|
||||||
|
background-color: var(--background-input);
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.emojiOption {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
padding: 2px;
|
||||||
|
background: none;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:hover, &.highlight {
|
||||||
|
background-color: var(--text-tertiary-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
143
src/components/EmojiPicker/EmojiPicker.tsx
Normal file
143
src/components/EmojiPicker/EmojiPicker.tsx
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { Component, createEffect, createSignal, For, onCleanup, onMount } from 'solid-js';
|
||||||
|
|
||||||
|
import styles from './EmojiPicker.module.scss';
|
||||||
|
import { useSettingsContext } from '../../contexts/SettingsContext';
|
||||||
|
import { debounce, isVisibleInContainer, uuidv4 } from '../../utils';
|
||||||
|
import { useIntl } from '@cookbook/solid-intl';
|
||||||
|
import ConfirmModal from '../ConfirmModal/ConfirmModal';
|
||||||
|
import { settings as t } from '../../translations';
|
||||||
|
import { hookForDev } from '../../lib/devTools';
|
||||||
|
import ButtonLink from '../Buttons/ButtonLink';
|
||||||
|
import Modal from '../Modal/Modal';
|
||||||
|
|
||||||
|
import emojiSearch from '@jukben/emoji-search';
|
||||||
|
import { createStore } from 'solid-js/store';
|
||||||
|
import { EmojiOption } from '../../types/primal';
|
||||||
|
import ButtonPrimary from '../Buttons/ButtonPrimary';
|
||||||
|
|
||||||
|
const EmojiPicker: Component<{ id?: string, filter: string, onSelect: (emoji: EmojiOption) => void }> = (props) => {
|
||||||
|
const [emojiResults, setEmojiResults] = createStore<EmojiOption[]>([]);
|
||||||
|
const [highlightedEmoji, setHighlightedEmoji] = createSignal<number>(0);
|
||||||
|
let emojiOptions: HTMLDivElement | undefined;
|
||||||
|
const instanceId = uuidv4();
|
||||||
|
|
||||||
|
const emojiChangeKeyboard = (e: KeyboardEvent) => {
|
||||||
|
if (e.code === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
setHighlightedEmoji(i => {
|
||||||
|
if (emojiResults.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i < emojiResults.length - 7 ? i + 6 : 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const emojiHolder = document.getElementById(`${instanceId}-${highlightedEmoji()}`);
|
||||||
|
|
||||||
|
if (emojiHolder && emojiOptions && !isVisibleInContainer(emojiHolder, emojiOptions)) {
|
||||||
|
emojiHolder.scrollIntoView({ block: 'end', behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.code === 'ArrowUp') {
|
||||||
|
e.preventDefault();
|
||||||
|
setHighlightedEmoji(i => {
|
||||||
|
if (emojiResults.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i >= 6 ? i - 6 : emojiResults.length - 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
const emojiHolder = document.getElementById(`${instanceId}-${highlightedEmoji()}`);
|
||||||
|
|
||||||
|
if (emojiHolder && emojiOptions && !isVisibleInContainer(emojiHolder, emojiOptions)) {
|
||||||
|
emojiHolder.scrollIntoView({ block: 'start', behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.code === 'ArrowRight') {
|
||||||
|
e.preventDefault();
|
||||||
|
setHighlightedEmoji(i => {
|
||||||
|
if (emojiResults.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i < emojiResults.length - 1 ? i + 1 : 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const emojiHolder = document.getElementById(`${instanceId}-${highlightedEmoji()}`);
|
||||||
|
|
||||||
|
if (emojiHolder && emojiOptions && !isVisibleInContainer(emojiHolder, emojiOptions)) {
|
||||||
|
emojiHolder.scrollIntoView({ block: 'end', behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.code === 'ArrowLeft') {
|
||||||
|
e.preventDefault();
|
||||||
|
setHighlightedEmoji(i => {
|
||||||
|
if (emojiResults.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i > 0 ? i - 1 : emojiResults.length - 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
const emojiHolder = document.getElementById(`${instanceId}-${highlightedEmoji()}`);
|
||||||
|
|
||||||
|
if (emojiHolder && emojiOptions && !isVisibleInContainer(emojiHolder, emojiOptions)) {
|
||||||
|
emojiHolder.scrollIntoView({ block: 'start', behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['Enter', 'Space'].includes(e.code)) {
|
||||||
|
props.onSelect(emojiResults[highlightedEmoji()]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
window.addEventListener('keydown', emojiChangeKeyboard);
|
||||||
|
});
|
||||||
|
|
||||||
|
onCleanup(() => {
|
||||||
|
window.removeEventListener('keydown', emojiChangeKeyboard);
|
||||||
|
});
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const val = props.filter.trim();
|
||||||
|
|
||||||
|
setEmojiResults(emojiSearch(val));
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={styles.emojiSuggestions}
|
||||||
|
ref={emojiOptions}
|
||||||
|
>
|
||||||
|
<For each={emojiResults}>
|
||||||
|
{(emoji, index) => (
|
||||||
|
<button
|
||||||
|
id={`${instanceId}-${index()}`}
|
||||||
|
class={`${styles.emojiOption} ${highlightedEmoji() === index() ? styles.highlight : ''}`}
|
||||||
|
onClick={() => {
|
||||||
|
props.onSelect(emoji);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{emoji.name}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default hookForDev(EmojiPicker);
|
@ -9,12 +9,17 @@ const Modal: Component<{
|
|||||||
open?: boolean,
|
open?: boolean,
|
||||||
id?: string,
|
id?: string,
|
||||||
opaqueBackdrop?: boolean,
|
opaqueBackdrop?: boolean,
|
||||||
|
onBackdropClick?: () => void,
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show when={props.open}>
|
<Show when={props.open}>
|
||||||
<Portal mount={document.getElementById("modal") as Node}>
|
<Portal mount={document.getElementById("modal") as Node}>
|
||||||
<div id={props.id} class={`${styles.modal} ${props.opaqueBackdrop ? styles.opaque : ''}`}>
|
<div
|
||||||
|
id={props.id}
|
||||||
|
class={`${styles.modal} ${props.opaqueBackdrop ? styles.opaque : ''}`}
|
||||||
|
onClick={props.onBackdropClick}
|
||||||
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
</Portal>
|
</Portal>
|
||||||
|
@ -269,6 +269,7 @@ const EditBox: Component<{
|
|||||||
|
|
||||||
if (lastEmojiTrigger < 0 || cursor - lastEmojiTrigger <= 1) {
|
if (lastEmojiTrigger < 0 || cursor - lastEmojiTrigger <= 1) {
|
||||||
setEmojiInput(false);
|
setEmojiInput(false);
|
||||||
|
setEmojiQuery('');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, createEffect, createSignal, Show } from 'solid-js';
|
import { Component, createEffect, createSignal, Show } from 'solid-js';
|
||||||
import { MenuItem, PrimalNote } from '../../../types/primal';
|
import { MenuItem, PrimalNote, ZapOption } from '../../../types/primal';
|
||||||
import { sendRepost } from '../../../lib/notes';
|
import { sendRepost } from '../../../lib/notes';
|
||||||
|
|
||||||
import styles from './NoteFooter.module.scss';
|
import styles from './NoteFooter.module.scss';
|
||||||
@ -252,17 +252,17 @@ const NoteFooter: Component<{ note: PrimalNote, wide?: boolean, id?: string }> =
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setZappedAmount(() => settings?.defaultZapAmount || 0);
|
setZappedAmount(() => settings?.defaultZap.amount || 0);
|
||||||
setZappedNow(true);
|
setZappedNow(true);
|
||||||
animateZap();
|
animateZap();
|
||||||
const success = await zapNote(props.note, account.publicKey, settings?.defaultZapAmount || 10, '', account.relays);
|
const success = await zapNote(props.note, account.publicKey, settings?.defaultZap.amount || 10, settings?.defaultZap.message || '', account.relays);
|
||||||
setIsZapping(false);
|
setIsZapping(false);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setZappedAmount(() => -(settings?.defaultZapAmount || 0));
|
setZappedAmount(() => -(settings?.defaultZap.amount || 0));
|
||||||
setZappedNow(true);
|
setZappedNow(true);
|
||||||
setZapped(props.note.post.noteActions.zapped);
|
setZapped(props.note.post.noteActions.zapped);
|
||||||
}
|
}
|
||||||
@ -413,14 +413,14 @@ const NoteFooter: Component<{ note: PrimalNote, wide?: boolean, id?: string }> =
|
|||||||
<CustomZap
|
<CustomZap
|
||||||
open={isCustomZap()}
|
open={isCustomZap()}
|
||||||
note={props.note}
|
note={props.note}
|
||||||
onConfirm={(amount: number) => {
|
onConfirm={(zapOption: ZapOption) => {
|
||||||
setIsCustomZap(false);
|
setIsCustomZap(false);
|
||||||
setZappedAmount(() => amount || 0);
|
setZappedAmount(() => zapOption.amount || 0);
|
||||||
setZappedNow(true);
|
setZappedNow(true);
|
||||||
setZapped(true);
|
setZapped(true);
|
||||||
animateZap();
|
animateZap();
|
||||||
}}
|
}}
|
||||||
onSuccess={(amount: number) => {
|
onSuccess={(zapOption: ZapOption) => {
|
||||||
setIsCustomZap(false);
|
setIsCustomZap(false);
|
||||||
setIsZapping(false);
|
setIsZapping(false);
|
||||||
setZappedNow(false);
|
setZappedNow(false);
|
||||||
@ -428,8 +428,8 @@ const NoteFooter: Component<{ note: PrimalNote, wide?: boolean, id?: string }> =
|
|||||||
setHideZapIcon(false);
|
setHideZapIcon(false);
|
||||||
setZapped(true);
|
setZapped(true);
|
||||||
}}
|
}}
|
||||||
onFail={(amount: number) => {
|
onFail={(zapOption: ZapOption) => {
|
||||||
setZappedAmount(() => -(amount || 0));
|
setZappedAmount(() => -(zapOption.amount || 0));
|
||||||
setZappedNow(true);
|
setZappedNow(true);
|
||||||
setIsCustomZap(false);
|
setIsCustomZap(false);
|
||||||
setIsZapping(false);
|
setIsZapping(false);
|
||||||
|
@ -6,11 +6,12 @@
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.zapOptions {
|
.zapOptions {
|
||||||
width: 396px;
|
display: flex;
|
||||||
display: grid;
|
flex-direction: column;
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
width: 100%;
|
||||||
grid-column-gap: 12px;
|
.zapInput {
|
||||||
grid-row-gap: 12px;
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +23,42 @@
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.zapInput {
|
.zapInput {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
background-color: var(--background-header-input);
|
||||||
|
border: none;
|
||||||
|
border-radius: 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.optEmoji {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 120px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 18px 0 0 18px;
|
||||||
|
margin: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 20px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--subtile-devider);
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -30,23 +66,137 @@ input.zapInput {
|
|||||||
height: 36px;
|
height: 36px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding-bottom: 0;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
|
padding-inline: 16px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
background-color: var(--background-header-input);
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 18px;
|
|
||||||
|
|
||||||
&:focus {
|
&.defAmount {
|
||||||
|
border-radius: 18px 0 0 18px;
|
||||||
|
}
|
||||||
|
&.defMessage {
|
||||||
|
border-radius: 0 18px 18px 0;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: flex-start;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&.optAmount {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
&.optMessage {
|
||||||
|
border-radius: 0 18px 18px 0;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: flex-start;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus, &:hover {
|
||||||
background-color: var(--subtile-devider);
|
background-color: var(--subtile-devider);
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.restoreZaps {
|
.restoreZaps {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
margin-top: 36px;
|
margin-top: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zapEmojiChangeModal {
|
||||||
|
position: fixed;
|
||||||
|
width: 420px;
|
||||||
|
height: 344px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
background-color: var(--background-input);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 22px;
|
||||||
|
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 220px;
|
||||||
|
height: 36px;
|
||||||
|
text-align: left;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 20px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 18px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: var(--subtile-devider);
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xClose {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
right: 18px;
|
||||||
|
|
||||||
|
.iconClose {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0px 0px;
|
||||||
|
background-color: var(--text-secondary);
|
||||||
|
-webkit-mask: url(../../assets/icons/close.svg) no-repeat center;
|
||||||
|
mask: url(../../assets/icons/close.svg) no-repeat center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.iconClose {
|
||||||
|
background-color: var(--text-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
import { Component, createSignal, For } from 'solid-js';
|
import { Component, createEffect, createSignal, For } from 'solid-js';
|
||||||
|
|
||||||
import styles from './SettingsZap.module.scss';
|
import styles from './SettingsZap.module.scss';
|
||||||
import { useSettingsContext } from '../../contexts/SettingsContext';
|
import { useSettingsContext } from '../../contexts/SettingsContext';
|
||||||
import { debounce } from '../../utils';
|
import { debounce, isVisibleInContainer, uuidv4 } from '../../utils';
|
||||||
import { useIntl } from '@cookbook/solid-intl';
|
import { useIntl } from '@cookbook/solid-intl';
|
||||||
import ConfirmModal from '../ConfirmModal/ConfirmModal';
|
import ConfirmModal from '../ConfirmModal/ConfirmModal';
|
||||||
import { settings as t } from '../../translations';
|
import { settings as t } from '../../translations';
|
||||||
import { hookForDev } from '../../lib/devTools';
|
import { hookForDev } from '../../lib/devTools';
|
||||||
import ButtonLink from '../Buttons/ButtonLink';
|
import ButtonLink from '../Buttons/ButtonLink';
|
||||||
|
import Modal from '../Modal/Modal';
|
||||||
|
|
||||||
|
import emojiSearch from '@jukben/emoji-search';
|
||||||
|
import { createStore } from 'solid-js/store';
|
||||||
|
import { EmojiOption } from '../../types/primal';
|
||||||
|
import ButtonPrimary from '../Buttons/ButtonPrimary';
|
||||||
|
import EmojiPicker from '../EmojiPicker/EmojiPicker';
|
||||||
|
|
||||||
const SettingsZap: Component<{ id?: string }> = (props) => {
|
const SettingsZap: Component<{ id?: string }> = (props) => {
|
||||||
|
|
||||||
@ -17,49 +24,110 @@ const SettingsZap: Component<{ id?: string }> = (props) => {
|
|||||||
|
|
||||||
const [isRestoringZaps, setIsRestoringZaps] = createSignal(false);
|
const [isRestoringZaps, setIsRestoringZaps] = createSignal(false);
|
||||||
|
|
||||||
|
const [isEmojiChange, setIsEmojiChange] = createSignal(-1);
|
||||||
|
|
||||||
|
const [emojiSearchTerm, setEmojiSearchTerm] = createSignal('smile');
|
||||||
|
|
||||||
const onRestoreZaps = () => {
|
const onRestoreZaps = () => {
|
||||||
settings?.actions.resetZapOptionsToDefault();
|
settings?.actions.resetZapOptionsToDefault();
|
||||||
setIsRestoringZaps(false);
|
setIsRestoringZaps(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeDefaultZap = (e: InputEvent) => {
|
const changeDefaultZapAmount = (e: InputEvent) => {
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const val = parseInt(target.value);
|
const amount = parseInt(target.value);
|
||||||
|
|
||||||
if (isNaN(val)) {
|
if (isNaN(amount)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
settings?.actions.setDefaultZapAmount(val);
|
settings?.actions.setDefaultZapAmount({ amount });
|
||||||
}, 500)
|
}, 500)
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeZapOptions = (e: InputEvent, index: number) => {
|
const changeDefaultZapMessage = (e: InputEvent) => {
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const val = parseInt(target.value);
|
const message = target.value;
|
||||||
|
|
||||||
if (isNaN(val)) {
|
settings?.actions.setDefaultZapAmount({ message });
|
||||||
|
}, 500)
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeZapOptionAmount = (e: InputEvent, index: number) => {
|
||||||
|
debounce(() => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
const amount = parseInt(target.value);
|
||||||
|
|
||||||
|
if (isNaN(amount)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
settings?.actions.setZapOptions(val, index);
|
settings?.actions.setZapOptions({ amount }, index);
|
||||||
}, 500);
|
}, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changeZapOptionMessage = (e: InputEvent, index: number) => {
|
||||||
|
debounce(() => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
const message = target.value;
|
||||||
|
|
||||||
|
settings?.actions.setZapOptions({ message }, index);
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeZapOptionEmoji = (emojiOption: EmojiOption) => {
|
||||||
|
if (isEmojiChange() < 0) return;
|
||||||
|
|
||||||
|
settings?.actions.setZapOptions({ emoji: emojiOption.name }, isEmojiChange());
|
||||||
|
setIsEmojiChange(-1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onKey = (e: KeyboardEvent) => {
|
||||||
|
if (e.code === 'Escape') {
|
||||||
|
setIsEmojiChange(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let emojiInput: HTMLInputElement | undefined;
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (isEmojiChange() >= 0) {
|
||||||
|
window.addEventListener('keydown', onKey);
|
||||||
|
setTimeout(() => {
|
||||||
|
setEmojiSearchTerm(() => 'smile')
|
||||||
|
emojiInput?.focus();
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.removeEventListener('keydown', onKey);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={props.id} class={styles.zapSettings}>
|
<div id={props.id} class={styles.zapSettings}>
|
||||||
<div class={styles.defaultZaps}>
|
<div class={styles.defaultZaps}>
|
||||||
<div class={styles.caption}>
|
<div class={styles.caption}>
|
||||||
Set default zap amount:
|
Set default zap amount:
|
||||||
</div>
|
</div>
|
||||||
<input
|
<div
|
||||||
type='text'
|
|
||||||
class={styles.zapInput}
|
class={styles.zapInput}
|
||||||
value={settings?.defaultZapAmount}
|
>
|
||||||
onInput={changeDefaultZap}
|
<input
|
||||||
|
class={styles.defAmount}
|
||||||
|
type='text'
|
||||||
|
value={settings?.defaultZap.amount}
|
||||||
|
onInput={changeDefaultZapAmount}
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
class={styles.defMessage}
|
||||||
|
type='text'
|
||||||
|
value={settings?.defaultZap.message}
|
||||||
|
onInput={changeDefaultZapMessage}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class={styles.customZaps}>
|
<div class={styles.customZaps}>
|
||||||
<div class={styles.caption}>
|
<div class={styles.caption}>
|
||||||
@ -67,13 +135,27 @@ const SettingsZap: Component<{ id?: string }> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div class={styles.zapOptions}>
|
<div class={styles.zapOptions}>
|
||||||
<For each={settings?.availableZapOptions}>
|
<For each={settings?.availableZapOptions}>
|
||||||
{(value, index) =>
|
{(option, index) =>
|
||||||
|
<div class={styles.zapInput}>
|
||||||
|
<button
|
||||||
|
class={styles.optEmoji}
|
||||||
|
onClick={(e: MouseEvent) => setIsEmojiChange(index())}
|
||||||
|
>
|
||||||
|
{option.emoji}
|
||||||
|
</button>
|
||||||
<input
|
<input
|
||||||
|
class={styles.optAmount}
|
||||||
type='text'
|
type='text'
|
||||||
class={styles.zapInput}
|
value={option.amount}
|
||||||
value={value}
|
onInput={(e: InputEvent) => changeZapOptionAmount(e, index())}
|
||||||
onInput={(e: InputEvent) => changeZapOptions(e, index())}
|
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
class={styles.optMessage}
|
||||||
|
type='text'
|
||||||
|
value={option.message}
|
||||||
|
onInput={(e: InputEvent) => changeZapOptionMessage(e, index())}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
@ -93,6 +175,36 @@ const SettingsZap: Component<{ id?: string }> = (props) => {
|
|||||||
onConfirm={onRestoreZaps}
|
onConfirm={onRestoreZaps}
|
||||||
onAbort={() => setIsRestoringZaps(false)}
|
onAbort={() => setIsRestoringZaps(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
open={isEmojiChange() >= 0}
|
||||||
|
onBackdropClick={() => setIsEmojiChange(-1)}
|
||||||
|
>
|
||||||
|
<div id={props.id} class={styles.zapEmojiChangeModal}>
|
||||||
|
<div class={styles.title}>
|
||||||
|
{intl.formatMessage(t.zapEmojiFilterTitle)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class={styles.xClose} onClick={() => setIsEmojiChange(-1)}>
|
||||||
|
<div class={styles.iconClose}></div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<input
|
||||||
|
ref={emojiInput}
|
||||||
|
onInput={(e: InputEvent) => {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
setEmojiSearchTerm(() => target.value);
|
||||||
|
}}
|
||||||
|
placeholder={intl.formatMessage(t.zapEmojiFilterPlaceholder)}
|
||||||
|
>
|
||||||
|
</input>
|
||||||
|
|
||||||
|
<EmojiPicker
|
||||||
|
filter={emojiSearchTerm()}
|
||||||
|
onSelect={changeZapOptionEmoji}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { ContentModeration, FeedPage, Filterlist, } from "./types/primal";
|
import { ContentModeration, FeedPage, } from "./types/primal";
|
||||||
import logoFire from './assets/icons/logo_fire.svg';
|
import logoFire from './assets/icons/logo_fire.svg';
|
||||||
import logoIce from './assets/icons/logo_ice.svg';
|
import logoIce from './assets/icons/logo_ice.svg';
|
||||||
import { MessageDescriptor } from "@cookbook/solid-intl";
|
|
||||||
import { linkPreviews } from "./lib/notes";
|
|
||||||
|
|
||||||
export const second = 1000;
|
export const second = 1000;
|
||||||
export const minute = 60 * second;
|
export const minute = 60 * second;
|
||||||
@ -308,15 +306,15 @@ export const apkLink = `https://github.com/PrimalHQ/primal-android-app/releases/
|
|||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
||||||
export const defaultZapAmount = 42;
|
export const defaultZap = { "amount": 42, "message": "Onward 🫡" };
|
||||||
|
|
||||||
export const defaultZapOptions = [
|
export const defaultZapOptions = [
|
||||||
21,
|
{ emoji: '👍', amount: 21, message: 'Great post 👍' },
|
||||||
420,
|
{ emoji: '🚀', amount: 420, message: 'Let\'s go 🚀' },
|
||||||
1_000,
|
{ emoji: '☕', amount: 1_000, message: 'Coffie on me ☕' },
|
||||||
5_000,
|
{ emoji: '🍻', amount: 5_000, message: 'Cheers 🍻' },
|
||||||
10_000,
|
{ emoji: '🍷', amount: 10_000, message: 'Party time 🍷' },
|
||||||
100_000,
|
{ emoji: '👑', amount: 100_000, message: 'Generational wealth 👑' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const contentScope = 'content';
|
export const contentScope = 'content';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createStore } from "solid-js/store";
|
import { createStore } from "solid-js/store";
|
||||||
import { useToastContext } from "../components/Toaster/Toaster";
|
import { useToastContext } from "../components/Toaster/Toaster";
|
||||||
import { contentScope, defaultContentModeration, defaultFeeds, defaultNotificationSettings, defaultZapAmount, defaultZapOptions, nostrHighlights, themes, trendingFeed, trendingScope } from "../constants";
|
import { contentScope, defaultContentModeration, defaultFeeds, defaultNotificationSettings, defaultZap, defaultZapOptions, nostrHighlights, themes, trendingFeed, trendingScope } from "../constants";
|
||||||
import {
|
import {
|
||||||
createContext,
|
createContext,
|
||||||
createEffect,
|
createEffect,
|
||||||
@ -20,6 +20,7 @@ import {
|
|||||||
ContextChildren,
|
ContextChildren,
|
||||||
PrimalFeed,
|
PrimalFeed,
|
||||||
PrimalTheme,
|
PrimalTheme,
|
||||||
|
ZapOption,
|
||||||
} from "../types/primal";
|
} from "../types/primal";
|
||||||
import {
|
import {
|
||||||
initAvailableFeeds,
|
initAvailableFeeds,
|
||||||
@ -35,8 +36,6 @@ import { APP_ID } from "../App";
|
|||||||
import { useIntl } from "@cookbook/solid-intl";
|
import { useIntl } from "@cookbook/solid-intl";
|
||||||
import { hexToNpub } from "../lib/keys";
|
import { hexToNpub } from "../lib/keys";
|
||||||
import { settings as t } from "../translations";
|
import { settings as t } from "../translations";
|
||||||
import { getFilterlists } from "../lib/profile";
|
|
||||||
|
|
||||||
|
|
||||||
export type SettingsContextStore = {
|
export type SettingsContextStore = {
|
||||||
locale: string,
|
locale: string,
|
||||||
@ -44,8 +43,8 @@ export type SettingsContextStore = {
|
|||||||
themes: PrimalTheme[],
|
themes: PrimalTheme[],
|
||||||
availableFeeds: PrimalFeed[],
|
availableFeeds: PrimalFeed[],
|
||||||
defaultFeed: PrimalFeed,
|
defaultFeed: PrimalFeed,
|
||||||
defaultZapAmount: number,
|
defaultZap: ZapOption,
|
||||||
availableZapOptions: number[],
|
availableZapOptions: ZapOption[],
|
||||||
notificationSettings: Record<string, boolean>,
|
notificationSettings: Record<string, boolean>,
|
||||||
applyContentModeration: boolean,
|
applyContentModeration: boolean,
|
||||||
contentModeration: ContentModeration[],
|
contentModeration: ContentModeration[],
|
||||||
@ -58,8 +57,8 @@ export type SettingsContextStore = {
|
|||||||
renameAvailableFeed: (feed: PrimalFeed, newName: string) => void,
|
renameAvailableFeed: (feed: PrimalFeed, newName: string) => void,
|
||||||
saveSettings: () => void,
|
saveSettings: () => void,
|
||||||
loadSettings: (pubkey: string) => void,
|
loadSettings: (pubkey: string) => void,
|
||||||
setDefaultZapAmount: (amount: number) => void,
|
setDefaultZapAmount: (option: ZapOption, temp?: boolean) => void,
|
||||||
setZapOptions: (amount:number, index: number) => void,
|
setZapOptions: (option: ZapOption, index: number, temp?: boolean) => void,
|
||||||
resetZapOptionsToDefault: (temp?: boolean) => void,
|
resetZapOptionsToDefault: (temp?: boolean) => void,
|
||||||
updateNotificationSettings: (key: string, value: boolean, temp?: boolean) => void,
|
updateNotificationSettings: (key: string, value: boolean, temp?: boolean) => void,
|
||||||
restoreDefaultFeeds: () => void,
|
restoreDefaultFeeds: () => void,
|
||||||
@ -74,7 +73,7 @@ export const initialData = {
|
|||||||
themes,
|
themes,
|
||||||
availableFeeds: [],
|
availableFeeds: [],
|
||||||
defaultFeed: defaultFeeds[0],
|
defaultFeed: defaultFeeds[0],
|
||||||
defaultZapAmount: defaultZapAmount,
|
defaultZap: defaultZap,
|
||||||
availableZapOptions: defaultZapOptions,
|
availableZapOptions: defaultZapOptions,
|
||||||
notificationSettings: { ...defaultNotificationSettings },
|
notificationSettings: { ...defaultNotificationSettings },
|
||||||
applyContentModeration: true,
|
applyContentModeration: true,
|
||||||
@ -92,13 +91,13 @@ export const SettingsProvider = (props: { children: ContextChildren }) => {
|
|||||||
|
|
||||||
// ACTIONS --------------------------------------
|
// ACTIONS --------------------------------------
|
||||||
|
|
||||||
const setDefaultZapAmount = (amount: number, temp?: boolean) => {
|
const setDefaultZapAmount = (option: ZapOption, temp?: boolean) => {
|
||||||
updateStore('defaultZapAmount', () => amount);
|
updateStore('defaultZap', () => option);
|
||||||
!temp && saveSettings();
|
!temp && saveSettings();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setZapOptions = (amount: number, index: number, temp?: boolean) => {
|
const setZapOptions = (option: ZapOption, index: number, temp?: boolean) => {
|
||||||
updateStore('availableZapOptions', index, () => amount);
|
updateStore('availableZapOptions', index, () => ({ ...option }));
|
||||||
!temp && saveSettings();
|
!temp && saveSettings();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,11 +110,11 @@ export const SettingsProvider = (props: { children: ContextChildren }) => {
|
|||||||
try {
|
try {
|
||||||
const settings = JSON.parse(content?.content);
|
const settings = JSON.parse(content?.content);
|
||||||
|
|
||||||
let options = settings.zapOptions as number[];
|
let options = settings.zapConfig;
|
||||||
let amount = settings.defaultZapAmount as number;
|
let amount = settings.zapDefault;
|
||||||
|
|
||||||
updateStore('availableZapOptions', () => options);
|
updateStore('availableZapOptions', () => options);
|
||||||
updateStore('defaultZapAmount', () => amount);
|
updateStore('defaultZap', () => amount);
|
||||||
|
|
||||||
!temp && saveSettings();
|
!temp && saveSettings();
|
||||||
}
|
}
|
||||||
@ -289,8 +288,8 @@ export const SettingsProvider = (props: { children: ContextChildren }) => {
|
|||||||
const settings = {
|
const settings = {
|
||||||
theme: store.theme,
|
theme: store.theme,
|
||||||
feeds: store.availableFeeds,
|
feeds: store.availableFeeds,
|
||||||
defaultZapAmount: store.defaultZapAmount,
|
defaultZap: store.defaultZap,
|
||||||
zapOptions: store.availableZapOptions,
|
zapConfig: store.availableZapOptions,
|
||||||
notifications: store.notificationSettings,
|
notifications: store.notificationSettings,
|
||||||
applyContentModeration: store.applyContentModeration,
|
applyContentModeration: store.applyContentModeration,
|
||||||
contentModeration: store.contentModeration,
|
contentModeration: store.contentModeration,
|
||||||
@ -336,11 +335,10 @@ export const SettingsProvider = (props: { children: ContextChildren }) => {
|
|||||||
updateStore('notificationSettings', () => ({ ...notificationSettings } || { ...defaultNotificationSettings }));
|
updateStore('notificationSettings', () => ({ ...notificationSettings } || { ...defaultNotificationSettings }));
|
||||||
updateStore('applyContentModeration', () => true);
|
updateStore('applyContentModeration', () => true);
|
||||||
|
|
||||||
|
let zapOptions = settings.zapConfig;
|
||||||
|
let zapAmount = settings.zapDefault;
|
||||||
|
|
||||||
let zapOptions = settings.zapOptions as number[];
|
updateStore('defaultZap', () => zapAmount);
|
||||||
let zapAmount = settings.defaultZapAmount as number;
|
|
||||||
|
|
||||||
updateStore('defaultZapAmount', () => zapAmount);
|
|
||||||
updateStore('availableZapOptions', () => zapOptions);
|
updateStore('availableZapOptions', () => zapOptions);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
@ -378,16 +376,16 @@ export const SettingsProvider = (props: { children: ContextChildren }) => {
|
|||||||
const {
|
const {
|
||||||
theme,
|
theme,
|
||||||
feeds,
|
feeds,
|
||||||
defaultZapAmount,
|
zapDefault,
|
||||||
zapOptions,
|
zapConfig,
|
||||||
notifications,
|
notifications,
|
||||||
applyContentModeration,
|
applyContentModeration,
|
||||||
contentModeration,
|
contentModeration,
|
||||||
} = JSON.parse(content?.content);
|
} = JSON.parse(content?.content);
|
||||||
|
|
||||||
theme && setThemeByName(theme, true);
|
theme && setThemeByName(theme, true);
|
||||||
defaultZapAmount && setDefaultZapAmount(defaultZapAmount, true);
|
zapDefault && setDefaultZapAmount(zapDefault, true);
|
||||||
zapOptions && updateStore('availableZapOptions', () => zapOptions);
|
zapConfig && updateStore('availableZapOptions', () => zapConfig);
|
||||||
|
|
||||||
if (notifications) {
|
if (notifications) {
|
||||||
updateStore('notificationSettings', () => ({ ...notifications }));
|
updateStore('notificationSettings', () => ({ ...notifications }));
|
||||||
|
@ -1429,6 +1429,16 @@ export const settings = {
|
|||||||
defaultMessage: 'This action will restore all your zap settings to their default values',
|
defaultMessage: 'This action will restore all your zap settings to their default values',
|
||||||
description: 'Label explaining the impact of restoring default zaps',
|
description: 'Label explaining the impact of restoring default zaps',
|
||||||
},
|
},
|
||||||
|
zapEmojiFilterTitle: {
|
||||||
|
id: 'settings.zapEmojiFilterTitle',
|
||||||
|
defaultMessage: 'Select an emoji',
|
||||||
|
description: 'Title for the select emoji modal',
|
||||||
|
},
|
||||||
|
zapEmojiFilterPlaceholder: {
|
||||||
|
id: 'settings.zapEmojiFilterPlaceholder',
|
||||||
|
defaultMessage: 'Type to filter...',
|
||||||
|
description: 'Placeholder for the emoji modal filter',
|
||||||
|
},
|
||||||
feedLatest: {
|
feedLatest: {
|
||||||
id: 'feeds.feedLatest',
|
id: 'feeds.feedLatest',
|
||||||
defaultMessage: 'Latest',
|
defaultMessage: 'Latest',
|
||||||
|
6
src/types/primal.d.ts
vendored
6
src/types/primal.d.ts
vendored
@ -623,3 +623,9 @@ export type SelectionOption = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type NotificationGroup = 'all' | 'zaps' | 'replies' | 'mentions' | 'reposts';
|
export type NotificationGroup = 'all' | 'zaps' | 'replies' | 'mentions' | 'reposts';
|
||||||
|
|
||||||
|
export type ZapOption = {
|
||||||
|
emoji?: string,
|
||||||
|
amount?: number,
|
||||||
|
message?: string,
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user