forked from Kieran/zap.stream
feat: stream cards improvements
- edit toggle - reorder with drag and drop - delete button inside edit modal - add ability to clear image from card - make card textarea taller and avoid horizontal resize
This commit is contained in:
parent
3e2336129c
commit
4e4ea9efa6
@ -10,6 +10,7 @@
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
"@radix-ui/react-progress": "^1.0.3",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-toggle": "^1.0.3",
|
||||
"@react-hook/resize-observer": "^1.2.6",
|
||||
"@scure/base": "^1.1.1",
|
||||
"@snort/shared": "^1.0.4",
|
||||
@ -31,6 +32,8 @@
|
||||
"qr-code-styling": "^1.6.0-rc.1",
|
||||
"react": "^18.2.0",
|
||||
"react-confetti": "^6.1.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-intersection-observer": "^9.5.1",
|
||||
|
@ -29,5 +29,5 @@ export function Event({ link }: EventProps) {
|
||||
);
|
||||
}
|
||||
|
||||
return <code>{link.id}</code>;
|
||||
return null;
|
||||
}
|
||||
|
@ -25,3 +25,13 @@
|
||||
height: 60px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.file-uploader-preview {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.file-uploader-preview .clear-button {
|
||||
color: var(--text-danger);
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ async function voidCatUpload(file: File | Blob): Promise<UploadResult> {
|
||||
}
|
||||
}
|
||||
|
||||
export function FileUploader({ onFileUpload }) {
|
||||
const [img, setImg] = useState();
|
||||
export function FileUploader({ defaultImage, onClear, onFileUpload }) {
|
||||
const [img, setImg] = useState(defaultImage);
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
|
||||
async function onFileChange(ev) {
|
||||
@ -63,13 +63,25 @@ export function FileUploader({ onFileUpload }) {
|
||||
}
|
||||
}
|
||||
|
||||
function clearImage() {
|
||||
setImg("");
|
||||
onClear();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="file-uploader-container">
|
||||
<label className="file-uploader">
|
||||
<input type="file" onChange={onFileChange} />
|
||||
{isUploading ? "Uploading..." : "Add File"}
|
||||
</label>
|
||||
{img && <img className="image-preview" src={img} />}
|
||||
<div className="file-uploader-preview">
|
||||
{img?.length > 0 && (
|
||||
<button className="btn btn-primary clear-button" onClick={clearImage}>
|
||||
Clear
|
||||
</button>
|
||||
)}
|
||||
{img && <img className="image-preview" src={img} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -32,7 +32,13 @@
|
||||
gap: 16px;
|
||||
border-radius: 24px;
|
||||
background: #111;
|
||||
width: 210px;
|
||||
min-width: 210px;
|
||||
max-width: 310px;
|
||||
}
|
||||
|
||||
.stream-card.image-card {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.stream-card .card-title {
|
||||
@ -90,6 +96,8 @@
|
||||
padding: 8px 16px;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 8px;
|
||||
resize: vertical;
|
||||
min-height: 210px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
@ -126,3 +134,15 @@
|
||||
background: transparent;
|
||||
color: var(--text-danger);
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0% { transform: rotate(0deg); }
|
||||
25% { transform: rotate(5deg); }
|
||||
50% { transform: rotate(0eg); }
|
||||
75% { transform: rotate(-5deg); }
|
||||
100% { transform: rotate(0deg); }
|
||||
}
|
||||
|
||||
.stream-card .card-image {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
import "./stream-cards.css";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useState, forwardRef } from "react";
|
||||
import * as Dialog from "@radix-ui/react-dialog";
|
||||
import { DndProvider, useDrag, useDrop } from "react-dnd";
|
||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||
|
||||
import type { NostrEvent } from "@snort/system";
|
||||
|
||||
import { Toggle } from "element/toggle";
|
||||
import { useLogin } from "hooks/login";
|
||||
import { useCards } from "hooks/cards";
|
||||
import { CARD, USER_CARDS } from "const";
|
||||
@ -30,50 +33,150 @@ interface CardProps {
|
||||
cards: NostrEvent[];
|
||||
}
|
||||
|
||||
function isEmpty(s?: string) {
|
||||
return !s || s.trim().length === 0;
|
||||
}
|
||||
|
||||
const CardPreview = forwardRef(
|
||||
({ style, title, link, image, content }, ref) => {
|
||||
const isImageOnly = !isEmpty(image) && isEmpty(content) && isEmpty(title);
|
||||
return (
|
||||
<div
|
||||
className={`stream-card ${isImageOnly ? "image-card" : ""}`}
|
||||
ref={ref}
|
||||
style={style}
|
||||
>
|
||||
{title && <h1 className="card-title">{title}</h1>}
|
||||
{image &&
|
||||
(link?.length > 0 ? (
|
||||
<ExternalLink href={link}>
|
||||
<img className="card-image" src={image} alt={title} />
|
||||
</ExternalLink>
|
||||
) : (
|
||||
<img className="card-image" src={image} alt={title} />
|
||||
))}
|
||||
<Markdown children={content} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
function Card({ canEdit, ev, cards }: CardProps) {
|
||||
const login = useLogin();
|
||||
const identifier = findTag(ev, "d");
|
||||
const title = findTag(ev, "title") || findTag(ev, "subject");
|
||||
const image = findTag(ev, "image");
|
||||
const link = findTag(ev, "r");
|
||||
const evCard = { title, image, link, content: ev.content, identifier };
|
||||
const content = ev.content;
|
||||
const evCard = { title, image, link, content, identifier };
|
||||
const tags = cards.map(toTag);
|
||||
const [style, dragRef] = useDrag(
|
||||
() => ({
|
||||
type: "card",
|
||||
item: { identifier },
|
||||
canDrag: () => {
|
||||
return canEdit;
|
||||
},
|
||||
collect: (monitor) => {
|
||||
const isDragging = monitor.isDragging();
|
||||
return {
|
||||
opacity: isDragging ? 0.1 : 1,
|
||||
cursor: !canEdit ? "auto" : isDragging ? "grabbing" : "grab",
|
||||
};
|
||||
},
|
||||
}),
|
||||
[canEdit, identifier],
|
||||
);
|
||||
|
||||
function findTagByIdentifier(d) {
|
||||
return tags.find((t) => t.at(1).endsWith(`:${d}`));
|
||||
}
|
||||
|
||||
const [dropStyle, dropRef] = useDrop(
|
||||
() => ({
|
||||
accept: ["card"],
|
||||
canDrop: () => {
|
||||
return canEdit;
|
||||
},
|
||||
collect: (monitor) => {
|
||||
const isOvering = monitor.isOver({ shallow: true });
|
||||
return {
|
||||
opacity: isOvering ? 0.3 : 1,
|
||||
animation: isOvering ? "shake 0.1s 3" : "",
|
||||
};
|
||||
},
|
||||
async drop(item) {
|
||||
if (identifier === item.identifier) {
|
||||
return;
|
||||
}
|
||||
const newItem = findTagByIdentifier(item.identifier);
|
||||
const oldItem = findTagByIdentifier(identifier);
|
||||
const newTags = tags.map((t) => {
|
||||
if (t === oldItem) {
|
||||
return newItem;
|
||||
}
|
||||
if (t === newItem) {
|
||||
return oldItem;
|
||||
}
|
||||
return t;
|
||||
});
|
||||
const pub = login?.publisher();
|
||||
const userCardsEv = await pub.generic((eb) => {
|
||||
eb.kind(USER_CARDS).content("");
|
||||
for (const tag of newTags) {
|
||||
eb.tag(tag);
|
||||
}
|
||||
return eb;
|
||||
});
|
||||
console.debug(userCardsEv);
|
||||
System.BroadcastEvent(userCardsEv);
|
||||
},
|
||||
}),
|
||||
[canEdit, tags, identifier],
|
||||
);
|
||||
|
||||
const card = (
|
||||
<>
|
||||
<div className="stream-card">
|
||||
{title && <h1 className="card-title">{title}</h1>}
|
||||
{image && <img src={image} alt={title} />}
|
||||
<Markdown children={ev.content} />
|
||||
</div>
|
||||
</>
|
||||
<CardPreview
|
||||
ref={dropRef}
|
||||
title={title}
|
||||
link={link}
|
||||
image={image}
|
||||
content={content}
|
||||
style={dropStyle}
|
||||
/>
|
||||
);
|
||||
const editor = canEdit && (
|
||||
<div className="editor-buttons">
|
||||
<EditCard card={evCard} />
|
||||
<DeleteCard card={ev} cards={cards} />
|
||||
<EditCard card={evCard} cards={cards} />
|
||||
</div>
|
||||
);
|
||||
return link && !canEdit ? (
|
||||
<div className="card-container">
|
||||
<ExternalLink href={link}>{card}</ExternalLink>
|
||||
{editor}
|
||||
</div>
|
||||
) : (
|
||||
<div className="card-container">
|
||||
return canEdit ? (
|
||||
<div className="card-container" ref={dragRef} style={style}>
|
||||
{card}
|
||||
{editor}
|
||||
</div>
|
||||
) : (
|
||||
<div className="card-container">{card}</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface CardDialogProps {
|
||||
header?: string;
|
||||
cta?: string;
|
||||
cancelCta?: string;
|
||||
card?: CardType;
|
||||
onSave(ev: CardType): void;
|
||||
onCancel(): void;
|
||||
}
|
||||
|
||||
function CardDialog({ header, cta, card, onSave, onCancel }: CardDialogProps) {
|
||||
function CardDialog({
|
||||
header,
|
||||
cta,
|
||||
cancelCta,
|
||||
card,
|
||||
onSave,
|
||||
onCancel,
|
||||
}: CardDialogProps) {
|
||||
const [title, setTitle] = useState(card?.title ?? "");
|
||||
const [image, setImage] = useState(card?.image ?? "");
|
||||
const [content, setContent] = useState(card?.content ?? "");
|
||||
@ -94,10 +197,14 @@ function CardDialog({ header, cta, card, onSave, onCancel }: CardDialogProps) {
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<label for="card-image">Image</label>
|
||||
<FileUploader onFileUpload={setImage} />
|
||||
<FileUploader
|
||||
defaultImage={image}
|
||||
onFileUpload={setImage}
|
||||
onClear={() => setImage("")}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<label for="card-image-link">Link</label>
|
||||
<label for="card-image-link">Image Link</label>
|
||||
<input
|
||||
id="card-image-link"
|
||||
type="text"
|
||||
@ -128,7 +235,7 @@ function CardDialog({ header, cta, card, onSave, onCancel }: CardDialogProps) {
|
||||
{cta || "Add Card"}
|
||||
</button>
|
||||
<button className="btn delete-button" onClick={onCancel}>
|
||||
Cancel
|
||||
{cancelCta || "Cancel"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -137,11 +244,14 @@ function CardDialog({ header, cta, card, onSave, onCancel }: CardDialogProps) {
|
||||
|
||||
interface EditCardProps {
|
||||
card: CardType;
|
||||
cards: NostrEvent[];
|
||||
}
|
||||
|
||||
function EditCard({ card }: EditCardProps) {
|
||||
function EditCard({ card, cards }: EditCardProps) {
|
||||
const login = useLogin();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const identifier = card.identifier;
|
||||
const tags = cards.map(toTag);
|
||||
|
||||
async function editCard({ title, image, link, content }) {
|
||||
const pub = login?.publisher();
|
||||
@ -165,8 +275,23 @@ function EditCard({ card }: EditCardProps) {
|
||||
}
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
setIsOpen(false);
|
||||
async function onCancel() {
|
||||
const pub = login?.publisher();
|
||||
if (pub) {
|
||||
const userCardsEv = await pub.generic((eb) => {
|
||||
eb.kind(USER_CARDS).content("");
|
||||
for (const tag of tags) {
|
||||
if (!tag.at(1).endsWith(`:${identifier}`)) {
|
||||
eb.tag(tag);
|
||||
}
|
||||
}
|
||||
return eb;
|
||||
});
|
||||
|
||||
console.debug(userCardsEv);
|
||||
System.BroadcastEvent(userCardsEv);
|
||||
setIsOpen(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@ -180,6 +305,7 @@ function EditCard({ card }: EditCardProps) {
|
||||
<CardDialog
|
||||
header="Edit card"
|
||||
cta="Save Card"
|
||||
cancelCta="Delete"
|
||||
card={card}
|
||||
onSave={editCard}
|
||||
onCancel={onCancel}
|
||||
@ -190,41 +316,6 @@ function EditCard({ card }: EditCardProps) {
|
||||
);
|
||||
}
|
||||
|
||||
interface DeleteCardProps {
|
||||
card: NostrEvent;
|
||||
cards: NostrEvent[];
|
||||
}
|
||||
|
||||
function DeleteCard({ card, cards }: DeleteCardProps) {
|
||||
const login = useLogin();
|
||||
const tags = cards.map(toTag);
|
||||
|
||||
async function deleteCard() {
|
||||
const pub = login?.publisher();
|
||||
if (pub) {
|
||||
const userCardsEv = await pub.generic((eb) => {
|
||||
eb.kind(USER_CARDS).content("");
|
||||
for (const tag of tags) {
|
||||
if (tag.at(1) !== toTag(card).at(1)) {
|
||||
eb.tag(tag);
|
||||
}
|
||||
}
|
||||
return eb;
|
||||
});
|
||||
|
||||
console.log(userCardsEv);
|
||||
|
||||
System.BroadcastEvent(userCardsEv);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<button className="btn delete-button" onClick={deleteCard}>
|
||||
Delete
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
interface AddCardProps {
|
||||
cards: NostrEvent[];
|
||||
}
|
||||
@ -294,12 +385,26 @@ export function StreamCards({ host }) {
|
||||
const login = useLogin();
|
||||
const canEdit = login?.pubkey === host;
|
||||
const cards = useCards(host, canEdit);
|
||||
return (
|
||||
<div className="stream-cards">
|
||||
{cards.map((ev) => (
|
||||
<Card canEdit={canEdit} cards={cards} key={ev.id} ev={ev} />
|
||||
))}
|
||||
{canEdit && <AddCard cards={cards} />}
|
||||
</div>
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const components = (
|
||||
<>
|
||||
<div className="stream-cards">
|
||||
{cards.map((ev) => (
|
||||
<Card canEdit={isEditing} cards={cards} key={ev.id} ev={ev} />
|
||||
))}
|
||||
{isEditing && <AddCard cards={cards} />}
|
||||
</div>
|
||||
{canEdit && (
|
||||
<div className="edit-container">
|
||||
<Toggle
|
||||
pressed={isEditing}
|
||||
onPressedChange={setIsEditing}
|
||||
label="Toggle edit mode"
|
||||
text="Edit cards"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
return <DndProvider backend={HTML5Backend}>{components}</DndProvider>;
|
||||
}
|
||||
|
27
src/element/toggle.css
Normal file
27
src/element/toggle.css
Normal file
@ -0,0 +1,27 @@
|
||||
.toggle-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
.toggle svg {
|
||||
color: var(--text-muted);
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
.toggle:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.toggle:hover svg {
|
||||
color: white;
|
||||
}
|
||||
.toggle[data-state='on'] svg {
|
||||
color: var(--text-link);
|
||||
}
|
44
src/element/toggle.tsx
Normal file
44
src/element/toggle.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import * as BaseToggle from "@radix-ui/react-toggle";
|
||||
import "./toggle.css";
|
||||
|
||||
interface ToggleProps {
|
||||
label: string;
|
||||
}
|
||||
|
||||
function ToggleLeft(props) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M8 5C4.13401 5 1 8.13401 1 12C1 15.866 4.13401 19 8 19H16C19.866 19 23 15.866 23 12C23 8.13401 19.866 5 16 5H8ZM12 12C12 14.2091 10.2091 16 8 16C5.79086 16 4 14.2091 4 12C4 9.79086 5.79086 8 8 8C10.2091 8 12 9.79086 12 12Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function ToggleRight(props) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M16 5C19.866 5 23 8.13401 23 12C23 15.866 19.866 19 16 19H8C4.13401 19 1 15.866 1 12C1 8.13401 4.13401 5 8 5H16ZM12 12C12 14.2091 13.7909 16 16 16C18.2091 16 20 14.2091 20 12C20 9.79086 18.2091 8 16 8C13.7909 8 12 9.79086 12 12Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function Toggle({ label, text, ...rest }: ToggleProps) {
|
||||
const { pressed } = rest;
|
||||
return (
|
||||
<div className="toggle-container">
|
||||
<BaseToggle.Root className="toggle" aria-label={label} {...rest}>
|
||||
{pressed ? <ToggleRight /> : <ToggleLeft />}
|
||||
</BaseToggle.Root>
|
||||
<span className="toggle-text">{text}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -163,3 +163,7 @@ button span.hide-on-mobile {
|
||||
.age-check .btn {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.profile-menu {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ export function LayoutPage() {
|
||||
<Menu
|
||||
menuClassName="ctx-menu"
|
||||
menuButton={
|
||||
<div>
|
||||
<div className="profile-menu">
|
||||
<Profile
|
||||
avatarClassname="mb-squared"
|
||||
pubkey={login.pubkey}
|
||||
@ -82,7 +82,11 @@ export function LayoutPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`page${location.pathname.startsWith("/naddr1") ? " stream" : ""}`}>
|
||||
<div
|
||||
className={`page${
|
||||
location.pathname.startsWith("/naddr1") ? " stream" : ""
|
||||
}`}
|
||||
>
|
||||
<Helmet>
|
||||
<title>Home - zap.stream</title>
|
||||
</Helmet>
|
||||
@ -92,9 +96,7 @@ export function LayoutPage() {
|
||||
<input className="search-input" type="text" placeholder="Search" />
|
||||
<Icon name="search" size={15} />
|
||||
</div>
|
||||
<div className="f-grow">
|
||||
{/* Future menu items go here */}
|
||||
</div>
|
||||
<div className="f-grow">{/* Future menu items go here */}</div>
|
||||
<div className="header-right">
|
||||
{loggedIn()}
|
||||
{loggedOut()}
|
||||
|
@ -43,6 +43,11 @@
|
||||
left: 120px;
|
||||
}
|
||||
|
||||
.profile-page .status-indicator .offline {
|
||||
margin-top: 8px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.profile-page .profile-actions {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
|
111
yarn.lock
111
yarn.lock
@ -2311,6 +2311,28 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-toggle@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "@radix-ui/react-toggle@npm:1.0.3"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.13.10
|
||||
"@radix-ui/primitive": 1.0.1
|
||||
"@radix-ui/react-primitive": 1.0.3
|
||||
"@radix-ui/react-use-controllable-state": 1.0.1
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
"@types/react-dom": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: ed5407f48254f20cda542017774f259d0b2c0007ea4bd7287d10d751016dbf269cb13d1142591432c269c3ab768cde2f1ba0344743027d36bbec10af909f19de
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-callback-ref@npm:1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@radix-ui/react-use-callback-ref@npm:1.0.1"
|
||||
@ -2373,6 +2395,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-dnd/asap@npm:^5.0.1":
|
||||
version: 5.0.2
|
||||
resolution: "@react-dnd/asap@npm:5.0.2"
|
||||
checksum: 18f040e53512983f11c542ef21e6e4cac605d585a10cd764b13bc1b2f3ac7490e0fa40503adc348d8387aa45bc8e7eebe9cb33003b960a30bb5fde666ff2adde
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-dnd/invariant@npm:^4.0.1":
|
||||
version: 4.0.2
|
||||
resolution: "@react-dnd/invariant@npm:4.0.2"
|
||||
checksum: 594f6d78896c19bb8f023e101334fd91a9fdff686117bd8e830ba53737ec0a6042dab66971d3d63c7afbc622103909aff7a64c5c6767e0aa8d9561fd42705016
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-dnd/shallowequal@npm:^4.0.1":
|
||||
version: 4.0.2
|
||||
resolution: "@react-dnd/shallowequal@npm:4.0.2"
|
||||
checksum: 7f21d691bddbfd4d2830948cbeefecca1600b2b46bcb1934926795f07ae8a1fa60a3dfd3a2112be5ef682c3820c80a99711e9fa15843f7e300acb25a4ecb70ab
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-hook/latest@npm:^1.0.2":
|
||||
version: 1.0.3
|
||||
resolution: "@react-hook/latest@npm:1.0.3"
|
||||
@ -4897,6 +4940,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dnd-core@npm:^16.0.1":
|
||||
version: 16.0.1
|
||||
resolution: "dnd-core@npm:16.0.1"
|
||||
dependencies:
|
||||
"@react-dnd/asap": ^5.0.1
|
||||
"@react-dnd/invariant": ^4.0.1
|
||||
redux: ^4.2.0
|
||||
checksum: b7d3ef4664f433af796f440ddd27ad9d7fef0205f26c4b7c0af6ebf612ffa9b33e64d095d3e79190c4baaed34aa36570f321ebe0d2cc8ff1031ff158a0907b3f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dns-equal@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "dns-equal@npm:1.0.0"
|
||||
@ -6133,6 +6187,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hoist-non-react-statics@npm:^3.3.2":
|
||||
version: 3.3.2
|
||||
resolution: "hoist-non-react-statics@npm:3.3.2"
|
||||
dependencies:
|
||||
react-is: ^16.7.0
|
||||
checksum: b1538270429b13901ee586aa44f4cc3ecd8831c061d06cb8322e50ea17b3f5ce4d0e2e66394761e6c8e152cd8c34fb3b4b690116c6ce2bd45b18c746516cb9e8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hpack.js@npm:^2.1.6":
|
||||
version: 2.1.6
|
||||
resolution: "hpack.js@npm:2.1.6"
|
||||
@ -8846,6 +8909,40 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dnd-html5-backend@npm:^16.0.1":
|
||||
version: 16.0.1
|
||||
resolution: "react-dnd-html5-backend@npm:16.0.1"
|
||||
dependencies:
|
||||
dnd-core: ^16.0.1
|
||||
checksum: e2368bf85d5632a5cd867b743feb54c9052d909ea5331608860fa455edf3c633ac791f5b338e3db29b19ea8670c0ba5fb43c9c1c2510760bea030811d726cdfa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dnd@npm:^16.0.1":
|
||||
version: 16.0.1
|
||||
resolution: "react-dnd@npm:16.0.1"
|
||||
dependencies:
|
||||
"@react-dnd/invariant": ^4.0.1
|
||||
"@react-dnd/shallowequal": ^4.0.1
|
||||
dnd-core: ^16.0.1
|
||||
fast-deep-equal: ^3.1.3
|
||||
hoist-non-react-statics: ^3.3.2
|
||||
peerDependencies:
|
||||
"@types/hoist-non-react-statics": ">= 3.3.1"
|
||||
"@types/node": ">= 12"
|
||||
"@types/react": ">= 16"
|
||||
react: ">= 16.14"
|
||||
peerDependenciesMeta:
|
||||
"@types/hoist-non-react-statics":
|
||||
optional: true
|
||||
"@types/node":
|
||||
optional: true
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: e8da2186aaafcd5bb41c090a995c963a7c3c73c20991667a2cfc0c800d7f7f73913414b2e61c437cdb6221bb2151bd5174088b8b42c17056a896fc4d1da5729f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dom@npm:^18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react-dom@npm:18.2.0"
|
||||
@ -8888,7 +8985,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-is@npm:^16.13.1":
|
||||
"react-is@npm:^16.13.1, react-is@npm:^16.7.0":
|
||||
version: 16.13.1
|
||||
resolution: "react-is@npm:16.13.1"
|
||||
checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f
|
||||
@ -9103,6 +9200,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"redux@npm:^4.2.0":
|
||||
version: 4.2.1
|
||||
resolution: "redux@npm:4.2.1"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.9.2
|
||||
checksum: f63b9060c3a1d930ae775252bb6e579b42415aee7a23c4114e21a0b4ba7ec12f0ec76936c00f546893f06e139819f0e2855e0d55ebfce34ca9c026241a6950dd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"regenerate-unicode-properties@npm:^10.1.0":
|
||||
version: 10.1.0
|
||||
resolution: "regenerate-unicode-properties@npm:10.1.0"
|
||||
@ -9881,6 +9987,7 @@ __metadata:
|
||||
"@radix-ui/react-dialog": ^1.0.4
|
||||
"@radix-ui/react-progress": ^1.0.3
|
||||
"@radix-ui/react-tabs": ^1.0.4
|
||||
"@radix-ui/react-toggle": ^1.0.3
|
||||
"@react-hook/resize-observer": ^1.2.6
|
||||
"@scure/base": ^1.1.1
|
||||
"@snort/shared": ^1.0.4
|
||||
@ -9923,6 +10030,8 @@ __metadata:
|
||||
qr-code-styling: ^1.6.0-rc.1
|
||||
react: ^18.2.0
|
||||
react-confetti: ^6.1.0
|
||||
react-dnd: ^16.0.1
|
||||
react-dnd-html5-backend: ^16.0.1
|
||||
react-dom: ^18.2.0
|
||||
react-helmet: ^6.1.0
|
||||
react-intersection-observer: ^9.5.1
|
||||
|
Loading…
Reference in New Issue
Block a user