feat: classnames
This commit is contained in:
@ -18,6 +18,7 @@
|
|||||||
"@types/use-sync-external-store": "^0.0.4",
|
"@types/use-sync-external-store": "^0.0.4",
|
||||||
"@uidotdev/usehooks": "^2.3.1",
|
"@uidotdev/usehooks": "^2.3.1",
|
||||||
"@void-cat/api": "^1.0.10",
|
"@void-cat/api": "^1.0.10",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"dexie": "^3.2.4",
|
"dexie": "^3.2.4",
|
||||||
"emojilib": "^3.0.10",
|
"emojilib": "^3.0.10",
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { useState, ReactNode } from "react";
|
import { useState, ReactNode } from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
import ShowMore from "Element/Event/ShowMore";
|
import ShowMore from "Element/Event/ShowMore";
|
||||||
@ -38,15 +39,13 @@ interface CollapsedSectionProps {
|
|||||||
export const CollapsedSection = ({ title, children, className }: CollapsedSectionProps) => {
|
export const CollapsedSection = ({ title, children, className }: CollapsedSectionProps) => {
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
const [collapsed, setCollapsed] = useState(true);
|
||||||
const icon = (
|
const icon = (
|
||||||
<div className={`collapse-icon ${collapsed ? "" : "flip"}`}>
|
<div className={classNames("collapse-icon", { flip: !collapsed })}>
|
||||||
<Icon name="arrowFront" />
|
<Icon name="arrowFront" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div className={classNames("collapsable-section", className)} onClick={() => setCollapsed(!collapsed)}>
|
||||||
className={`collapsable-section${className ? ` ${className}` : ""}`}
|
|
||||||
onClick={() => setCollapsed(!collapsed)}>
|
|
||||||
{title}
|
{title}
|
||||||
<CollapsedIcon icon={icon} collapsed={collapsed} />
|
<CollapsedIcon icon={icon} collapsed={collapsed} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import "./Copy.css";
|
import "./Copy.css";
|
||||||
|
import classNames from "classnames";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
import { useCopy } from "useCopy";
|
import { useCopy } from "useCopy";
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ export default function Copy({ text, maxSize = 32, className }: CopyProps) {
|
|||||||
const trimmed = text.length > maxSize ? `${text.slice(0, sliceLength)}...${text.slice(-sliceLength)}` : text;
|
const trimmed = text.length > maxSize ? `${text.slice(0, sliceLength)}...${text.slice(-sliceLength)}` : text;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`copy flex pointer g8${className ? ` ${className}` : ""}`} onClick={() => copy(text)}>
|
<div className={classNames("copy flex pointer g8", className)} onClick={() => copy(text)}>
|
||||||
<span className="copy-body">{trimmed}</span>
|
<span className="copy-body">{trimmed}</span>
|
||||||
<span className="icon" style={{ color: copied ? "var(--success)" : "var(--highlight)" }}>
|
<span className="icon" style={{ color: copied ? "var(--success)" : "var(--highlight)" }}>
|
||||||
{copied ? <Icon name="check" size={14} /> : <Icon name="copy-solid" size={14} />}
|
{copied ? <Icon name="check" size={14} /> : <Icon name="copy-solid" size={14} />}
|
||||||
|
@ -3,6 +3,7 @@ import { useState } from "react";
|
|||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { decodeInvoice } from "@snort/shared";
|
import { decodeInvoice } from "@snort/shared";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import SendSats from "Element/SendSats";
|
import SendSats from "Element/SendSats";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
@ -60,7 +61,7 @@ export default function Invoice(props: InvoiceProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={`note-invoice flex ${isExpired ? "expired" : ""} ${isPaid ? "paid" : ""}`}>
|
<div className={classNames("note-invoice flex", { expired: isExpired, paid: isPaid })}>
|
||||||
<div className="invoice-header">{header()}</div>
|
<div className="invoice-header">{header()}</div>
|
||||||
|
|
||||||
<p className="invoice-amount">
|
<p className="invoice-amount">
|
||||||
|
@ -8,6 +8,7 @@ import useLogin from "Hooks/useLogin";
|
|||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
import { useNoteCreator } from "State/NoteCreator";
|
import { useNoteCreator } from "State/NoteCreator";
|
||||||
import { NoteCreator } from "./NoteCreator";
|
import { NoteCreator } from "./NoteCreator";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
export const NoteCreatorButton = ({ className }: { className?: string }) => {
|
export const NoteCreatorButton = ({ className }: { className?: string }) => {
|
||||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||||
@ -36,7 +37,7 @@ export const NoteCreatorButton = ({ className }: { className?: string }) => {
|
|||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
ref={buttonRef}
|
ref={buttonRef}
|
||||||
className={`primary circle${className ? ` ${className}` : ""}`}
|
className={classNames("primary circle", className)}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
update(v => {
|
update(v => {
|
||||||
v.replyTo = undefined;
|
v.replyTo = undefined;
|
||||||
|
@ -2,7 +2,9 @@ import { Link, useNavigate } from "react-router-dom";
|
|||||||
import React, { ReactNode, useMemo, useState } from "react";
|
import React, { ReactNode, useMemo, useState } from "react";
|
||||||
import { useInView } from "react-intersection-observer";
|
import { useInView } from "react-intersection-observer";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
import classNames from "classnames";
|
||||||
import { EventExt, EventKind, HexKey, Lists, NostrLink, NostrPrefix, TaggedNostrEvent } from "@snort/system";
|
import { EventExt, EventKind, HexKey, Lists, NostrLink, NostrPrefix, TaggedNostrEvent } from "@snort/system";
|
||||||
|
|
||||||
import { findTag, hexToBech32, profileLink } from "SnortUtils";
|
import { findTag, hexToBech32, profileLink } from "SnortUtils";
|
||||||
import useModeration from "Hooks/useModeration";
|
import useModeration from "Hooks/useModeration";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
@ -27,7 +29,7 @@ import { chainKey } from "Hooks/useThreadContext";
|
|||||||
export function NoteInner(props: NoteProps) {
|
export function NoteInner(props: NoteProps) {
|
||||||
const { data: ev, related, highlight, options: opt, ignoreModeration = false, className } = props;
|
const { data: ev, related, highlight, options: opt, ignoreModeration = false, className } = props;
|
||||||
|
|
||||||
const baseClassName = `note card${className ? ` ${className}` : ""}`;
|
const baseClassName = classNames("note card", className);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [showReactions, setShowReactions] = useState(false);
|
const [showReactions, setShowReactions] = useState(false);
|
||||||
|
|
||||||
@ -328,7 +330,7 @@ export function NoteInner(props: NoteProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const note = (
|
const note = (
|
||||||
<div className={`${baseClassName}${highlight ? " active " : " "}`} onClick={e => goToEvent(e, ev)} ref={ref}>
|
<div className={classNames(baseClassName, { active: highlight })} onClick={e => goToEvent(e, ev)} ref={ref}>
|
||||||
{content()}
|
{content()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -3,6 +3,7 @@ import { useMemo, useState, ReactNode, useContext } from "react";
|
|||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { TaggedNostrEvent, u256, NostrPrefix, EventExt, parseNostrLink, NostrLink } from "@snort/system";
|
import { TaggedNostrEvent, u256, NostrPrefix, EventExt, parseNostrLink, NostrLink } from "@snort/system";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import { getAllLinkReactions, getLinkReactions } from "SnortUtils";
|
import { getAllLinkReactions, getLinkReactions } from "SnortUtils";
|
||||||
import BackButton from "Element/BackButton";
|
import BackButton from "Element/BackButton";
|
||||||
@ -83,14 +84,17 @@ const ThreadNote = ({ active, note, isLast, isLastSubthread, related, chains, on
|
|||||||
const [collapsed, setCollapsed] = useState(!activeInReplies);
|
const [collapsed, setCollapsed] = useState(!activeInReplies);
|
||||||
const hasMultipleNotes = replies.length > 1;
|
const hasMultipleNotes = replies.length > 1;
|
||||||
const isLastVisibleNote = isLastSubthread && isLast && !hasMultipleNotes;
|
const isLastVisibleNote = isLastSubthread && isLast && !hasMultipleNotes;
|
||||||
const className = `subthread-container ${isLast && collapsed ? "subthread-last" : "subthread-multi subthread-mid"}`;
|
const className = classNames(
|
||||||
|
"subthread-container",
|
||||||
|
isLast && collapsed ? "subthread-last" : "subthread-multi subthread-mid",
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<Divider variant="small" />
|
<Divider variant="small" />
|
||||||
<Note
|
<Note
|
||||||
highlight={active === note.id}
|
highlight={active === note.id}
|
||||||
className={`thread-note ${isLastVisibleNote ? "is-last-note" : ""}`}
|
className={classNames("thread-note", { "is-last-note": isLastVisibleNote })}
|
||||||
data={note}
|
data={note}
|
||||||
key={note.id}
|
key={note.id}
|
||||||
related={related}
|
related={related}
|
||||||
@ -156,13 +160,15 @@ const TierThree = ({ active, isLastSubthread, notes, related, chains, onNavigate
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`subthread-container ${hasMultipleNotes ? "subthread-multi" : ""} ${
|
className={classNames("subthread-container", {
|
||||||
isLast ? "subthread-last" : "subthread-mid"
|
"subthread-multi": hasMultipleNotes,
|
||||||
}`}>
|
"subthread-last": isLast,
|
||||||
|
"subthread-mid": !isLast,
|
||||||
|
})}>
|
||||||
<Divider variant="small" />
|
<Divider variant="small" />
|
||||||
<Note
|
<Note
|
||||||
highlight={active === first.id}
|
highlight={active === first.id}
|
||||||
className={`thread-note ${isLastSubthread && isLast ? "is-last-note" : ""}`}
|
className={classNames("thread-note", { "is-last-note": isLastSubthread && isLast })}
|
||||||
data={first}
|
data={first}
|
||||||
key={first.id}
|
key={first.id}
|
||||||
related={related}
|
related={related}
|
||||||
@ -188,12 +194,14 @@ const TierThree = ({ active, isLastSubthread, notes, related, chains, onNavigate
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={r.id}
|
key={r.id}
|
||||||
className={`subthread-container ${lastReply ? "" : "subthread-multi"} ${
|
className={classNames("subthread-container", {
|
||||||
lastReply ? "subthread-last" : "subthread-mid"
|
"subthread-multi": !lastReply,
|
||||||
}`}>
|
"subthread-last": !lastReply,
|
||||||
|
"subthread-mid": lastReply,
|
||||||
|
})}>
|
||||||
<Divider variant="small" />
|
<Divider variant="small" />
|
||||||
<Note
|
<Note
|
||||||
className={`thread-note ${lastNote ? "is-last-note" : ""}`}
|
className={classNames("thread-note", { "is-last-note": lastNote })}
|
||||||
highlight={active === r.id}
|
highlight={active === r.id}
|
||||||
data={r}
|
data={r}
|
||||||
key={r.id}
|
key={r.id}
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
|
import Icon, { IconProps } from "Icons/Icon";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
interface IconButtonProps {
|
interface IconButtonProps {
|
||||||
onClick(): void;
|
onClick?: () => void;
|
||||||
children: ReactNode;
|
icon: IconProps;
|
||||||
|
className?: string;
|
||||||
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IconButton = ({ onClick, children }: IconButtonProps) => {
|
const IconButton = ({ onClick, icon, children, className }: IconButtonProps) => {
|
||||||
return (
|
return (
|
||||||
<button className="icon" type="button" onClick={onClick}>
|
<button className={classNames("icon", className)} type="button" onClick={onClick}>
|
||||||
<div className="icon-wrapper">{children}</div>
|
<Icon {...icon} />
|
||||||
|
{children}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import "./Text.css";
|
import "./Text.css";
|
||||||
import { ReactNode, useState } from "react";
|
import { ReactNode, useState } from "react";
|
||||||
import { HexKey, ParsedFragment } from "@snort/system";
|
import { HexKey, ParsedFragment } from "@snort/system";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import Invoice from "Element/Embed/Invoice";
|
import Invoice from "Element/Embed/Invoice";
|
||||||
import Hashtag from "Element/Embed/Hashtag";
|
import Hashtag from "Element/Embed/Hashtag";
|
||||||
@ -276,7 +277,7 @@ export default function Text({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div dir="auto" className={`text${className ? ` ${className}` : ""}`} onClick={onClick}>
|
<div dir="auto" className={classNames("text", className)} onClick={onClick}>
|
||||||
{renderContent()}
|
{renderContent()}
|
||||||
{showSpotlight && <SpotlightMediaModal images={images} onClose={() => setShowSpotlight(false)} idx={imageIdx} />}
|
{showSpotlight && <SpotlightMediaModal images={images} onClose={() => setShowSpotlight(false)} idx={imageIdx} />}
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,6 +2,7 @@ import "./Avatar.css";
|
|||||||
|
|
||||||
import { CSSProperties, ReactNode, useEffect, useState } from "react";
|
import { CSSProperties, ReactNode, useEffect, useState } from "react";
|
||||||
import type { UserMetadata } from "@snort/system";
|
import type { UserMetadata } from "@snort/system";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import useImgProxy from "Hooks/useImgProxy";
|
import useImgProxy from "Hooks/useImgProxy";
|
||||||
import { getDisplayName } from "Element/User/DisplayName";
|
import { getDisplayName } from "Element/User/DisplayName";
|
||||||
@ -44,7 +45,7 @@ const Avatar = ({ pubkey, user, size, onClick, image, imageOverlay, icons, class
|
|||||||
<div
|
<div
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
style={style}
|
style={style}
|
||||||
className={`avatar${imageOverlay ? " with-overlay" : ""} ${className ?? ""}`}
|
className={classNames("avatar", { "with-overlay": imageOverlay }, className)}
|
||||||
data-domain={domain?.toLowerCase()}
|
data-domain={domain?.toLowerCase()}
|
||||||
title={getDisplayName(user, "")}>
|
title={getDisplayName(user, "")}>
|
||||||
{icons && <div className="icons">{icons}</div>}
|
{icons && <div className="icons">{icons}</div>}
|
||||||
|
@ -2,6 +2,7 @@ import "./NoteToSelf.css";
|
|||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import FormattedMessage from "Element/FormattedMessage";
|
import FormattedMessage from "Element/FormattedMessage";
|
||||||
import { profileLink } from "SnortUtils";
|
import { profileLink } from "SnortUtils";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import messages from "../messages";
|
import messages from "../messages";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
@ -31,9 +32,9 @@ export default function NoteToSelf({ pubkey, clickable, className, link }: NoteT
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`nts${className ? ` ${className}` : ""}`}>
|
<div className={classNames("nts", className)}>
|
||||||
<div className="avatar-wrapper">
|
<div className="avatar-wrapper">
|
||||||
<div className={`avatar${clickable ? " clickable" : ""}`}>
|
<div className={classNames("avatar", { clickable: clickable })}>
|
||||||
<Icon onClick={clickLink} name="book-closed" size={20} />
|
<Icon onClick={clickLink} name="book-closed" size={20} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,6 +6,7 @@ import { HexKey, UserMetadata } from "@snort/system";
|
|||||||
import { useUserProfile } from "@snort/system-react";
|
import { useUserProfile } from "@snort/system-react";
|
||||||
import { useHover } from "@uidotdev/usehooks";
|
import { useHover } from "@uidotdev/usehooks";
|
||||||
import { ControlledMenu } from "@szhsin/react-menu";
|
import { ControlledMenu } from "@szhsin/react-menu";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import { profileLink } from "SnortUtils";
|
import { profileLink } from "SnortUtils";
|
||||||
import Avatar from "Element/User/Avatar";
|
import Avatar from "Element/User/Avatar";
|
||||||
@ -157,7 +158,7 @@ export default function ProfileImage({
|
|||||||
if (link === "") {
|
if (link === "") {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={`pfp${className ? ` ${className}` : ""}`} onClick={handleClick}>
|
<div className={classNames("pfp", className)} onClick={handleClick}>
|
||||||
{inner()}
|
{inner()}
|
||||||
</div>
|
</div>
|
||||||
{profileCard()}
|
{profileCard()}
|
||||||
@ -167,7 +168,7 @@ export default function ProfileImage({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Link
|
<Link
|
||||||
className={`pfp${className ? ` ${className}` : ""}`}
|
className={classNames("pfp", className)}
|
||||||
to={link === undefined ? profileLink(pubkey) : link}
|
to={link === undefined ? profileLink(pubkey) : link}
|
||||||
onClick={handleClick}>
|
onClick={handleClick}>
|
||||||
{inner()}
|
{inner()}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import IconProps from "./IconProps";
|
export const BlueWallet = (props: { width?: number; height?: number }) => {
|
||||||
|
|
||||||
export const BlueWallet = (props: IconProps) => {
|
|
||||||
return (
|
return (
|
||||||
<svg width="58px" height="58px" viewBox="0 0 58 58" version="1.1" xmlns="http://www.w3.org/2000/svg" {...props}>
|
<svg viewBox="0 0 58 58" version="1.1" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||||
<title>logo-bluewallet</title>
|
<title>logo-bluewallet</title>
|
||||||
<defs>
|
<defs>
|
||||||
<filter x="-14.0%" y="-13.8%" width="128.1%" height="127.6%" filterUnits="objectBoundingBox" id="filter-1">
|
<filter x="-14.0%" y="-13.8%" width="128.1%" height="127.6%" filterUnits="objectBoundingBox" id="filter-1">
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { MouseEventHandler } from "react";
|
import { MouseEventHandler } from "react";
|
||||||
import IconsSvg from "public/icons.svg";
|
import IconsSvg from "public/icons.svg";
|
||||||
|
|
||||||
type Props = {
|
export interface IconProps {
|
||||||
name: string;
|
name: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
className?: string;
|
className?: string;
|
||||||
onClick?: MouseEventHandler<SVGSVGElement>;
|
onClick?: MouseEventHandler<SVGSVGElement>;
|
||||||
};
|
}
|
||||||
|
|
||||||
const Icon = (props: Props) => {
|
const Icon = (props: IconProps) => {
|
||||||
const size = props.size || 20;
|
const size = props.size || 20;
|
||||||
const href = `${IconsSvg}#` + props.name;
|
const href = `${IconsSvg}#` + props.name;
|
||||||
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
export default interface IconProps {
|
|
||||||
className?: string;
|
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
}
|
|
@ -1,6 +1,4 @@
|
|||||||
import IconProps from "./IconProps";
|
export default function NostrIcon(props: { width?: number; height?: number }) {
|
||||||
|
|
||||||
export default function NostrIcon(props: IconProps) {
|
|
||||||
return (
|
return (
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 116.446 84.924" {...props}>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 116.446 84.924" {...props}>
|
||||||
<path
|
<path
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import IconProps from "./IconProps";
|
|
||||||
import "./Spinner.css";
|
import "./Spinner.css";
|
||||||
|
|
||||||
const Spinner = (props: IconProps) => (
|
const Spinner = (props: { width?: number; height?: number; className?: string }) => (
|
||||||
<svg
|
<svg
|
||||||
width={props.width ?? 20}
|
width={props.width ?? 20}
|
||||||
height={props.height ?? 20}
|
height={props.height ?? 20}
|
||||||
|
@ -53,23 +53,6 @@
|
|||||||
max-height: 300px; /* Cap images in notifications to 300px height */
|
max-height: 300px; /* Cap images in notifications to 300px height */
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-icon {
|
|
||||||
padding: 4px;
|
|
||||||
border-radius: 8px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--gray-light) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary-icon:not(.active):hover {
|
|
||||||
background-color: var(--gray-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary-icon.active {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary-tooltip {
|
.summary-tooltip {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
@ -23,6 +23,7 @@ import ProfilePreview from "Element/User/ProfilePreview";
|
|||||||
import { getDisplayName } from "Element/User/DisplayName";
|
import { getDisplayName } from "Element/User/DisplayName";
|
||||||
import { Day } from "Const";
|
import { Day } from "Const";
|
||||||
import Tabs, { Tab } from "Element/Tabs";
|
import Tabs, { Tab } from "Element/Tabs";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
function notificationContext(ev: TaggedNostrEvent) {
|
function notificationContext(ev: TaggedNostrEvent) {
|
||||||
switch (ev.kind) {
|
switch (ev.kind) {
|
||||||
@ -196,9 +197,12 @@ function NotificationSummary({ evs }: { evs: Array<TaggedNostrEvent> }) {
|
|||||||
const filterIcon = (f: NotificationSummaryFilter, icon: string, iconActiveClass?: string) => {
|
const filterIcon = (f: NotificationSummaryFilter, icon: string, iconActiveClass?: string) => {
|
||||||
const active = hasFlag(filter, f);
|
const active = hasFlag(filter, f);
|
||||||
return (
|
return (
|
||||||
<div className={`summary-icon${active ? " active" : ""}`} onClick={() => setFilter(v => v ^ f)}>
|
<button
|
||||||
|
type="button"
|
||||||
|
className={classNames("icon-sm transparent", { active: active })}
|
||||||
|
onClick={() => setFilter(v => v ^ f)}>
|
||||||
<Icon name={icon} className={active ? iconActiveClass : undefined} />
|
<Icon name={icon} className={active ? iconActiveClass : undefined} />
|
||||||
</div>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -305,10 +305,8 @@ export default function ProfilePage({ id: propId }: ProfilePageProps) {
|
|||||||
|
|
||||||
const link = encodeTLV(NostrPrefix.Profile, id);
|
const link = encodeTLV(NostrPrefix.Profile, id);
|
||||||
return (
|
return (
|
||||||
<div className="icon-actions">
|
<>
|
||||||
<IconButton onClick={() => setShowProfileQr(true)}>
|
<IconButton onClick={() => setShowProfileQr(true)} icon={{ name: "qr", size: 16 }} />
|
||||||
<Icon name="qr" size={16} />
|
|
||||||
</IconButton>
|
|
||||||
{showProfileQr && (
|
{showProfileQr && (
|
||||||
<Modal id="profile-qr" className="qr-modal" onClose={() => setShowProfileQr(false)}>
|
<Modal id="profile-qr" className="qr-modal" onClose={() => setShowProfileQr(false)}>
|
||||||
<ProfileImage pubkey={id} />
|
<ProfileImage pubkey={id} />
|
||||||
@ -324,11 +322,7 @@ export default function ProfilePage({ id: propId }: ProfilePageProps) {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{lnurl && (
|
{lnurl && <IconButton onClick={() => setShowLnQr(true)} icon={{ name: "zap", size: 16 }} />}
|
||||||
<IconButton onClick={() => setShowLnQr(true)}>
|
|
||||||
<Icon name="zap" size={16} />
|
|
||||||
</IconButton>
|
|
||||||
)}
|
|
||||||
{loginPubKey && !login.readonly && (
|
{loginPubKey && !login.readonly && (
|
||||||
<>
|
<>
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -340,14 +334,14 @@ export default function ProfilePage({ id: propId }: ProfilePageProps) {
|
|||||||
value: id,
|
value: id,
|
||||||
})}`,
|
})}`,
|
||||||
)
|
)
|
||||||
}>
|
}
|
||||||
<Icon name="envelope" size={16} />
|
icon={{ name: "envelope", size: 16 }}
|
||||||
</IconButton>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +324,23 @@ button.icon:hover {
|
|||||||
color: var(--highlight);
|
color: var(--highlight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.icon-sm {
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--gray-light) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.icon-sm:not(.active):hover {
|
||||||
|
background-color: var(--gray-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.icon-sm.active {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -2720,6 +2720,7 @@ __metadata:
|
|||||||
"@webpack-cli/generators": ^3.0.4
|
"@webpack-cli/generators": ^3.0.4
|
||||||
"@webscopeio/react-textarea-autocomplete": ^4.9.2
|
"@webscopeio/react-textarea-autocomplete": ^4.9.2
|
||||||
babel-loader: ^9.1.3
|
babel-loader: ^9.1.3
|
||||||
|
classnames: ^2.3.2
|
||||||
config: ^3.3.9
|
config: ^3.3.9
|
||||||
copy-webpack-plugin: ^11.0.0
|
copy-webpack-plugin: ^11.0.0
|
||||||
css-loader: ^6.7.3
|
css-loader: ^6.7.3
|
||||||
@ -5114,7 +5115,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"classnames@npm:^2.2.5":
|
"classnames@npm:^2.2.5, classnames@npm:^2.3.2":
|
||||||
version: 2.3.2
|
version: 2.3.2
|
||||||
resolution: "classnames@npm:2.3.2"
|
resolution: "classnames@npm:2.3.2"
|
||||||
checksum: 2c62199789618d95545c872787137262e741f9db13328e216b093eea91c85ef2bfb152c1f9e63027204e2559a006a92eb74147d46c800a9f96297ae1d9f96f4e
|
checksum: 2c62199789618d95545c872787137262e741f9db13328e216b093eea91c85ef2bfb152c1f9e63027204e2559a006a92eb74147d46c800a9f96297ae1d9f96f4e
|
||||||
|
Reference in New Issue
Block a user