From 6fc69e2f8834cab78638cb5494d7d68e64f52834 Mon Sep 17 00:00:00 2001 From: flooorianflo Date: Sun, 9 Jun 2024 13:21:13 +0200 Subject: [PATCH] feat: add experiments + fixes --- design-system/Icons.tsx | 54 ++++++ design-system/experiments.css | 28 ++++ design-system/global.css | 14 ++ interface/components/Popup.tsx | 2 +- interface/sections/FileSystem.tsx | 29 ++-- pages/archive/copyables/+Page.tsx | 85 ---------- pages/archive/copyables/+config.h.ts | 6 - .../archive/copyables/assets/vectorfiles.json | 60 ------- pages/archive/experiments/api-key/+Page.tsx | 120 +++++++++++++ .../archive/experiments/api-key/+config.h.ts | 4 + .../experiments/custom-caret/+Page.tsx | 158 ++++++++++++++++++ .../experiments/custom-caret/+config.h.ts | 4 + pages/archive/experiments/index/+Page.tsx | 155 +++++++++++++++++ pages/archive/experiments/index/+config.h.ts | 6 + pages/archive/index/+Page.tsx | 14 +- pages/archive/photos/+Page.tsx | 14 +- pages/archive/posts/+Page.tsx | 14 +- pages/archive/projects/index/+Page.tsx | 28 +--- pages/archive/short-projects/index/+Page.tsx | 28 +--- pages/inventory/+Page.tsx | 16 ++ pages/inventory/+config.h.ts | 4 + public/sitemap.xml | 54 +++--- 22 files changed, 623 insertions(+), 274 deletions(-) create mode 100644 design-system/experiments.css delete mode 100644 pages/archive/copyables/+Page.tsx delete mode 100644 pages/archive/copyables/+config.h.ts delete mode 100644 pages/archive/copyables/assets/vectorfiles.json create mode 100644 pages/archive/experiments/api-key/+Page.tsx create mode 100644 pages/archive/experiments/api-key/+config.h.ts create mode 100644 pages/archive/experiments/custom-caret/+Page.tsx create mode 100644 pages/archive/experiments/custom-caret/+config.h.ts create mode 100644 pages/archive/experiments/index/+Page.tsx create mode 100644 pages/archive/experiments/index/+config.h.ts create mode 100644 pages/inventory/+Page.tsx create mode 100644 pages/inventory/+config.h.ts diff --git a/design-system/Icons.tsx b/design-system/Icons.tsx index a10c9223..9322858e 100644 --- a/design-system/Icons.tsx +++ b/design-system/Icons.tsx @@ -424,3 +424,57 @@ export function Translate(props: { ) } + +export function Eye(props: { + size?: number + class?: string + stroke?: 2 | 1.5 + onClick?: () => void + fill?: string +}) { + return ( + + + + ) +} + +export function Rotate(props: { + size?: number + class?: string + stroke?: 2 | 1.5 + onClick?: () => void + fill?: string +}) { + return ( + + + + ) +} + +export function Trash(props: { + size?: number + class?: string + stroke?: 2 | 1.5 + onClick?: () => void + fill?: string +}) { + return ( + + + + ) +} diff --git a/design-system/experiments.css b/design-system/experiments.css new file mode 100644 index 00000000..d9019506 --- /dev/null +++ b/design-system/experiments.css @@ -0,0 +1,28 @@ +@keyframes blink { + 0%, 100% { + opacity: 1; + } + 25%, 75% { + opacity: 1; + } + 50% { + opacity: 0; + } + } + + .custom-caret { + position: absolute; + width: 2px; + height: 1.25em; + background: #3b82f6; + border-radius: 1000px; + animation: blink 1s step-end infinite; + pointer-events: none; + } + + .mirror-div { + visibility: hidden; + position: absolute; + white-space: pre-wrap; + word-wrap: break-word; + } \ No newline at end of file diff --git a/design-system/global.css b/design-system/global.css index 2be50bc9..b7bd64c8 100644 --- a/design-system/global.css +++ b/design-system/global.css @@ -145,6 +145,20 @@ h4, h5, h6 { font-size: 15px; } +.animate-svg path { + transition: stroke-dashoffset 0.3s ease-in-out; + } + + .checked path { + stroke-dasharray: 20; + stroke-dashoffset: 0; + } + + .unchecked path { + stroke-dasharray: 20; + stroke-dashoffset: 20; + } + @media (prefers-color-scheme: dark) { body { background-color: #000; diff --git a/interface/components/Popup.tsx b/interface/components/Popup.tsx index 1ab56258..7561c9e7 100644 --- a/interface/components/Popup.tsx +++ b/interface/components/Popup.tsx @@ -79,7 +79,7 @@ export function Popup({ popup, isOpen, onClose, children }: PopupProps) { type="secondary" function={onClose} rounded - class="absolute top-4 right-5 w-10 h-10 flex items-center justify-center" + class="absolute z-20 top-4 right-5 w-10 h-10 flex items-center justify-center" > diff --git a/interface/sections/FileSystem.tsx b/interface/sections/FileSystem.tsx index a5dd7990..e17e3ecc 100644 --- a/interface/sections/FileSystem.tsx +++ b/interface/sections/FileSystem.tsx @@ -1,16 +1,13 @@ import { JSX } from "preact/jsx-runtime" import { usePageContext } from "../../renderer/usePageContext" -import Vectorfiles from "../../pages/archive/copyables/assets/vectorfiles.json" import { InlineLink } from "#components/Button" import * as m from "#lang/paraglide/messages" -// TODO: Auto fill the amount of items in each tab export const tabs = [ { name: "Projects", path: "/archive/projects", items: { - amount: 2, label: "projects", }, }, @@ -18,23 +15,13 @@ export const tabs = [ name: "Short Projects", path: "/archive/short-projects", items: { - amount: 6, label: "projects", }, }, - { - name: "Copyables", - path: "/archive/copyables", - items: { - amount: Vectorfiles.length, - label: "copyables", - }, - }, { name: "Photos", path: "/archive/photos", items: { - amount: 10, label: "photos", }, }, @@ -42,10 +29,16 @@ export const tabs = [ name: "Posts", path: "/archive/posts", items: { - amount: 13, label: "posts", }, }, + { + name: "Experiments", + path: "/archive/experiments", + items: { + label: "experiments", + }, + }, ] export default function FileSystem(props: { @@ -93,13 +86,13 @@ export default function FileSystem(props: { {m.archive_title()} - {tabs.length} {m.categories()} + / @@ -117,13 +110,13 @@ export default function FileSystem(props: { {tab.name} - {`${tab.items.amount} ${tab.items.label}`} + {`/${tab.items.label}`} diff --git a/pages/archive/copyables/+Page.tsx b/pages/archive/copyables/+Page.tsx deleted file mode 100644 index 6b2068da..00000000 --- a/pages/archive/copyables/+Page.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import Vectorfiles from "./assets/vectorfiles.json" -import { useState } from "preact/hooks" -import { FolderIllustration } from "#design-system/Vectors" -import FileSystem from "#sections/FileSystem" - -/* How to add a new vector file: -1. Copy the SVG file -2. Go to https://onlinetexttools.com/replace-text and replace " with ' -3. Go to https://lingojam.com/TexttoOneLine and convert the SVG to one line -4. Add the file to the vectorfiles.json file inside of the assets folder -*/ - -Vectorfiles.reverse() - -export default function Page() { - return ( -
- -
- - {Vectorfiles.map((file) => { - return ( - -
-
-
- - ) - })} -
- -
- ) -} - -function Item(props: { fileData: string; children: any }) { - const [copied, setCopied] = useState(false) - - return ( - <> -
- {copied && ( -

- Copied! -

- )} -
{ - navigator.clipboard.writeText(props.fileData) - setCopied(true) - setTimeout(() => { - setCopied(false) - }, 1000) - }} - class="w-auto transition-opacity rounded-lg cursor-context-menu hover:opacity-75" - > - {props.children} -
-
- - ) -} diff --git a/pages/archive/copyables/+config.h.ts b/pages/archive/copyables/+config.h.ts deleted file mode 100644 index ee53b474..00000000 --- a/pages/archive/copyables/+config.h.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default { - title: "Copyables Archive | Florian - Design Engineer", - description: - "In my copyables, you will find code that you can copy and paste into your own projects. Feel free to look through if you are interested.", - image: "/images/opengraph/og-image-archive.jpg", -} diff --git a/pages/archive/copyables/assets/vectorfiles.json b/pages/archive/copyables/assets/vectorfiles.json deleted file mode 100644 index b009a426..00000000 --- a/pages/archive/copyables/assets/vectorfiles.json +++ /dev/null @@ -1,60 +0,0 @@ -[ - { - "name": "CD", - "data": "", - "source": "https://www.figma.com/community/file/1177354491329002534/cd-compact-disc" - }, - { - "name": "Cassette", - "data": "", - "source": "https://www.figma.com/community/file/1238315023143004952/walkman-tps-l2-illustration" - }, - { - "name": "Retro Button", - "data": "", - "source": "https://www.figma.com/community/file/1264637373341596251/macos-buttons-in-retrospect" - }, - { - "name": "Pointer", - "data": "", - "source": "https://www.figma.com/community/file/905067239318782670/cursors" - }, - { - "name": "HealthKit File", - "data": "" - }, - { - "name": "Stamp", - "data": "" - }, - { - "name": "Shirt Mockup", - "data": "", - "source": "https://www.figma.com/community/file/1176549358875268456/clothing-flat-mockup-technical-fashion" - }, - { - "name": "Hoodie Mockup", - "data": "", - "source": "https://www.figma.com/community/file/1176549358875268456/clothing-flat-mockup-technical-fashion" - }, - { - "name": "Credit Card", - "data": "" - }, - { - "name": "Select Widget", - "data": "" - }, - { - "name": "Selected Label", - "data": "" - }, - { - "name": "Paper Fold", - "data": "" - }, - { - "name": "Car", - "data": "" - } -] diff --git a/pages/archive/experiments/api-key/+Page.tsx b/pages/archive/experiments/api-key/+Page.tsx new file mode 100644 index 00000000..6b5ec384 --- /dev/null +++ b/pages/archive/experiments/api-key/+Page.tsx @@ -0,0 +1,120 @@ +import Button, { InlineLink } from "#components/Button" +import { Eye, Rotate, Trash } from "#design-system/Icons" +import { useState } from "preact/hooks" + +export default function Page() { + const [showSecret, setShowSecret] = useState(false) + const [loading, setLoading] = useState(false) + + return ( + <> +
+
+
+ + Archive + +

/

+ + Experiments + +

/

+

+ API Key +

+
+
+
+
+ + + + + + + + + + + + + +
NameSecretManage
+ Default API Key + +
+ {loading ? ( +
+ ) : ( + <> + {showSecret ? ( + + 3d4f2bf07dc1be38b20cd6e4694 + + ) : ( + ●●●●●●●●●●●●●●●●●● + )} + + + )} +
+
+
+ + +
+
+
+
+ + ) +} diff --git a/pages/archive/experiments/api-key/+config.h.ts b/pages/archive/experiments/api-key/+config.h.ts new file mode 100644 index 00000000..bd86b152 --- /dev/null +++ b/pages/archive/experiments/api-key/+config.h.ts @@ -0,0 +1,4 @@ +export default { + title: "API Key Creation Expiriment | Florian - Design Engineer", + description: "An experiment to create an API key on Florian's personal site.", +} diff --git a/pages/archive/experiments/custom-caret/+Page.tsx b/pages/archive/experiments/custom-caret/+Page.tsx new file mode 100644 index 00000000..5500ebd3 --- /dev/null +++ b/pages/archive/experiments/custom-caret/+Page.tsx @@ -0,0 +1,158 @@ +import { useState, useEffect, useRef } from "preact/hooks" +import { InlineLink } from "#components/Button" +import "#design-system/experiments.css" + +export default function Page() { + const [focused, setFocused] = useState(false) + const inputRef = useRef(null) + const caretRef = useRef(null) + const mirrorRef = useRef(null) + + useEffect(() => { + const input = inputRef.current + const caret = caretRef.current + const mirror = mirrorRef.current + + if (!input || !caret || !mirror) return + + const updateCaretPosition = () => { + const selectionStart = input.selectionStart || 0 + const text = input.value.substring(0, selectionStart) + + mirror.textContent = text + "\u200b" + + const inputStyles = window.getComputedStyle(input) + mirror.style.font = inputStyles.font + mirror.style.padding = inputStyles.padding + mirror.style.border = inputStyles.border + mirror.style.boxSizing = inputStyles.boxSizing + mirror.style.width = `${input.clientWidth}px` + + const range = document.createRange() + const textNode = mirror.firstChild + if (textNode) { + range.setStart(textNode, text.length) + range.setEnd(textNode, text.length) + } + const rects = range.getClientRects() + const rect = rects[rects.length - 1] + + if (rect) { + caret.style.left = `${ + rect.left - mirror.getBoundingClientRect().left + }px` + caret.style.top = `${rect.top - mirror.getBoundingClientRect().top}px` + } else { + caret.style.left = `12px` + caret.style.top = `12px` + } + } + + const handleInput = () => { + let inputValue = input.value + let lines = inputValue.split("\n") + + if (lines.length > 4) { + lines = lines.slice(0, 4) + } + + lines = lines.map((line) => + line.length > 58 ? line.substring(0, 58) : line + ) + + input.value = lines.join("\n") + + updateCaretPosition() + } + + const handleKeydown = (event: KeyboardEvent) => { + if ( + event.key === "Enter" || + event.key === "Backspace" || + event.key === "Delete" + ) { + requestAnimationFrame(updateCaretPosition) + } + } + + const handleMouseMove = (event: MouseEvent) => { + if (focused) return + + const rect = input.getBoundingClientRect() + const x = event.clientX - rect.left + const y = event.clientY - rect.top + + caret.style.left = `${x}px` + caret.style.top = `${y}px` + } + + input.addEventListener("input", handleInput) + input.addEventListener("click", handleInput) + input.addEventListener("keyup", handleInput) + input.addEventListener("keydown", handleKeydown) + input.addEventListener("mousemove", handleMouseMove) + + return () => { + input.removeEventListener("input", handleInput) + input.removeEventListener("click", handleInput) + input.removeEventListener("keyup", handleInput) + input.removeEventListener("keydown", handleKeydown) + input.removeEventListener("mousemove", handleMouseMove) + } + }, [focused]) + + return ( + <> +
+
+
+ + Archive + +

/

+ + Experiments + +

/

+

+ Custom Caret +

+
+
+
+
+

+ Noteblock +

+
+