diff --git a/package-lock.json b/package-lock.json index b522ca5..d6991b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "hacks-of-mistria", - "version": "0.2.1", + "version": "0.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "hacks-of-mistria", - "version": "0.2.1", + "version": "0.4.0", "hasInstallScript": true, "dependencies": { "@chakra-ui/react": "^3.0.2", @@ -18,7 +18,8 @@ "next-themes": "^0.4.3", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-icons": "^5.3.0" + "react-icons": "^5.3.0", + "zustand": "^5.0.1" }, "devDependencies": { "@vitejs/plugin-react": "^4.3.1", @@ -6459,6 +6460,35 @@ "engines": { "node": ">= 10" } + }, + "node_modules/zustand": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.1.tgz", + "integrity": "sha512-pRET7Lao2z+n5R/HduXMio35TncTlSW68WsYBq2Lg1ASspsNGjpwLAsij3RpouyV6+kHMwwwzP0bZPD70/Jx/w==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index a15fb61..8b15e1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hacks-of-mistria", - "version": "0.3.0", + "version": "0.4.0", "description": "A tool to edit your save files in Fields of Mistria", "main": "./out/main/index.js", "author": "arkatsy, dwlim12", @@ -22,7 +22,8 @@ "next-themes": "^0.4.3", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-icons": "^5.3.0" + "react-icons": "^5.3.0", + "zustand": "^5.0.1" }, "devDependencies": { "@vitejs/plugin-react": "^4.3.1", diff --git a/src/renderer/src/app.jsx b/src/renderer/src/app.jsx index 817c65b..9879ce6 100644 --- a/src/renderer/src/app.jsx +++ b/src/renderer/src/app.jsx @@ -1,9 +1,9 @@ -import { useState } from "react" import { Image, Box } from "@chakra-ui/react" import SaveSelection from "@components/save-selection" import SaveEditing from "@components/save-editing" -import fomClouds from "@assets/fom-clouds.png" import fomLogo from "@assets/fom-logo.webp" +import background from "@assets/fom-bg1.png" +import { useStore } from "./store" function Layout({ children }) { return ( @@ -16,36 +16,28 @@ function Layout({ children }) { alignItems="center" pos="relative" > + + {children} background - - {children} ) } export function App() { - const [editingSaveId, setEditingSaveId] = useState(null) + const { editingSaveId } = useStore() - const goToEditing = (saveId) => setEditingSaveId(saveId) - const goToSelection = () => setEditingSaveId(null) - - return ( - - {editingSaveId ? ( - - ) : ( - - )} - - ) + return {editingSaveId ? : } } diff --git a/src/renderer/src/components/loading.jsx b/src/renderer/src/components/loading.jsx index 09d0f16..7510d0c 100644 --- a/src/renderer/src/components/loading.jsx +++ b/src/renderer/src/components/loading.jsx @@ -1,10 +1,13 @@ -import { Center, Flex, Text, Spinner } from "@chakra-ui/react" +import { Center, Flex, Text, Spinner, VStack } from "@chakra-ui/react" -export default function Loading({ text }) { +export default function Loading({ text = "", extra = "" }) { return (
- {text} + + {text} + {extra} +
diff --git a/src/renderer/src/components/number-input.jsx b/src/renderer/src/components/number-input.jsx index 34b2564..486f0b3 100644 --- a/src/renderer/src/components/number-input.jsx +++ b/src/renderer/src/components/number-input.jsx @@ -11,8 +11,9 @@ export default function NumberInput({ value, onValueChange, step, min, label, he value={+value || 0} onValueChange={(e) => onValueChange(+e.value)} w="full" + bg="orange.900/10" > - + diff --git a/src/renderer/src/components/save-card.jsx b/src/renderer/src/components/save-card.jsx index d02807b..eafb5e3 100644 --- a/src/renderer/src/components/save-card.jsx +++ b/src/renderer/src/components/save-card.jsx @@ -49,7 +49,7 @@ const weatherIcons = [ } ] -function SaveCard({ save, onClick }) { +export default function SaveCard({ save, onClick }) { const { header, autosave, id } = save const data = { @@ -62,15 +62,46 @@ function SaveCard({ save, onClick }) { onClick && onClick(id) } + const season = displayCalendarTime(header.calendar_time).split(" ")[2].toLowerCase() + + const styles = { + background: { + spring: "rose.950", + summer: "green.950", + fall: "yellow.950", + winter: "teal.900" + }, + foreground: { + spring: "rose.50", + summer: "green.100/90", + fall: "yellow.100/75", + winter: "teal.50" + }, + border: { + spring: "rose.600", + summer: "green.600", + fall: "yellow.600", + winter: "teal.600" + } + } + + const isSpring = season === "spring" + const isSummer = season === "summer" + const isFall = season === "fall" + const isWinter = season === "winter" + return ( @@ -123,5 +154,3 @@ function SaveCard({ save, onClick }) { ) } - -export default memo(SaveCard) diff --git a/src/renderer/src/components/save-editing.jsx b/src/renderer/src/components/save-editing.jsx index a3b5205..c8f189f 100644 --- a/src/renderer/src/components/save-editing.jsx +++ b/src/renderer/src/components/save-editing.jsx @@ -28,8 +28,12 @@ import { seasonsList, getCalendarTime, PronounsList, formatPronouns } from "@uti import Loading from "./loading" import { useSaveData } from "../queries" import { useSaveDataMutation } from "../mutations" +import { useStore } from "../store" +import { LuArrowLeft } from "react-icons/lu" + +export default function SaveEditing() { + const { goToSelection: onBack, editingSaveId: saveId } = useStore() -export default function SaveEditing({ saveId, onBack }) { const { data: saveData, isError: isErrorData } = useSaveData(saveId) const { mutate: updateSave, @@ -100,15 +104,15 @@ export default function SaveEditing({ saveId, onBack }) { return ( - - + {saveData.id} @@ -136,6 +140,7 @@ export default function SaveEditing({ saveId, onBack }) { + return } const filteredSaves = data.filter((save) => { @@ -65,7 +66,7 @@ export default function SaveSelection({ onSaveSelected }) { } function handleSaveClick(saveId) { - onSaveSelected(saveId) + setEditingSaveId(saveId) } const handleRefreshClick = () => refreshSaves() @@ -76,7 +77,8 @@ export default function SaveSelection({ onSaveSelected }) { }> {visibleSaves.length === 0 ? ( @@ -99,7 +101,7 @@ export default function SaveSelection({ onSaveSelected }) { {visibleSaves.map((save) => ( ))} - + )} - + - - - - - + ) diff --git a/src/renderer/src/components/select-input.jsx b/src/renderer/src/components/select-input.jsx index 3ea8cf0..70ced86 100644 --- a/src/renderer/src/components/select-input.jsx +++ b/src/renderer/src/components/select-input.jsx @@ -9,14 +9,19 @@ import { export default function SelectInput({ collection, textLabel, currentValue, onValueChange }) { return ( - onValueChange(e.value[0])}> + onValueChange(e.value[0])}> {textLabel} - + - + {collection.items.map((item) => ( - + {item.label} ))} diff --git a/src/renderer/src/components/text-input.jsx b/src/renderer/src/components/text-input.jsx index fdb495f..db3dd9f 100644 --- a/src/renderer/src/components/text-input.jsx +++ b/src/renderer/src/components/text-input.jsx @@ -5,7 +5,7 @@ import { Input } from "@chakra-ui/react" export default function TextInput({ currentValue, textLabel, onChange, icon }) { return ( - + onChange(e.target.value)} /> diff --git a/src/renderer/src/components/ui/color-picker.jsx b/src/renderer/src/components/ui/color-picker.jsx new file mode 100644 index 0000000..b245f06 --- /dev/null +++ b/src/renderer/src/components/ui/color-picker.jsx @@ -0,0 +1,158 @@ +import { + ColorPicker as ChakraColorPicker, + For, + IconButton, + Portal, + Span, + Stack, + Text, + VStack +} from "@chakra-ui/react" +import { forwardRef } from "react" +import { LuCheck, LuPipette } from "react-icons/lu" + +export const ColorPickerTrigger = forwardRef(function ColorPickerTrigger(props, ref) { + const { fitContent, ...rest } = props + return ( + + {props.children || } + + ) +}) + +export const ColorPickerInput = forwardRef(function ColorHexInput(props, ref) { + return +}) + +export const ColorPickerContent = forwardRef(function ColorPickerContent(props, ref) { + const { portalled = true, portalRef, ...rest } = props + return ( + + + + + + ) +}) + +export const ColorPickerInlineContent = forwardRef(function ColorPickerInlineContent(props, ref) { + return ( + + ) +}) + +export const ColorPickerSliders = forwardRef(function ColorPickerSliders(props, ref) { + return ( + + + + + ) +}) + +export const ColorPickerArea = forwardRef(function ColorPickerArea(props, ref) { + return ( + + + + + ) +}) + +export const ColorPickerEyeDropper = forwardRef(function ColorPickerEyeDropper(props, ref) { + return ( + + + + + + ) +}) + +export const ColorPickerChannelSlider = forwardRef(function ColorPickerSlider(props, ref) { + return ( + + + + + + ) +}) + +export const ColorPickerSwatchTrigger = forwardRef(function ColorPickerSwatchTrigger(props, ref) { + const { swatchSize, children, ...rest } = props + return ( + + {children || ( + + + + + + )} + + ) +}) + +export const ColorPickerRoot = forwardRef(function ColorPickerRoot(props, ref) { + return ( + + {props.children} + + + ) +}) + +const formatMap = { + rgba: ["red", "green", "blue", "alpha"], + hsla: ["hue", "saturation", "lightness", "alpha"], + hsba: ["hue", "saturation", "brightness", "alpha"], + hexa: ["hex", "alpha"] +} + +export const ColorPickerChannelInputs = forwardRef(function ColorPickerChannelInputs(props, ref) { + const channels = formatMap[props.format] + return ( + + {channels.map((channel) => ( + + + + {channel.charAt(0).toUpperCase()} + + + ))} + + ) +}) + +export const ColorPickerChannelSliders = forwardRef(function ColorPickerChannelSliders(props, ref) { + const channels = formatMap[props.format] + return ( + + + {(channel) => ( + + + {channel} + + + + )} + + + ) +}) + +export const ColorPickerLabel = ChakraColorPicker.Label +export const ColorPickerControl = ChakraColorPicker.Control +export const ColorPickerValueText = ChakraColorPicker.ValueText +export const ColorPickerValueSwatch = ChakraColorPicker.ValueSwatch +export const ColorPickerChannelInput = ChakraColorPicker.ChannelInput +export const ColorPickerSwatchGroup = ChakraColorPicker.SwatchGroup diff --git a/src/renderer/src/components/ui/number-input.jsx b/src/renderer/src/components/ui/number-input.jsx index 1c8afe4..d569465 100644 --- a/src/renderer/src/components/ui/number-input.jsx +++ b/src/renderer/src/components/ui/number-input.jsx @@ -7,8 +7,16 @@ export const NumberInputRoot = forwardRef(function NumberInput(props, ref) { {children} - - + + ) diff --git a/src/renderer/src/components/ui/provider.jsx b/src/renderer/src/components/ui/provider.jsx index 5c18de2..7f90bf1 100644 --- a/src/renderer/src/components/ui/provider.jsx +++ b/src/renderer/src/components/ui/provider.jsx @@ -1,10 +1,13 @@ -import { ChakraProvider, defaultSystem } from "@chakra-ui/react" +import { ChakraProvider, Theme } from "@chakra-ui/react" import { ColorModeProvider } from "./color-mode" +import { system } from "../../theme" export function Provider(props) { return ( - - + + + + ) } diff --git a/src/renderer/src/components/unpacking-measurement.jsx b/src/renderer/src/components/unpacking-measurement.jsx index dc512f4..8728696 100644 --- a/src/renderer/src/components/unpacking-measurement.jsx +++ b/src/renderer/src/components/unpacking-measurement.jsx @@ -1,5 +1,5 @@ -import { Box, HStack, Stack, Text } from "@chakra-ui/react" import { useState, useEffect } from "react" +import { Stack, Text, HStack, Box } from "@chakra-ui/react" import InputNumber from "@components/number-input" import { Button } from "@components/ui/button" @@ -27,8 +27,10 @@ export default function UnpackingMeasurement() { } return ( - - Measure Unpacking Time + + + Measure Unpacking Time + - - {report && {report}} + {report && ( + + {report} + + )} ) } diff --git a/src/renderer/src/main.jsx b/src/renderer/src/main.jsx index 8744f38..e32f54f 100644 --- a/src/renderer/src/main.jsx +++ b/src/renderer/src/main.jsx @@ -1,4 +1,3 @@ -import "./styles/globals.css" import { StrictMode } from "react" import { createRoot } from "react-dom/client" import { App } from "./app" @@ -11,7 +10,7 @@ const queryClient = new QueryClient() createRoot(document.getElementById("root")).render( - + diff --git a/src/renderer/src/store.js b/src/renderer/src/store.js new file mode 100644 index 0000000..c9fc1d1 --- /dev/null +++ b/src/renderer/src/store.js @@ -0,0 +1,7 @@ +import { create } from "zustand"; + +export const useStore = create((set) => ({ + editingSaveId: null, + setEditingSaveId: (saveId) => set({ editingSaveId: saveId }), + goToSelection: () => set({ editingSaveId: null }) +})) diff --git a/src/renderer/src/styles/globals.css b/src/renderer/src/styles/globals.css deleted file mode 100644 index fcc0b4a..0000000 --- a/src/renderer/src/styles/globals.css +++ /dev/null @@ -1,22 +0,0 @@ -::selection { - background-color: #f4e1d2; - color: #000; -} - -*, -*::before, -*::after { - font-family: cursive, system-ui; -} - -::-webkit-scrollbar { - display: none; -} - -::-webkit-scrollbar-button { - display: none; -} - -body { - -ms-overflow-style: none; -} diff --git a/src/renderer/src/theme.js b/src/renderer/src/theme.js new file mode 100644 index 0000000..9e20400 --- /dev/null +++ b/src/renderer/src/theme.js @@ -0,0 +1,120 @@ +import { defineConfig, defaultConfig, createSystem } from "@chakra-ui/react" + +const config = defineConfig({ + cssVarsRoot: ":where(html)", + globalCss: { + "*::selection": { + bg: "rose.500", + color: "white" + }, + "*::-webkit-scrollbar": { + display: "none" + }, + "*::-webkit-scrollbar-button": { + display: "none" + }, + "*, *::before, *::after": { + fontFamily: "cursive, system-ui, sans-serif" + } + }, + theme: { + tokens: { + colors: { + indigo: { + 50: { value: "#eef2ff" }, + 100: { value: "#e0e7ff" }, + 200: { value: "#c7d2fe" }, + 300: { value: "#a5b4fc" }, + 400: { value: "#818cf8" }, + 500: { value: "#6366f1" }, + 600: { value: "#4f46e5" }, + 700: { value: "#4338ca" }, + 800: { value: "#3730a3" }, + 900: { value: "#312e81" }, + 950: { value: "#1e1b4b" } + }, + violet: { + 50: { value: "#f5f3ff" }, + 100: { value: "#ede9fe" }, + 200: { value: "#ddd6fe" }, + 300: { value: "#c4b5fd" }, + 400: { value: "#a78bfa" }, + 500: { value: "#8b5cf6" }, + 600: { value: "#7c3aed" }, + 700: { value: "#6d28d9" }, + 800: { value: "#5b21b6" }, + 900: { value: "#4c1d95" }, + 950: { value: "#2e1065" } + }, + rose: { + 50: { value: "#fff1f2" }, + 100: { value: "#ffe4e6" }, + 200: { value: "#fecdd3" }, + 300: { value: "#fda4af" }, + 400: { value: "#fb7185" }, + 500: { value: "#f43f5e" }, + 600: { value: "#e11d48" }, + 700: { value: "#be123c" }, + 800: { value: "#9f1239" }, + 900: { value: "#881337" }, + 950: { value: "#4c0519" } + }, + slate: { + 50: { value: "#f8fafc" }, + 100: { value: "#f1f5f9" }, + 200: { value: "#e2e8f0" }, + 300: { value: "#cbd5e1" }, + 400: { value: "#94a3b8" }, + 500: { vaue: "#64748b" }, + 600: { value: "#475569" }, + 700: { value: "#334155" }, + 800: { value: "#1e293b" }, + 900: { value: "#0f172a" }, + 950: { value: "#020617" } + } + } + }, + semanticTokens: { + colors: { + rose: { + solid: { value: "{colors.rose.500}" }, + contrast: { value: "{colors.rose.100}" }, + fg: { value: "{colors.rose.700}" }, + muted: { value: "{colors.rose.100}" }, + subtle: { value: "{colors.rose.200}" }, + emphasized: { value: "{colors.rose.300}" }, + focusRing: { value: "{colors.rose.500}" } + }, + violet: { + solid: { value: "{colors.violet.500}" }, + contrast: { value: "{colors.violet.100}" }, + fg: { value: "{colors.violet.700}" }, + muted: { value: "{colors.violet.100}" }, + subtle: { value: "{colors.violet.200}" }, + emphasized: { value: "{colors.violet.300}" }, + focusRing: { value: "{colors.violet.500}" } + }, + indigo: { + solid: { value: "{colors.indigo.500}" }, + contrast: { value: "{colors.indigo.100}" }, + fg: { value: "{colors.indigo.700}" }, + muted: { value: "{colors.indigo.100}" }, + subtle: { value: "{colors.indigo.200}" }, + emphasized: { value: "{colors.indigo.300}" }, + focusRing: { value: "{colors.indigo.500}" } + }, + slate: { + solid: { value: "{colors.slate.500}" }, + contrast: { value: "{colors.slate.100}" }, + fg: { value: "{colors.slate.700}" }, + muted: { value: "{colors.slate.100}" }, + subtle: { value: "{colors.slate.200}" }, + emphasized: { value: "{colors.slate.300}" }, + focusRing: { value: "{colors.slate.500}" } + } + } + } + } +}) + +export const system = createSystem(config, defaultConfig)