diff --git a/src/app/components/ChatMessageMenuMobile.svelte b/src/app/components/ChatMessageMenuMobile.svelte index 83d5f1a2..38e31877 100644 --- a/src/app/components/ChatMessageMenuMobile.svelte +++ b/src/app/components/ChatMessageMenuMobile.svelte @@ -6,9 +6,12 @@ import Reply from "@assets/icons/reply-2.svg?dataurl" import Copy from "@assets/icons/copy.svg?dataurl" import Code2 from "@assets/icons/code-2.svg?dataurl" + import AltArrowDown from "@assets/icons/alt-arrow-down.svg?dataurl" + import AltArrowUp from "@assets/icons/alt-arrow-up.svg?dataurl" import Icon from "@lib/components/Icon.svelte" import Modal from "@lib/components/Modal.svelte" import ModalBody from "@lib/components/ModalBody.svelte" + import {slideAndFade} from "@lib/transition" import Button from "@lib/components/Button.svelte" import EmojiPicker from "@lib/components/EmojiPicker.svelte" import EventInfo from "@app/components/EventInfo.svelte" @@ -25,6 +28,8 @@ const {event, pubkeys, reply, edit}: Props = $props() + const tile = "button h-auto flex-col gap-1.5 py-4 text-xs" + const onEmoji = async (emoji: NativeEmoji) => { history.back() @@ -51,33 +56,49 @@ } const showInfo = () => pushModal(EventInfo, {event}, {replaceState: true}) + + const toggleMore = () => { + showMore = !showMore + } + + let showMore = $state(false) -
- - -
+
+ - {#if edit} - + {#if showMore} +
+ {#if edit} + + {/if} + + +
{/if} -
diff --git a/src/app/components/RoomItemMenuMobile.svelte b/src/app/components/RoomItemMenuMobile.svelte index fbef7ef4..0ca0cbc5 100644 --- a/src/app/components/RoomItemMenuMobile.svelte +++ b/src/app/components/RoomItemMenuMobile.svelte @@ -4,14 +4,18 @@ import * as nip19 from "nostr-tools/nip19" import {getIdOrAddress, tagSpec, tagValue, toNostrURI} from "@welshman/util" import Bolt from "@assets/icons/bolt.svg?dataurl" + import Pen from "@assets/icons/pen.svg?dataurl" import Reply from "@assets/icons/reply-2.svg?dataurl" import ShareCircle from "@assets/icons/share-circle.svg?dataurl" import Code2 from "@assets/icons/code-2.svg?dataurl" import TrashBin2 from "@assets/icons/trash-bin-2.svg?dataurl" import SmileCircle from "@assets/icons/smile-circle.svg?dataurl" import MenuDots from "@assets/icons/menu-dots.svg?dataurl" + import AltArrowDown from "@assets/icons/alt-arrow-down.svg?dataurl" + import AltArrowUp from "@assets/icons/alt-arrow-up.svg?dataurl" import Pin from "@assets/icons/pin.svg?dataurl" import NotesMinimalistic from "@assets/icons/notes-minimalistic.svg?dataurl" + import {slideAndFade} from "@lib/transition" import Button from "@lib/components/Button.svelte" import Link from "@lib/components/Link.svelte" import Icon from "@lib/components/Icon.svelte" @@ -34,15 +38,17 @@ url: string event: TrustedEvent reply: () => void + edit?: () => void } - const {url, event, reply}: Props = $props() + const {url, event, reply, edit}: Props = $props() const h = tagValue(tagSpec(ROOM), event.tags) ?? "" const path = makeContentPath(url, event.kind, getIdOrAddress(event)) const pinIds = $roomPinLists.pins(url, h).$ const userIsRoomAdmin = deriveUserIsRoomAdmin(url, h) const isPinned = $derived($pinIds.includes(event.id)) + const tile = "button h-auto flex-col gap-1.5 py-4 text-xs" const onEmoji = async (emoji: NativeEmoji) => { history.back() @@ -67,6 +73,11 @@ reply() } + const sendEdit = () => { + history.back() + edit?.() + } + const share = () => { history.back() shareEvent(url, "Message", event) @@ -76,6 +87,10 @@ const showDelete = () => pushModal(EventDeleteConfirm, {url, event}) + const toggleMore = () => { + showMore = !showMore + } + const togglePin = async () => { if (!h) return @@ -91,57 +106,75 @@ pushToast({message: isPinned ? "Message unpinned" : "Message pinned"}) } } + + let showMore = $state(false) -
- {#if event.pubkey === $user.pubkey} - - {/if} - - - {#if path} - - - View Details - - {/if} - {#if h && $userIsRoomAdmin} - - {/if} - {#if h} - - {/if} +
{#if ENABLE_ZAPS} - - - Send Zap + + + Zap {/if} - -
+
+ + {#if showMore} +
+ {#if edit} + + {/if} + + {#if h} + + {/if} + {#if h && $userIsRoomAdmin} + + {/if} + {#if path} + + + View Details + + {/if} + + {#if event.pubkey === $user.pubkey} + + {/if} +
+ {/if} +
diff --git a/src/lib/components/button.css b/src/lib/components/button.css index 95d5c62e..56b819db 100644 --- a/src/lib/components/button.css +++ b/src/lib/components/button.css @@ -30,13 +30,14 @@ } } - /* secondary — outline that fills on hover */ + /* secondary — solid fill that darkens on hover */ .button-secondary { - @apply bg-surface text-secondary border-secondary; + @apply bg-secondary text-secondary-content; + border-color: rgba(0, 0, 0, 0.1); box-shadow: var(--shadow-sm); &:hover { - @apply bg-secondary text-secondary-content; + @apply bg-secondary-bold; } } @@ -80,15 +81,41 @@ } } - /* outline */ + /* outline — border and text carry the color, fill arrives on hover. Stands + alone as a neutral outline, or pairs with a color class. */ .button-outline { - @apply text-content bg-transparent; + @apply text-content border-line bg-transparent; + box-shadow: var(--shadow-sm); &:hover { @apply border-primary text-primary; } } + .button-outline.button-primary { + @apply text-primary border-primary bg-transparent; + + &:hover { + @apply bg-primary text-primary-content; + } + } + + .button-outline.button-secondary { + @apply text-secondary border-secondary bg-transparent; + + &:hover { + @apply bg-secondary text-secondary-content; + } + } + + .button-outline.button-error { + @apply text-error border-error bg-transparent; + + &:hover { + @apply bg-error text-error-content; + } + } + /* sizes — height is explicit (not derived from padding/line-height) so sm/xs reliably change the button height even when the content is a fixed-size icon */ .button, @@ -139,30 +166,41 @@ } } -[data-fl-theme="clay"] .button-primary, -[data-fl-theme="clay"] .button-error { +/* these are unlayered, so they beat the @layer rules above no matter their + specificity — hence the :not(.button-outline) on every filled variant */ +[data-fl-theme="clay"] .button-primary:not(.button-outline), +[data-fl-theme="clay"] .button-secondary:not(.button-outline), +[data-fl-theme="clay"] .button-error:not(.button-outline) { box-shadow: var(--shadow-sm), var(--shadow-inset-strong); } /* hover lift + bigger offset shadow; active press + smaller offset shadow */ -[data-fl-theme="clay"] .button-primary:hover { +[data-fl-theme="clay"] .button-primary:not(.button-outline):hover { background: var(--primary-bold); transform: translateY(-2px); box-shadow: 6px 6px 0 rgba(var(--shadow-color), 0.3), var(--shadow-inset-strong); } -[data-fl-theme="clay"] .button-secondary:hover, +[data-fl-theme="clay"] .button-secondary:not(.button-outline):hover { + background: var(--secondary-bold); + transform: translateY(-2px); + box-shadow: + 6px 6px 0 rgba(var(--shadow-color), 0.3), + var(--shadow-inset-strong); +} [data-fl-theme="clay"] .button-neutral:hover, -[data-fl-theme="clay"] .button-error:hover { +[data-fl-theme="clay"] .button-outline:hover, +[data-fl-theme="clay"] .button-error:not(.button-outline):hover { transform: translateY(-2px); } -[data-fl-theme="clay"] .button-primary:active, -[data-fl-theme="clay"] .button-secondary:active, -[data-fl-theme="clay"] .button-neutral:active { +[data-fl-theme="clay"] .button-primary:not(.button-outline):active, +[data-fl-theme="clay"] .button-secondary:not(.button-outline):active, +[data-fl-theme="clay"] .button-neutral:active, +[data-fl-theme="clay"] .button-outline:active { transform: translateY(2px); box-shadow: 2px 2px 0 rgba(var(--shadow-color), 0.3); } -[data-fl-theme="clay"] .button-error:active { +[data-fl-theme="clay"] .button-error:not(.button-outline):active { transform: translateY(2px); }