diff --git a/next.config.js b/next.config.js index 121c4f4..18d1af8 100644 --- a/next.config.js +++ b/next.config.js @@ -5,6 +5,10 @@ import "./src/env.js"; /** @type {import("next").NextConfig} */ -const config = {}; +const config = { + experimental: { + reactCompiler: true, + }, +}; export default config; diff --git a/package.json b/package.json index 794f04a..0ce7678 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@trpc/client": "^11.0.0-rc.446", "@trpc/react-query": "^11.0.0-rc.446", "@trpc/server": "^11.0.0-rc.446", + "babel-plugin-react-compiler": "19.0.0-beta-40c6c23-20250301", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "drizzle-orm": "^0.33.0", @@ -55,6 +56,7 @@ "next-themes": "^0.4.4", "postgres": "^3.4.4", "react": "^18.3.1", + "react-colorful": "^5.6.1", "react-dom": "^18.3.1", "react-hook-form": "^7.54.2", "react-textarea-autosize": "^8.5.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf1f4d9..10fea64 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,6 +83,9 @@ importers: '@trpc/server': specifier: ^11.0.0-rc.446 version: 11.0.0-rc.824(typescript@5.8.2) + babel-plugin-react-compiler: + specifier: 19.0.0-beta-40c6c23-20250301 + version: 19.0.0-beta-40c6c23-20250301 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -94,16 +97,16 @@ importers: version: 0.33.0(@types/react@18.3.18)(postgres@3.4.5)(react@18.3.1) geist: specifier: ^1.3.0 - version: 1.3.1(next@15.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + version: 1.3.1(next@15.2.1(babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) lucide-react: specifier: ^0.477.0 version: 0.477.0(react@18.3.1) next: specifier: ^15.0.1 - version: 15.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 15.2.1(babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-auth: specifier: 5.0.0-beta.25 - version: 5.0.0-beta.25(next@15.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 5.0.0-beta.25(next@15.2.1(babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.4.4 version: 0.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -113,6 +116,9 @@ importers: react: specifier: ^18.3.1 version: 18.3.1 + react-colorful: + specifier: ^5.6.1 + version: 5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) @@ -233,10 +239,22 @@ packages: '@auth/drizzle-adapter@1.8.0': resolution: {integrity: sha512-cxApE0h5WcyDsgGix9hzmWmCz0qxvmMJexAOQmI6R/YXYxrZ/mKBKu0BlfgQBR6z2XvNWl4wbEGchwSenSCksQ==} + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + '@babel/runtime@7.26.9': resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} engines: {node: '>=6.9.0'} + '@babel/types@7.26.9': + resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} + engines: {node: '>=6.9.0'} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -1719,6 +1737,9 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301: + resolution: {integrity: sha512-himtjPafvMbA7PYnV2L+jprpB3h4rhx/n5s4L3gC654FOUsmsv5n4p8d6ufvK2zqUQs4kTOjgT2b4wnuDU32CA==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2990,6 +3011,12 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + react-colorful@5.6.1: + resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -3525,10 +3552,19 @@ snapshots: - '@simplewebauthn/server' - nodemailer + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + '@babel/runtime@7.26.9': dependencies: regenerator-runtime: 0.14.1 + '@babel/types@7.26.9': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -4782,6 +4818,10 @@ snapshots: axobject-query@4.1.0: {} + babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301: + dependencies: + '@babel/types': 7.26.9 + balanced-match@1.0.2: {} binary-extensions@2.3.0: {} @@ -5186,8 +5226,8 @@ snapshots: '@typescript-eslint/parser': 8.26.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0)(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -5206,7 +5246,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -5217,18 +5257,18 @@ snapshots: stable-hash: 0.0.4 tinyglobby: 0.2.12 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.26.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -5236,7 +5276,7 @@ snapshots: dependencies: eslint: 8.57.1 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -5247,7 +5287,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -5458,9 +5498,9 @@ snapshots: functions-have-names@1.2.3: {} - geist@1.3.1(next@15.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): + geist@1.3.1(next@15.2.1(babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): dependencies: - next: 15.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.2.1(babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) get-intrinsic@1.3.0: dependencies: @@ -5832,10 +5872,10 @@ snapshots: natural-compare@1.4.0: {} - next-auth@5.0.0-beta.25(next@15.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + next-auth@5.0.0-beta.25(next@15.2.1(babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): dependencies: '@auth/core': 0.37.2 - next: 15.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.2.1(babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 next-themes@0.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -5843,7 +5883,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next@15.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@15.2.1(babel-plugin-react-compiler@19.0.0-beta-40c6c23-20250301)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 15.2.1 '@swc/counter': 0.1.3 @@ -5863,6 +5903,7 @@ snapshots: '@next/swc-linux-x64-musl': 15.2.1 '@next/swc-win32-arm64-msvc': 15.2.1 '@next/swc-win32-x64-msvc': 15.2.1 + babel-plugin-react-compiler: 19.0.0-beta-40c6c23-20250301 sharp: 0.33.5 transitivePeerDependencies: - '@babel/core' @@ -6159,6 +6200,11 @@ snapshots: queue-microtask@1.2.3: {} + react-colorful@5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 diff --git a/src/components/article/editor/article-form.tsx b/src/components/article/editor/article-form.tsx index 4779085..95ef32d 100644 --- a/src/components/article/editor/article-form.tsx +++ b/src/components/article/editor/article-form.tsx @@ -1,6 +1,5 @@ "use client"; -import "./styles.css"; import { Article } from "@/server/db/schema"; import React from "react"; @@ -18,37 +17,44 @@ import { FormMessage, } from "@/components/ui/form"; import { articleSchema } from "@/lib/validation/zod/article"; -import { debounce } from "@/lib/utils"; +import { cn, debounce } from "@/lib/utils"; import { updateArticle } from "@/server/actions/article"; import Editor from "./editor"; +import { Badge } from "@/components/ui/badge"; export default ({ server_article }: { server_article: Article }) => { - const form = useForm>({ - resolver: zodResolver(articleSchema), - defaultValues: { - title: server_article?.title ?? "", - content: - server_article?.content ?? - `

+ const defaultValues = { + title: server_article?.title ?? "", + content: + server_article?.content ?? + `

Hey bearbeite mich!

`, - }, + }; + + const [loading, setLoading] = React.useState(false); + const form = useForm>({ + resolver: zodResolver(articleSchema), + defaultValues, }); // 2. Define a submit handler. async function onSubmit(values: z.infer) { + setLoading(true); await updateArticle(values, server_article.id); + setLoading(false); + form.reset(values); } const debouncedSubmit = React.useCallback( debounce(() => { form.handleSubmit(onSubmit)(); - }, 1000), + }, 3000), [form], ); return (
- + { { field.onChange(e); @@ -67,28 +74,42 @@ export default ({ server_article }: { server_article: Article }) => { )} /> +
+ ( + + + { + field.onChange(value.editor.getHTML()); + debouncedSubmit(); + }, + }} + /> + - ( - - - { - field.onChange(value.editor.getHTML()); - debouncedSubmit(); - }, - }} - /> - - - - - )} - /> + + + )} + /> +
+ + {!form.formState.isDirty && !loading + ? "gespeichert" + : "nicht gespeichert"} + +
+
); diff --git a/src/components/article/editor/editor.tsx b/src/components/article/editor/editor.tsx index b7daeea..2cd884a 100644 --- a/src/components/article/editor/editor.tsx +++ b/src/components/article/editor/editor.tsx @@ -1,4 +1,6 @@ "use client"; + +import "./styles.css"; import React from "react"; import { EditorProvider, EditorProviderProps } from "@tiptap/react"; import { MenuBar } from "./menu-bar"; @@ -12,12 +14,14 @@ function Editor({ readOnly?: boolean; }) { return ( - } - {...editorProviderProps} - /> +
+ } + {...editorProviderProps} + /> +
); } diff --git a/src/components/article/editor/extentions.ts b/src/components/article/editor/extentions.ts index 0a6f2a9..a651a14 100644 --- a/src/components/article/editor/extentions.ts +++ b/src/components/article/editor/extentions.ts @@ -9,6 +9,9 @@ export const extensions = [ /* @ts-ignore */ TextStyle.configure({ types: [ListItem.name] }), StarterKit.configure({ + code: false, + codeBlock: false, + horizontalRule: {}, bulletList: { keepMarks: true, keepAttributes: false, // TODO : Making this as `false` becase marks are not preserved when I try to preserve attrs, awaiting a bit of help diff --git a/src/components/article/editor/menu-bar.tsx b/src/components/article/editor/menu-bar.tsx index ce43186..bedd927 100644 --- a/src/components/article/editor/menu-bar.tsx +++ b/src/components/article/editor/menu-bar.tsx @@ -1,4 +1,7 @@ +import ColorPickerPopover from "@/components/color-picker/color-picker-popover"; import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { RGBAToHexA } from "@/lib/utils"; import { useCurrentEditor } from "@tiptap/react"; import { BoldIcon, @@ -17,6 +20,7 @@ import { SeparatorHorizontalIcon, StrikethroughIcon, TextIcon, + TypeIcon, UndoIcon, } from "lucide-react"; @@ -28,7 +32,10 @@ export const MenuBar = () => { } return ( -
+
+ {/*
+ +
*/}
@@ -57,7 +66,7 @@ export const MenuBar = () => { > - + */} - + */} - - - - {/* - */} + editor.chain().focus().setColor(color).run()} + /> +
+
+ + + + + + ); +} diff --git a/src/components/color-picker/color-picker.css b/src/components/color-picker/color-picker.css new file mode 100644 index 0000000..e68e5e3 --- /dev/null +++ b/src/components/color-picker/color-picker.css @@ -0,0 +1,16 @@ +.color-picker .react-colorful { + width: 100%; + height: 240px; +} +.color-picker .react-colorful__saturation { + border-radius: 4px 4px 0 0; +} +.color-picker .react-colorful__hue { + height: 40px; + border-radius: 0 0 4px 4px; +} +.color-picker .react-colorful__hue-pointer { + width: 12px; + height: inherit; + border-radius: 0; +} diff --git a/src/components/color-picker/index.tsx b/src/components/color-picker/index.tsx new file mode 100644 index 0000000..339430a --- /dev/null +++ b/src/components/color-picker/index.tsx @@ -0,0 +1,103 @@ +"use client"; +import "./color-picker.css"; + +import React from "react"; +import { useState, useEffect } from "react"; +import { HexColorPicker } from "react-colorful"; +import { Input } from "../ui/input"; +import { debounce } from "@/lib/utils"; + +const STORAGE_KEY = "savedColors"; +const MAX_COLORS = 12; +const SELECT_DEBOUNCE = 500; + +export type ColorPickerProps = { + onInput?: (color: string) => void; + initialColor?: string; +}; + +function ColorPicker({ onInput, initialColor }: ColorPickerProps) { + const [mounted, setMounted] = useState(false); + const [customColors, setCustomColors] = useState([]); + const [color, setColor] = useState(initialColor ?? "#ff0000"); + + // Load colors from localStorage on mount + useEffect(() => { + if (initialColor?.length) setColor(initialColor); + const storageColors = localStorage.getItem(STORAGE_KEY); + const storedColors = storageColors ? JSON.parse(storageColors) : []; + if (storedColors.length) { + setCustomColors(storedColors); + if (!initialColor?.length) setColor(storedColors[0]); + setMounted(true); + } + }, []); + + const persistColor = (newColor: string) => { + if (newColor.length < 2) return; + if (customColors[0] === newColor) return; // Prevent duplicate consecutive colors + + const updatedColors = [ + newColor, + ...customColors.filter((c) => c !== newColor), + ].slice(0, MAX_COLORS); + console.log(updatedColors); + + setCustomColors(updatedColors); + localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedColors)); + }; + + const selectColor = (newColor: string) => { + persistColor(newColor); + onInput?.(newColor); + }; + + const selectColorDebounced = debounce((newColor: string) => { + selectColor(newColor); + }, SELECT_DEBOUNCE); + + const handleColorChange = (newColor: string, skipDebounce = false) => { + setColor(newColor); + if (skipDebounce) + selectColor(newColor); // Delayed save + else selectColorDebounced(newColor); + }; + + return ( +
+ {/* React Colorful Picker */} + + + {/* Default Input (Native Color Picker) */} +
+
+ handleColorChange(e.currentTarget.value)} + /> +
+ + {/* Display Recent Colors */} +
+ {customColors.map((col) => ( +
+
+ ); +} + +export default ColorPicker; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 8a28624..5435c1a 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -20,3 +20,18 @@ export function debounce void>( timeoutId = setTimeout(() => func(...args), delay); }; } + +export function RGBAToHexA(rgba: string, forceRemoveAlpha = false) { + return ( + "#" + + rgba + .replace(/^rgba?\(|\s+|\)$/g, "") // Get's rgba / rgb string values + .split(",") // splits them at "," + .filter((string, index) => !forceRemoveAlpha || index !== 3) + .map((string) => parseFloat(string)) // Converts them to numbers + .map((number, index) => (index === 3 ? Math.round(number * 255) : number)) // Converts alpha to 255 number + .map((number) => number.toString(16)) // Converts numbers to hex + .map((string) => (string.length === 1 ? "0" + string : string)) // Adds 0 when length of one number is 1 + .join("") + ); // Puts the array to togehter to a string +} diff --git a/src/server/actions/article.ts b/src/server/actions/article.ts index e1e859c..ee3fb9d 100644 --- a/src/server/actions/article.ts +++ b/src/server/actions/article.ts @@ -22,7 +22,7 @@ export async function updateArticle( articleId, }); // if (!result[0]?.id?.length) return false; - // return revalidatePath(`/artikel/${result[0].id}/edit`); + // return revalidatePath(`/artikel/${result[0]?.slug}/edit`); } export async function deleteArticle(articleId: string) { const result = await api.article.delete({ diff --git a/src/server/api/routers/article.ts b/src/server/api/routers/article.ts index c107a2a..90fe7a1 100644 --- a/src/server/api/routers/article.ts +++ b/src/server/api/routers/article.ts @@ -86,7 +86,7 @@ export const articleRouter = createTRPCRouter({ .set(input.article) .where(eq(articles.id, input.articleId)) .returning({ - id: articles.id, + slug: articles.slug, }); }), delete: protectedProcedure