diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ced5f..62b5169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### What's New? +- Right Hand Cursor Mode added - Download as PNGs Option added - Interactive Cursor size component - More polished UI diff --git a/core/builder/config.py b/core/builder/config.py index 28c8a09..c12fcc8 100644 --- a/core/builder/config.py +++ b/core/builder/config.py @@ -33,6 +33,83 @@ def _assign(v) -> int: self.links = links +rconfigs: Dict[str, Config] = { + "left_ptr": Config( + x=207, + y=24, + winname="Pointer", + xname="left_ptr", + links=["arrow", "default", "top_left_arrow"], + ), + "left_ptr_watch": Config( + x=197, + y=24, + winname="Work", + xname="left_ptr_watch", + links=[ + "00000000000000020006000e7e9ffc3f", + "08e8e1c95fe2fc01f976f1e063a24ccd", + "3ecb610c1bf2410f44200f48c40d3599", + "progress", + ], + ), + "right_ptr": Config( + x=55, + y=17, + winname="Alternate", + xname="right_ptr", + links=["draft_large", "draft_small"], + ), + "circle": Config( + x=207, + y=24, + winname="Unavailable", + xname="circle", + links=["forbidden"], + ), + "context-menu": Config( + x=207, + y=24, + xname="context-menu", + ), + "copy": Config( + x=207, + y=24, + xname="copy", + links=[ + "1081e37283d90000800003c07f3ef6bf", + "6407b0e94181790501fd1e167b474872", + "b66166c04f8c3109214a4fbd64a50fc8", + ], + ), + "link": Config( + x=207, + y=24, + xname="link", + links=[ + "3085a0e285430894940527032f8b26df", + "640fb0e74195791501fd1ed57b41487f", + "a2a266d0498c3104214a47bd64ab0fc8", + ], + ), + "pointer-move": Config( + x=207, + y=24, + xname="pointer-move", + ), + "person": Config( + x=207, + y=24, + winname="Person", + ), + "pin": Config( + x=207, + y=24, + winname="Pin", + ), +} + + configs: Dict[str, Config] = { "bd_double_arrow": Config( winname="Dgn1", diff --git a/core/builder/cursor.py b/core/builder/cursor.py index 2e55e50..8224b13 100644 --- a/core/builder/cursor.py +++ b/core/builder/cursor.py @@ -7,7 +7,7 @@ from clickgen.writer import to_win, to_x11 from PIL import Image -from core.builder.config import configs, gsubtmp +from core.builder.config import configs, gsubtmp, rconfigs from core.utils.parser import UploadFormData @@ -18,6 +18,7 @@ def store_cursors(sid: str, data: UploadFormData, logger: Logger): platform = data.platform pngs = data.frames size = data.size + right_mode = data.mode == "right" delay = data.delay try: @@ -26,6 +27,8 @@ def store_cursors(sid: str, data: UploadFormData, logger: Logger): return None, errors config = configs.get(name, None) + if right_mode: + config = rconfigs.get(name, config) if not config: raise ValueError(f"Unable to find Configuration for '{name}'") else: diff --git a/core/utils/parser.py b/core/utils/parser.py index 7126703..9ca8b9a 100644 --- a/core/utils/parser.py +++ b/core/utils/parser.py @@ -13,6 +13,7 @@ class UploadFormData: platform: str size: int delay: int + mode: Literal["left", "right"] errors: List[str] @@ -20,6 +21,7 @@ def parse_upload_formdata(request: Request, logger: Logger): errors: List[str] = [] name: str = "" + mode: Literal["left", "right"] = "left" size: int = 0 delay: int = 0 platform: str = "" @@ -32,6 +34,7 @@ def parse_upload_formdata(request: Request, logger: Logger): raise ValueError("JSON data Not Found at 'data' key in FormData request.") else: data = json.loads(form_data) + s = data.get("size", None) if not s: raise ValueError("'size' Not Found in JSON 'data' ") @@ -58,6 +61,14 @@ def parse_upload_formdata(request: Request, logger: Logger): else: platform = p + m = data.get("mode", None) + if m != "left" and m != "right": + raise ValueError( + "Invalid 'mode' type. It must be type 'left' or 'right'" + ) + else: + mode = m + n = data.get("name", None) if not n: raise ValueError("'name' Not Found in JSON 'data' ") @@ -90,6 +101,7 @@ def parse_upload_formdata(request: Request, logger: Logger): size=size, delay=delay, platform=platform, + mode=mode, errors=errors, ) diff --git a/package.json b/package.json index 16be8cb..1fd5753 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "bibata", "description": "CLI for converting cursor svg files to png.", "author": "Abdulkaiz Khatri ", - "version": "1.0.0", + "version": "1.0.1", "private": true, "bugs": { "url": "https://github.com/ful1e5/bibata/issues", diff --git a/prisma/migrations/20240110062335_right_hand_cursor_type_added/migration.sql b/prisma/migrations/20240110062335_right_hand_cursor_type_added/migration.sql new file mode 100644 index 0000000..441bb09 --- /dev/null +++ b/prisma/migrations/20240110062335_right_hand_cursor_type_added/migration.sql @@ -0,0 +1,10 @@ +-- AlterEnum +-- This migration adds more than one value to an enum. +-- With PostgreSQL versions 11 and earlier, this is not possible +-- in a single migration. This can be worked around by creating +-- multiple migrations, each migration adding only one value to +-- the enum. + + +ALTER TYPE "Type" ADD VALUE 'ModernRight'; +ALTER TYPE "Type" ADD VALUE 'OriginalRight'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5d87c70..ddabaf9 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -26,7 +26,9 @@ enum Platform { enum Type { Modern + ModernRight Original + OriginalRight } model User { diff --git a/src/app/(home)/studio/page.tsx b/src/app/(home)/studio/page.tsx index 5775d4e..5447f56 100644 --- a/src/app/(home)/studio/page.tsx +++ b/src/app/(home)/studio/page.tsx @@ -20,6 +20,7 @@ import { Image } from 'bibata/app'; export default function StudioPage() { const [type, setType] = useState(TYPES[0]); + const [cursorMode, setCursorMode] = useState<'left' | 'right'>('left'); const [cursorSize, setCursorSize] = useState(SIZES[3]); const [colorName, setColorName] = useState('Amber'); @@ -71,12 +72,13 @@ export default function StudioPage() { />
!a.match('Right'))} value={type} - onClick={(v) => { - if (v !== type) { + onChange={(t, rhm) => { + if (t !== type) { resetImages(); - setType(v); + setType(t); + setCursorMode(rhm ? 'right' : 'left'); refreshToken(); } }} @@ -114,6 +116,7 @@ export default function StudioPage() { { - if (!type) { - return { error: `Invalid type: ${type}` }; - } - if (!TYPES.includes(type)) { - return { error: `${type} is not available` }; - } - +const update = async (version: string | null) => { const fetcher = new FetchSVG(); try { const redis = new ImageRedis(); + const file = await fetcher.getFile(); - const svgs = await fetcher.fetchSVGs({ type, version }); - if (!svgs) { - return { error: 'Something went wrong. SVGs. not found' }; - } + for (const type of TYPES) { + const svgs = await fetcher.fetchSVGs({ file, type, version }); + if (!svgs) { + return { + error: 'Something went wrong. SVGs. not found', + type, + version + }; + } - const key = `${type}:${version}`; - await redis.del(key); - await redis.saveSVGs(key, svgs); + const key = `${type}:${version}`; + await redis.del(key); + await redis.saveSVGs(key, svgs); + } return; } catch (e) { diff --git a/src/app/api/svg/route.ts b/src/app/api/svg/route.ts index 3e65869..e09bbe3 100644 --- a/src/app/api/svg/route.ts +++ b/src/app/api/svg/route.ts @@ -48,7 +48,7 @@ export async function GET(request: NextRequest) { } } else { return NextResponse.json( - { error: `No images found for '${type}'` }, + { error: `No cursor bitmaps found for '${type}'` }, { status: 404 } ); } diff --git a/src/components/DownloadButton/index.tsx b/src/components/DownloadButton/index.tsx index 2176048..31d5710 100644 --- a/src/components/DownloadButton/index.tsx +++ b/src/components/DownloadButton/index.tsx @@ -22,6 +22,7 @@ type Props = { lock?: boolean; auth: AuthToken; version: string; + mode: 'left' | 'right'; config: { type: string; color: Color; @@ -86,6 +87,7 @@ export const DownloadButton: React.FC = (props) => { name: i.name, frames: i.frames, delay: i.delay, + mode: props.mode, ...options }) ); diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 6c8697c..466632f 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -84,8 +84,8 @@ export const Footer: React.FC = (_props) => { rel='noopener noreferrer'> - - + + @@ -163,7 +163,7 @@ export const Footer: React.FC = (_props) => {

- Copyright © 2023-{currentYear} AbdulKaiz Khatri + Copyright © {currentYear} AbdulKaiz Khatri

diff --git a/src/components/Message.tsx b/src/components/Message.tsx index fb9073c..f23e188 100644 --- a/src/components/Message.tsx +++ b/src/components/Message.tsx @@ -13,26 +13,24 @@ type Props = { export const Message: React.FC = (props) => { return (
-
- -
- - {props.tag} - - - {props.message} - - - - -
- -
+ +
+ + {props.tag} + + + {props.message} + + + + +
+
); }; diff --git a/src/components/TypePicker.tsx b/src/components/TypePicker.tsx index 5ac64d5..221eb94 100644 --- a/src/components/TypePicker.tsx +++ b/src/components/TypePicker.tsx @@ -1,39 +1,56 @@ 'use client'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; -import { ModernSVG, OriginalSVG } from './svgs'; +import { FlipCursorSVG, ModernSVG, OriginalSVG } from './svgs'; interface Props { list: string[]; value: string; - onClick: (v: string) => void; // eslint-disable-line no-unused-vars + onChange: (v: string, m: boolean) => void; // eslint-disable-line no-unused-vars } export const TypePicker: React.FC = (props) => { + const [type, setType] = useState(props.value); + const [rightHandMode, setRightHandMode] = useState(false); + + useEffect(() => { + props.onChange(rightHandMode ? `${type}Right` : type, rightHandMode); + }, [type, rightHandMode]); // eslint-disable-line react-hooks/exhaustive-deps + return (
-
-
- {props.list.map((t) => ( - - ))} +
+
+ {props.list.map((t) => { + const active = props.value.includes(t); + + return ( + + ); + })} +
diff --git a/src/components/svgs/flip.tsx b/src/components/svgs/flip.tsx new file mode 100644 index 0000000..f12b65a --- /dev/null +++ b/src/components/svgs/flip.tsx @@ -0,0 +1,30 @@ +'use client'; + +import React from 'react'; + +type Props = { + flip?: boolean; +}; + +// eslint-disable-next-line no-unused-vars +export const FlipCursorSVG: React.FC = (props) => { + return ( + <> + {props.flip ? ( + + + + ) : ( + + + + )} + + ); +}; diff --git a/src/components/svgs/index.ts b/src/components/svgs/index.ts index 58c5625..80fb06e 100644 --- a/src/components/svgs/index.ts +++ b/src/components/svgs/index.ts @@ -27,6 +27,7 @@ import { CloseSVG } from './close'; import { ModernSVG } from './modern'; import { OriginalSVG } from './original'; +import { FlipCursorSVG } from './flip'; export { BibataTypoLogo, @@ -51,5 +52,6 @@ export { PaletteSVG, CloseSVG, ModernSVG, - OriginalSVG + OriginalSVG, + FlipCursorSVG }; diff --git a/src/components/svgs/modern.tsx b/src/components/svgs/modern.tsx index 926895f..5407f55 100644 --- a/src/components/svgs/modern.tsx +++ b/src/components/svgs/modern.tsx @@ -2,13 +2,16 @@ import React from 'react'; -type Props = {}; +type Props = { + flip?: boolean; +}; -// eslint-disable-next-line no-unused-vars -export const ModernSVG: React.FC = (_props) => { +export const ModernSVG: React.FC = (props) => { return ( diff --git a/src/components/svgs/original.tsx b/src/components/svgs/original.tsx index fbb27dd..4415036 100644 --- a/src/components/svgs/original.tsx +++ b/src/components/svgs/original.tsx @@ -2,13 +2,16 @@ import React from 'react'; -type Props = {}; +type Props = { + flip?: boolean; +}; -// eslint-disable-next-line no-unused-vars -export const OriginalSVG: React.FC = (_props) => { +export const OriginalSVG: React.FC = (props) => { return ( diff --git a/src/configs.ts b/src/configs.ts index f558332..1b494f2 100644 --- a/src/configs.ts +++ b/src/configs.ts @@ -1,6 +1,7 @@ import { Color, Colors, Delays } from 'bibata/app'; export const VERSIONS = [ + '1.0.1', '1.0.0', '1.0.0-beta.0', '1.0.0-alpha.1', @@ -14,7 +15,7 @@ export const BUG_REPORT_ENDPOINT = (title: string, body: string) => { return `https://github.com/ful1e5/bibata/issues/new?labels=bug,auto+generated&title=${title}&body=${body}`; }; -export const TYPES = ['Modern', 'Original']; +export const TYPES = ['Modern', 'ModernRight', 'Original', 'OriginalRight']; export const SIZES = [16, 20, 22, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96]; diff --git a/src/utils/figma/fetch-svgs.ts b/src/utils/figma/fetch-svgs.ts index 9a543d3..39374ec 100644 --- a/src/utils/figma/fetch-svgs.ts +++ b/src/utils/figma/fetch-svgs.ts @@ -4,6 +4,7 @@ import * as Figma from 'figma-api'; import { VERSIONS } from '@root/configs'; import { SVG } from 'bibata/app'; +import { GetFileResult } from 'figma-api/lib/api-types'; export type FetchImageOptions = { color?: { @@ -13,6 +14,7 @@ export type FetchImageOptions = { }; export type FetchSVGsOptions = { + file: GetFileResult; type: string; version: string | null; }; @@ -39,11 +41,14 @@ export class FetchSVG { } } - public async fetchSVGs({ type, version }: FetchSVGsOptions) { + public async getFile() { + return await this.api.getFile(this.key); + } + + public async fetchSVGs({ file, type, version }: FetchSVGsOptions) { if (!version || !VERSIONS.includes(version)) { throw new Error(`Invalid version: ${version}`); } - const file = await this.api.getFile(this.key); const page = file.document.children.filter( (e) => e.name === version @@ -57,7 +62,7 @@ export class FetchSVG { const entries: Figma.Node[] = []; - const groups = [type, 'Shared', 'Wait', `${type} Watch`]; + const groups = [type, `${type} Watch`, 'Shared', 'Wait']; page.children.forEach((e) => { if (e.type === 'GROUP' && groups.includes(e.name)) { diff --git a/src/version.ts b/src/version.ts index 3578d79..1137975 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const LIB_VERSION = "1.0.0"; +export const LIB_VERSION = "1.0.1";