diff --git a/package.json b/package.json index fabd94b..ea4e855 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,12 @@ }, "dependencies": { "@tauri-apps/api": "^1.5.3", - "color-convert": "^2.0.1", "dayjs": "^1.11.10", "solid-icons": "^1.1.0", "solid-js": "^1.8.16" }, "devDependencies": { "@tauri-apps/cli": "^1.5.11", - "@types/color-convert": "^2.0.3", "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "prettier": "^3.2.5", diff --git a/src-tauri/src/service/clipboard.rs b/src-tauri/src/service/clipboard.rs index 71eb38d..779822a 100644 --- a/src-tauri/src/service/clipboard.rs +++ b/src-tauri/src/service/clipboard.rs @@ -4,7 +4,6 @@ use crate::connection; use alloc::borrow::Cow; use arboard::ImageData; use entity::clipboard::{self, ActiveModel, Model}; -use migration::IntoIndexColumn; use sea_orm::{ ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect, QueryTrait, Set, @@ -49,78 +48,60 @@ pub async fn get_clipboards_db( ) -> Result, DbErr> { let db = connection::establish_connection().await?; - let mut query = clipboard::Entity::find(); - - // filter to get only pinned entries - if let Some(starred) = star { - query = query.filter(clipboard::Column::Star.eq(starred)); - } - - // filter to get only images - if let Some(img) = img { - query = query.filter(clipboard::Column::Type.eq("image")); - } - - // smart search - if let Some(content) = search { - - // display text entries - let filter = if content == "txt" || content == "text" { - clipboard::Column::Content.contains(&content) - .or(clipboard::Column::Type.eq("text")) - - // display image entries - } else if content == "img" || content == "image" { - clipboard::Column::Content.contains(&content) - .or(clipboard::Column::Type.eq("image")) - - // display link entries - } else if content == "lnk" || content == "link" { - clipboard::Column::Content.contains(&content) - .or(clipboard::Column::Type.eq("link")) - - // display color entries - } else if content == "clr" || content == "color" { - clipboard::Column::Content.contains(&content) - .or(clipboard::Column::Type.eq("hex")) - .or(clipboard::Column::Type.eq("rgb")) - } else if content == "hex" { - clipboard::Column::Content.contains(&content) - .or(clipboard::Column::Type.eq("hex")) - } else if content == "rgb" { - clipboard::Column::Content.contains(&content) - .or(clipboard::Column::Type.eq("rgb")) - - // use default search - } else { - clipboard::Column::Content.contains(&content) - }; - - query = query.filter(filter) - .order_by_desc(clipboard::Column::Content.starts_with(&content)); - - } else { - // order the results by creation time by default - query = query.order_by_desc(clipboard::Column::Id); - } - - query = query.offset(cursor).limit(10); - - let model = query.all(&db).await?; + let model = clipboard::Entity::find() + .apply_if(star, |query, starred| { + query.filter(clipboard::Column::Star.eq(starred)) + }) + .apply_if(search, |query, search| { + let filter = match search.as_str() { + "txt" | "text" => clipboard::Column::Content + .contains(search) + .or(clipboard::Column::Type.eq("text")), + + "img" | "image" => clipboard::Column::Content + .contains(search) + .or(clipboard::Column::Type.eq("image")), + + "lnk" | "link" => clipboard::Column::Content + .contains(search) + .or(clipboard::Column::Type.eq("link")), + + "clr" | "color" | "colour" => clipboard::Column::Content + .contains(search) + .or(clipboard::Column::Type.eq("hex")) + .or(clipboard::Column::Type.eq("rgb")), + + "hex" => clipboard::Column::Content + .contains(search) + .or(clipboard::Column::Type.eq("hex")), + + "rgb" => clipboard::Column::Content + .contains(search) + .or(clipboard::Column::Type.eq("rgb")), + + _ => clipboard::Column::Content.contains(search), + }; + query.filter(filter) + }) + .apply_if(img, |query, _img| { + query.filter(clipboard::Column::Type.eq("image")) + }) + .offset(cursor) + .limit(10) + .order_by_desc(clipboard::Column::Id) + .all(&db) + .await?; let parsed_model: Vec = model .into_iter() .map(|mut m| { - if let Some(blob) = &m.blob { + if let Some(blob) = m.blob.take() { let base64_string = base64::encode_config(blob, base64::STANDARD); m.base64 = Some(format!("data:image/png;base64,{}", base64_string)); - m.blob = None; } - // Safely truncate content if it's longer than 100 characters if let Some(content) = &m.content { if content.chars().count() > 100 { - // Take the first 100 characters, and collect them back into a String let truncated = content.chars().take(100).collect::(); m.content = Some(truncated); } @@ -132,7 +113,6 @@ pub async fn get_clipboards_db( Ok(parsed_model) } - pub async fn star_clipboard_db(id: i32, star: bool) -> Result { let db = connection::establish_connection().await?; diff --git a/src/components/pages/app/Clipboards.tsx b/src/components/pages/app/Clipboards.tsx index 287a2fb..95a9831 100644 --- a/src/components/pages/app/Clipboards.tsx +++ b/src/components/pages/app/Clipboards.tsx @@ -12,8 +12,8 @@ import { Clips } from "../../../@types"; import clippy from "../../../assets/clippy.png"; import ClipboardStore from "../../../store/ClipboardStore"; import HotkeyStore from "../../../store/HotkeyStore"; +import { rgbCompatible } from "../../../utils/colors"; import { formatBytes } from "../../../utils/helpers"; -import { hsvToRgbString, hwbToRgbString } from "../../../utils/convertors"; dayjs.extend(utc); dayjs.extend(relativeTime); @@ -58,7 +58,7 @@ export const Clipboards: Component = ({}) => { }} class={`${ clipboard.star ? "text-yellow-400 dark:text-yellow-300" : "hidden text-zinc-700" - } z-10 h-2/4 w-8 py-2 text-xs hover:text-yellow-400 group-hover:block dark:text-white dark:hover:text-yellow-300`} + } z-10 hover:text-yellow-400 group-hover:block dark:text-white dark:hover:text-yellow-300`} /> { @@ -67,7 +67,7 @@ export const Clipboards: Component = ({}) => { setClipboards((prev) => prev.filter((o) => o.id !== id)); } }} - class="hidden h-2/4 w-8 py-2 text-xs text-zinc-700 hover:text-red-600 group-hover:block dark:text-white dark:hover:text-red-600" + class="hidden text-zinc-700 hover:text-red-600 group-hover:block dark:text-white dark:hover:text-red-600" /> ); @@ -135,23 +135,13 @@ export const Clipboards: Component = ({}) => { {type === "hex" && (
)} {type === "rgb" && (
)} @@ -179,9 +169,7 @@ export const Clipboards: Component = ({}) => {
{dayjs.utc(created_date!).fromNow()}
-
-
{IconFunctions(clipboard)}
-
+
{IconFunctions(clipboard)}

diff --git a/src/utils/colors.ts b/src/utils/colors.ts new file mode 100644 index 0000000..2af76f0 --- /dev/null +++ b/src/utils/colors.ts @@ -0,0 +1,103 @@ +export function rgbCompatible(color?: string | null) { + if (color?.includes("hsv")) return hsvToRgbString(color); + if (color?.includes("hwb")) return hwbToRgbString(color); + return color; +} + +export function hsvToRgbString(hsvString: string): string { + // Parse HSV values from input string + const hsvRegex = /hsv\((\d+),\s*(\d+)%?,\s*(\d+)%?\)/; + const match = hsvString.match(hsvRegex); + if (!match) { + return ""; + } + + const hue: number = parseInt(match[1]); + const saturation: number = parseInt(match[2]) / 100; + const value: number = parseInt(match[3]) / 100; + + const chroma: number = value * saturation; + const hueSegment: number = hue / 60; + const x: number = chroma * (1 - Math.abs((hueSegment % 2) - 1)); + const m: number = value - chroma; + + let red: number = 0; + let green: number = 0; + let blue: number = 0; + + if (hueSegment >= 0 && hueSegment < 1) { + red = chroma; + green = x; + } else if (hueSegment >= 1 && hueSegment < 2) { + red = x; + green = chroma; + } else if (hueSegment >= 2 && hueSegment < 3) { + green = chroma; + blue = x; + } else if (hueSegment >= 3 && hueSegment < 4) { + green = x; + blue = chroma; + } else if (hueSegment >= 4 && hueSegment < 5) { + red = x; + blue = chroma; + } else { + red = chroma; + blue = x; + } + + red = Math.round((red + m) * 255); + green = Math.round((green + m) * 255); + blue = Math.round((blue + m) * 255); + + const rgbString: string = `rgb(${red}, ${green}, ${blue})`; + return rgbString; +} + +export function hwbToRgbString(hwbString: string): string { + // Parse HWB values from input string + const hwbRegex = /hwb\((\d+),\s*(\d+\.?\d*?)%,\s*(\d+\.?\d*?)%\)/; + const match = hwbString.match(hwbRegex); + if (!match) { + return ""; + } + + const hue: number = parseFloat(match[1]); + const whiteness: number = parseFloat(match[2]) / 100; + const blackness: number = parseFloat(match[3]) / 100; + + const chroma: number = 1 - whiteness - blackness; + const hueSegment: number = hue / 60; + const x: number = chroma * (1 - Math.abs((hueSegment % 2) - 1)); + const m: number = 1 - chroma; + + let red: number = 0; + let green: number = 0; + let blue: number = 0; + + if (hueSegment >= 0 && hueSegment < 1) { + red = chroma; + green = x; + } else if (hueSegment >= 1 && hueSegment < 2) { + red = x; + green = chroma; + } else if (hueSegment >= 2 && hueSegment < 3) { + green = chroma; + blue = x; + } else if (hueSegment >= 3 && hueSegment < 4) { + green = x; + blue = chroma; + } else if (hueSegment >= 4 && hueSegment < 5) { + red = x; + blue = chroma; + } else { + red = chroma; + blue = x; + } + + red = Math.round((red + whiteness) * 255); + green = Math.round((green + whiteness) * 255); + blue = Math.round((blue + whiteness) * 255); + + const rgbString: string = `rgb(${red}, ${green}, ${blue})`; + return rgbString; +} diff --git a/src/utils/convertors.ts b/src/utils/convertors.ts deleted file mode 100644 index 8b9aa26..0000000 --- a/src/utils/convertors.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { hsv, hwb } from 'color-convert'; - -export function hsvToRgbString(hsvString: string): string { - - // Parse HSV values from input string - const hsvRegex = /hsv\((\d+),\s*(\d+),\s*(\d+)\)/; - const match = hsvString.match(hsvRegex); - if (!match) { - return ""; - } - - const hue: number = parseInt(match[1]); - const saturation: number = parseInt(match[2]); - const value: number = parseInt(match[3]); - - const [red, green, blue] = hsv.rgb([hue, saturation, value]); - - const rgbString: string = `rgb(${red}, ${green}, ${blue})`; - return rgbString; -} - -export function hwbToRgbString(hwbString: string): string { - - // Parse HWB values from input string - const hwbRegex = /hwb\((\d+),\s*(\d+\.?\d*?)%,\s*(\d+\.?\d*?)%\)/; - const match = hwbString.match(hwbRegex); - if (!match) { - return ""; - } - - const hue: number = parseFloat(match[1]); - const whiteness: number = parseFloat(match[2]); - const blackness: number = parseFloat(match[3]); - - const [red, green, blue] = hwb.rgb([hue, whiteness, blackness]); - - const rgbString: string = `rgb(${red}, ${green}, ${blue})`; - return rgbString; -}