diff --git a/biome.json b/biome.json index e1a8ab6..ee424a4 100644 --- a/biome.json +++ b/biome.json @@ -2,17 +2,55 @@ "$schema": "https://biomejs.dev/schemas/1.6.3/schema.json", "formatter": { "enabled": true, - "formatWithErrors": false, + "formatWithErrors": true, "indentStyle": "space", "indentWidth": 2, "lineEnding": "lf", "lineWidth": 80, - "attributePosition": "auto" + "attributePosition": "auto", + "ignore": [ + "**/node_modules/**", + "**/dist/**", + "**/build/**", + "**/coverage/**", + "**/.git/**", + "**/.vscode/**", + "**/.github/**", + "**/.yarn/**", + "**/.pnp/**", + "**/.cache/**", + "**/.next/**", + "**/.nuxt/**", + "**/out/**", + "**/public/**", + "**/static" + ] }, "organizeImports": { "enabled": true }, - "linter": { "enabled": true, "rules": { "recommended": true } }, + "linter": { + "enabled": true, + "rules": { "recommended": true }, + "ignore": [ + "**/node_modules/**", + "**/dist/**", + "**/build/**", + "**/coverage/**", + "**/.git/**", + "**/.vscode/**", + "**/.github/**", + "**/.yarn/**", + "**/.pnp/**", + "**/.cache/**", + "**/.next/**", + "**/.nuxt/**", + "**/out/**", + "**/public/**", + "**/static" + ] + }, "javascript": { "formatter": { + "enabled": true, "jsxQuoteStyle": "double", "quoteProperties": "asNeeded", "trailingComma": "es5", diff --git a/components/AliasedEmails.tsx b/components/AliasedEmails.tsx index 0b40b89..1f9a6df 100644 --- a/components/AliasedEmails.tsx +++ b/components/AliasedEmails.tsx @@ -1,4 +1,4 @@ -import { AliasType } from "@/components/types" +import type { AliasType } from "@/components/types" import { colorSelector } from "@/utils/colorSelector" import { faker } from "@faker-js/faker" import { @@ -26,9 +26,8 @@ import { IconX, } from "@tabler/icons-react" import aliasedEmail from "aliased-email" -import { useAtom } from "jotai" import { useCallback, useEffect, useState } from "react" -import { localCopyHistoryAtom } from "./global/CopyHistory" +import { CopyComponent } from "@/components/global/CopyComponent" type Props = { extension?: boolean } @@ -43,7 +42,6 @@ export default function InputCreator({ extension }: Props) { defaultValue: "", }) const [finalEmail, setFinalEmail] = useState("") - const [copiedEmail, setCopiedEmail] = useState("") const [timestampEnabled, setTimestampEnabled] = useLocalStorage({ key: "timestampEnabled", defaultValue: true, @@ -65,12 +63,12 @@ export default function InputCreator({ extension }: Props) { } const handleCreateAlias = (query: string) => { - query = query.trim().replaceAll(/\W/g, "") - if (aliases.find((a) => a.value === query)) return - if (query.length === 0) return + const trimmedQuery = query.trim().replaceAll(/\W/g, "") + if (aliases.find((a) => a.value === trimmedQuery)) return + if (trimmedQuery.length === 0) return setAliases([ ...aliases, - { label: query, value: query.trim().replaceAll(/\W/g, "") }, + { label: trimmedQuery, value: trimmedQuery.trim().replaceAll(/\W/g, "") }, ]) } const [editingAliases, setEditingAliases] = useState(false) @@ -84,24 +82,6 @@ export default function InputCreator({ extension }: Props) { } } - const [copyHistory, setCopyHistory] = useAtom(localCopyHistoryAtom) - const uniqueCopyHistory = new Set(copyHistory.map((item) => item.value)) - - const handleCopyEmail = () => { - setCopiedEmail(finalEmail) - - if (uniqueCopyHistory.has(finalEmail)) return - setCopyHistory((history) => [ - ...history, - { - id: history.length, - type: "email", - value: finalEmail, - timestamp: new Date().getTime(), - }, - ]) - } - const useRealtimeTimestamp = () => { const [realtimeTimestamp, setRealtimeTimestamp] = useState("") @@ -206,7 +186,7 @@ export default function InputCreator({ extension }: Props) { Random Alias - + {} - - )} - + + } + disabled={!validateEmail(email) || email.length === 0} + /> diff --git a/components/RegexReplacer.tsx b/components/RegexReplacer.tsx index 016284a..1e4a52f 100644 --- a/components/RegexReplacer.tsx +++ b/components/RegexReplacer.tsx @@ -1,50 +1,130 @@ -import { Box, Button, CopyButton, Input, Text } from "@mantine/core" +import { Box, Card, Grid, Input, Text, Tooltip } from "@mantine/core" import { useInputState } from "@mantine/hooks" import React, { useEffect, useState } from "react" import { regexReplacer } from "@/utils/regexReplacer" +import { stringToRegex } from "@/utils/transformStringToRegex" +import { CopyComponent } from "@/components/global/CopyComponent" +import { IconAlertCircle, IconRegex } from "@tabler/icons-react" -type Props = {} +type Props = { + extension?: boolean +} -const RegexReplacer = (props: Props) => { +const RegexReplacer = ({ extension }: Props) => { const [regexInput, setRegexInput] = useInputState("") const [replaceValue, setReplaceValue] = useInputState("") const [testText, setTestText] = useInputState("") const [preview, setPreview] = useInputState("") - - //convert the regexInput to regex + const [regex, setRegex] = useState(null) useEffect(() => { + setRegex(stringToRegex(regexInput)) setPreview(regexReplacer(regexInput, replaceValue, testText)) - }, [regexInput, replaceValue, testText]) + }, [regexInput, replaceValue, testText, setPreview]) return ( - - - - - - - - - - - - - {({ copied, copy }) => } - - + + + + Regex Replace Tester + + + + } + radius={"xl"} + autoComplete="off" + autoSave="off" + data-test="regex-input" + rightSection={ + + + + + + } + /> + + + + + + + + + + + + + + 0 && regex.toString() !== "/(?:)/" + ? false + : true + } + data-test="regex-copy" + /> + + + 0 ? false : true} + data-test="regex-preview" + /> + + + + + + ) } diff --git a/components/TextGeneration.tsx b/components/TextGeneration.tsx index 7738509..3c4b81d 100644 --- a/components/TextGeneration.tsx +++ b/components/TextGeneration.tsx @@ -15,6 +15,7 @@ import { PlaceText } from "../utils/transformer" import { useAtom } from "jotai" import { localCopyHistoryAtom } from "./global/CopyHistory" import { colorSelector } from "@/utils/colorSelector" +import { CopyComponent } from "@/components/global/CopyComponent" interface Props { extension?: boolean @@ -32,16 +33,18 @@ export default function CopyGroupCard({ defaultOptions }: Props) { (acc, option) => { const key = option.textElement const copyButton = ( - ) if (acc[key]) { @@ -101,60 +104,3 @@ export default function CopyGroupCard({ defaultOptions }: Props) { ) } - -export const CopyButtons = ({ - label, - textElement, - text: value, - ...rest -}: { - label: string - textElement: string - text: string -}) => { - const [copyHistory, setCopyHistory] = useAtom(localCopyHistoryAtom) - - return ( - - {({ copied, copy }) => ( - - - - )} - - ) -} diff --git a/components/global/ConfirmationPopup.tsx b/components/global/ConfirmationPopup.tsx index 866a0da..8eb6400 100644 --- a/components/global/ConfirmationPopup.tsx +++ b/components/global/ConfirmationPopup.tsx @@ -2,7 +2,7 @@ import { Badge, Button, Group, - MantineColor, + type MantineColor, Popover, Stack, Text, @@ -20,7 +20,7 @@ type Props = { onCancel?: () => void confirmColor?: MantineColor cancelColor?: MantineColor - [x: string]: any + [x: string]: string | boolean | (() => void) | undefined } export default function ConfirmationPopup({ title, @@ -38,9 +38,7 @@ export default function ConfirmationPopup({ const [opened, setOpened] = useState(false) const handleCancel = () => { - { - onCancel && onCancel() - } + onCancel?.() setOpened(false) } diff --git a/components/global/CopyComponent.tsx b/components/global/CopyComponent.tsx new file mode 100644 index 0000000..f2e0467 --- /dev/null +++ b/components/global/CopyComponent.tsx @@ -0,0 +1,73 @@ +import { localCopyHistoryAtom } from "@/components/global/CopyHistory" +import type { CopyHistoryType } from "@/components/types" +import { Box, Button, CopyButton, Tooltip } from "@mantine/core" +import { useAtom } from "jotai" +import { colorSelector } from "../../utils/colorSelector" +import { useState } from "react" + +type Props = { + value?: string + type: string + label?: string + fullWidth?: boolean + size?: "xs" | "sm" | "md" | "lg" | "xl" + id?: string + h?: number | string + maw?: number | string + rightIcon?: React.ReactNode + disabled?: boolean +} + +export const CopyComponent = ({ value, type, label, ...rest }: Props) => { + const [copyHistory, setCopyHistory] = useAtom(localCopyHistoryAtom) + + const [displayedCopiedValue, setDisplayedCopiedValue] = useState("") + + const handleCopy = (value: string, type: string) => { + setDisplayedCopiedValue(value) + + if (copyHistory[copyHistory.length - 1]?.value === value) { + return + } + setCopyHistory((history) => [ + ...history, + { + id: history.length, + type: type, + value, + timestamp: new Date().getTime(), + }, + ]) + } + return ( + + + {({ copied, copy }) => ( + + + + )} + + + ) +} diff --git a/components/global/CopyHistory.tsx b/components/global/CopyHistory.tsx index ba7c9e4..e14c480 100644 --- a/components/global/CopyHistory.tsx +++ b/components/global/CopyHistory.tsx @@ -7,7 +7,7 @@ import { Button, CopyButton, Flex, - MantineNumberSize, + type MantineNumberSize, SimpleGrid, Text, Tooltip, @@ -15,10 +15,10 @@ import { import { IconCopy } from "@tabler/icons-react" import { colorSelector } from "@/utils/colorSelector" import { useRouter } from "next/router" -import { CopyHistoryType } from "@/components/types" +import type { CopyHistoryType } from "@/components/types" type Props = { - type?: "email" | "text" + type?: "email" | "text" | "regex" | "string" spacing?: MantineNumberSize tooltip?: boolean scrollThreshold: number @@ -30,24 +30,18 @@ export const localCopyHistoryAtom = atomWithStorage( ) export default function CopyHistory({ type, tooltip, scrollThreshold }: Props) { - let copyHistory = useAtomValue(localCopyHistoryAtom) + const copyHistory = useAtomValue(localCopyHistoryAtom) const router = useRouter() const extension = router.pathname.includes("/extension") - type == "email" && - (copyHistory = copyHistory.filter((item) => item.type === type)) - - type == "text" && - (copyHistory = copyHistory.filter((item) => item.type === type)) - const ScrollingText = ({ children, scrollThreshold, scrolling, ...rest }: { - children: String + children: string scrollThreshold: number scrolling: boolean }) => { @@ -59,17 +53,15 @@ export default function CopyHistory({ type, tooltip, scrollThreshold }: Props) { const speed = scrollThreshold * 0.02 if (speed > 0.8) { return 0.8 - } else { - return speed } + return speed } const scrollAmount = (scrollThreshold: number) => { if (children.length <= scrollThreshold) { return 0 - } else { - return (scrollThreshold - children.length) * scalingFactor + "ch" } + return `${(scrollThreshold - children.length) * scalingFactor}ch` } return ( @@ -91,7 +83,7 @@ export default function CopyHistory({ type, tooltip, scrollThreshold }: Props) { } : { transform: `translateX(${scrollAmount(scrollThreshold)})`, - transition: `transform 0.1s ease-out`, + transition: "transform 0.1s ease-out", } } > @@ -108,10 +100,10 @@ export default function CopyHistory({ type, tooltip, scrollThreshold }: Props) { historyItem: CopyHistoryType }) => { return ( - + {({ copied, copy }) => (