diff --git a/frontend/src/components/ScratchItem.module.scss b/frontend/src/components/ScratchItem.module.scss index dd7f89cd0..1a35d62c9 100644 --- a/frontend/src/components/ScratchItem.module.scss +++ b/frontend/src/components/ScratchItem.module.scss @@ -147,3 +147,15 @@ text-overflow: ellipsis; } } + +.red-on-shift { + --warning-color: #ce3a3a; + color: var(--warning-color) !important; + border-color: var(--warning-color) !important; +} + +.red-on-shift:hover { + --warning-hover-color: #f58d8d; + color: var(--warning-hover-color) !important; + border-color: var(--warning-hover-color) !important; +} \ No newline at end of file diff --git a/frontend/src/components/ScratchItem.tsx b/frontend/src/components/ScratchItem.tsx index bf771139f..29026d344 100644 --- a/frontend/src/components/ScratchItem.tsx +++ b/frontend/src/components/ScratchItem.tsx @@ -1,11 +1,11 @@ "use client"; -import type { ReactNode } from "react"; +import { type ReactNode, useState } from "react"; import Image from "next/image"; import Link from "@/components/Link"; -import { RepoForkedIcon } from "@primer/octicons-react"; +import { RepoForkedIcon, TrashIcon } from "@primer/octicons-react"; import clsx from "clsx"; import TimeAgo from "@/components/TimeAgo"; @@ -15,6 +15,7 @@ import { presetUrl, scratchUrl, userAvatarUrl } from "@/lib/api/urls"; import getTranslation from "@/lib/i18n/translate"; import AnonymousFrogAvatar from "./Frog/AnonymousFrog"; +import Button from "./Button"; import PlatformLink from "./PlatformLink"; import { calculateScorePercent, percentToString } from "./ScoreBadge"; import styles from "./ScratchItem.module.scss"; @@ -144,53 +145,120 @@ function ScratchItemRow({ showOwner = true, showPlatform = true, showPresetOrCompiler = true, + showDeleteButton = false, }: { scratch: api.TerseScratch; children?: ReactNode; showOwner?: boolean; showPlatform?: boolean; showPresetOrCompiler?: boolean; + showDeleteButton?: boolean; }) { + const [warnDelete, setWarnDelete] = useState(false); + const [showElement, setShowElement] = useState(true); + const deleteScratch = async (scratch: api.TerseScratch) => { + if ( + !warnDelete && + !confirm( + "Are you sure you want to delete this scratch? This action cannot be undone.", + ) + ) { + return; + } + + try { + await api.delete_(scratchUrl(scratch), {}); + setShowElement(false); // Hide deleted element to avoid performing a page refresh, and allow deleting more scratches + } catch (error) { + alert("An error occurred trying to deleting this scratch."); + throw error; + } + }; + + document.body.addEventListener("keydown", (evt: KeyboardEvent) => { + setWarnDelete(evt.shiftKey); + }); + + document.body.addEventListener("keyup", (evt: KeyboardEvent) => { + setWarnDelete(evt.shiftKey); + }); + return ( -