From c72f63cfde3afe1ba2cf342b75fad02f8cd8fe51 Mon Sep 17 00:00:00 2001 From: udara Date: Mon, 30 Oct 2023 20:38:41 -0400 Subject: [PATCH] Add themes --- package.json | 2 +- release/app/package-lock.json | 4 +- release/app/package.json | 2 +- src/renderer/context/PilesContext.js | 46 +- .../pages/Pile/Editor/Editor.module.scss | 2 + .../pages/Pile/Editor/ProseMirror.scss | 2 +- src/renderer/pages/Pile/Layout.tsx | 21 +- .../pages/Pile/PileLayout.module.scss | 105 ++++ .../pages/Pile/Settings/Settings.module.scss | 42 +- src/renderer/pages/Pile/Settings/index.jsx | 39 +- yarn.lock | 477 ++++++++++-------- 11 files changed, 501 insertions(+), 241 deletions(-) diff --git a/package.json b/package.json index 7eb884d..d664f71 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts", "postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts", "lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx", - "package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish always", + "package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never", "rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app", "start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer", "start:main": "cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only .", diff --git a/release/app/package-lock.json b/release/app/package-lock.json index c5c0c8c..b272627 100644 --- a/release/app/package-lock.json +++ b/release/app/package-lock.json @@ -1,12 +1,12 @@ { "name": "pile", - "version": "0.7.20", + "version": "0.7.50", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "pile", - "version": "0.7.20", + "version": "0.7.50", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/release/app/package.json b/release/app/package.json index 927a24b..53d5787 100644 --- a/release/app/package.json +++ b/release/app/package.json @@ -1,6 +1,6 @@ { "name": "pile", - "version": "0.7.20", + "version": "0.7.50", "description": "Pile: Everyday journal and thought companion.", "license": "MIT", "author": { diff --git a/src/renderer/context/PilesContext.js b/src/renderer/context/PilesContext.js index a256cc8..60db46d 100644 --- a/src/renderer/context/PilesContext.js +++ b/src/renderer/context/PilesContext.js @@ -1,6 +1,19 @@ -import { useState, createContext, useContext, useEffect } from 'react'; +import { + useState, + createContext, + useContext, + useEffect, + useMemo, + useCallback, +} from 'react'; import { useLocation } from 'react-router-dom'; +export const availableThemes = { + light: { primary: '#4d80e6', secondary: '#fff' }, + purple: { primary: '#d014e1', secondary: '#fff' }, + yellow: { primary: '#ff9634', secondary: '#fff' }, +}; + export const PilesContext = createContext(); export const PilesContextProvider = ({ children }) => { @@ -11,7 +24,7 @@ export const PilesContextProvider = ({ children }) => { // Initialize config file useEffect(() => { getConfig(); - }, []); + }, [location]); // Set the current pile based on the url useEffect(() => { @@ -105,26 +118,29 @@ export const PilesContextProvider = ({ children }) => { // Update current pile const updateCurrentPile = (newPile) => { const newPiles = piles.map((pile) => { - if (currentPile.path === path) { - setCurrentPile(newPile); + if (pile.path === currentPile.path) { return newPile; } return pile; }); writeConfig(newPiles); + setCurrentPile(newPile); }; // THEMES - const getTheme = () => { - return currentPile.theme ?? 'light'; - }; - - const setTheme = (theme = 'light') => { - const valid = ['light', 'dark', 'purple', 'green', 'night']; - if (!valid.includes(theme)) return; - const _pile = { ...currentPile, theme: theme }; - updateCurrentPile(_pile); - }; + const currentTheme = useMemo(() => { + return currentPile?.theme ?? 'light'; + }, [currentPile]); + + const setTheme = useCallback( + (theme = 'light') => { + const valid = Object.keys(availableThemes); + if (!valid.includes(theme)) return; + const _pile = { ...currentPile, theme: theme }; + updateCurrentPile(_pile); + }, + [currentPile] + ); const pilesContextValue = { piles, @@ -132,6 +148,8 @@ export const PilesContextProvider = ({ children }) => { createPile, currentPile, deletePile, + currentTheme, + setTheme, }; return ( diff --git a/src/renderer/pages/Pile/Editor/Editor.module.scss b/src/renderer/pages/Pile/Editor/Editor.module.scss index ca397b6..a32d7e2 100644 --- a/src/renderer/pages/Pile/Editor/Editor.module.scss +++ b/src/renderer/pages/Pile/Editor/Editor.module.scss @@ -20,6 +20,8 @@ p { line-height: 1.45; + + &:first-child { margin-top: 0; } diff --git a/src/renderer/pages/Pile/Editor/ProseMirror.scss b/src/renderer/pages/Pile/Editor/ProseMirror.scss index 69b3e1b..c6a792a 100644 --- a/src/renderer/pages/Pile/Editor/ProseMirror.scss +++ b/src/renderer/pages/Pile/Editor/ProseMirror.scss @@ -5,7 +5,7 @@ position: relative; p.is-editor-empty:first-child::before { - color: #adb5bd; + color: var(--secondary); content: attr(data-placeholder); float: left; height: 0; diff --git a/src/renderer/pages/Pile/Layout.tsx b/src/renderer/pages/Pile/Layout.tsx index b3538eb..f759eb0 100644 --- a/src/renderer/pages/Pile/Layout.tsx +++ b/src/renderer/pages/Pile/Layout.tsx @@ -3,25 +3,37 @@ import styles from './PileLayout.module.scss'; import { HomeIcon } from 'renderer/icons'; import Sidebar from './Sidebar/Timeline/index'; import { CountUp } from 'use-count-up'; -import usePost from 'renderer/hooks/usePost'; import { useIndexContext } from 'renderer/context/IndexContext'; -import { useEffect, useState } from 'react'; +import { useEffect, useCallback } from 'react'; import { DateTime } from 'luxon'; import Settings from './Settings'; import HighlightsDialog from './Highlights'; +import { usePilesContext } from 'renderer/context/PilesContext'; export default function PileLayout({ children }) { const { pileName } = useParams(); const { index, refreshIndex } = useIndexContext(); - + const { currentTheme } = usePilesContext(); const now = DateTime.now().toLocaleString(DateTime.DATE_HUGE); useEffect(() => { window.scrollTo(0, 0); }, []); + const themeStyles = useCallback(() => { + switch (currentTheme) { + case 'purple': + return styles.purpleTheme; + case 'yellow': + return styles.yellowTheme; + default: + break; + } + }, [currentTheme]); + return ( -
+
+
@@ -61,6 +73,7 @@ export default function PileLayout({ children }) { {children}
+
); } diff --git a/src/renderer/pages/Pile/PileLayout.module.scss b/src/renderer/pages/Pile/PileLayout.module.scss index d9565ec..3a6439f 100644 --- a/src/renderer/pages/Pile/PileLayout.module.scss +++ b/src/renderer/pages/Pile/PileLayout.module.scss @@ -1,6 +1,109 @@ .frame { position: relative; max-width: 100vw; + color: var(--primary); +} + +.purpleTheme { + --brand: #00ff29; + --translucent: rgba(173, 138, 193, 0.5); + --sidebar-width: 250px; + --nav-height: 52px; + --primary: #57168c; + --secondary: #794d92; + --base: #d014e1; + --base-hover: #df38e5; + --base-yellow: #e6e04d; + --base-green: #4de64d; + --base-red: #ff2a2a; + --base-red-light: #ffdbdb; + --active: #e1ff8e; + --active-hover: #946d00; + --active-text: #fff; + --border: #be84dd; + --bg: #f9eeff; + --bg-secondary: rgb(195, 129, 226); + --bg-tertiary: rgb(207, 178, 225); + --bg-color-secondary-hover: rgb(226, 226, 226); + + @media (prefers-color-scheme: dark) { + --translucent: rgba(13, 10, 35, 0.5); + --sidebar-width: 250px; + --nav-height: 52px; + --primary: #ffe9ff; + --secondary: #ab92ae; + --base: #d014e1; + --base-hover: #df38e5; + --base-yellow: #776b0e; + --base-green: #128212; + --base-red: rgb(255, 116, 85); + --base-red-light: #3d2323; + --active: #e6ffa3; + --active-hover: #e6ffa3; + --active-text: #fff; + --border: #5f4263; + --bg: #251b24; + --bg-secondary: #481e51; + --bg-tertiary: #5a1a5f; + --bg-color-secondary-hover: rgb(114, 95, 122); + --bg-translucent: rgba(32, 10, 35, 0.45); + } +} + +.yellowTheme { + --brand: #00ff29; + --translucent: rgba(173, 138, 193, 0.5); + --sidebar-width: 250px; + --nav-height: 52px; + --primary: #412109; + --secondary: #88511e; + --base: #f18e1c; + --base-hover: #c5751f; + --base-yellow: #e6e04d; + --base-green: #4de64d; + --base-red: #ff3512; + --base-red-light: #ffdbdb; + --active: #193bff; + --active-hover: #001e94; + --active-text: #fff; + --border: #f6a446; + --bg: #fff7ee; + --bg-secondary: rgb(196, 130, 69); + --bg-tertiary: rgb(225, 208, 178); + --bg-color-secondary-hover: rgb(226, 226, 226); + + @media (prefers-color-scheme: dark) { + --translucent: rgba(13, 10, 35, 0.5); + --sidebar-width: 250px; + --nav-height: 52px; + --primary: #fff7e9; + --secondary: #aea392; + --base: #ff9634; + --base-hover: #df7000; + --base-yellow: #776b0e; + --base-green: #128212; + --base-red: rgb(255, 71, 71); + --base-red-light: #3d2323; + --active: #ff9500; + --active-hover: #df7000; + --active-text: #fff; + --border: #635342; + --bg: #25201b; + --bg-secondary: #51371e; + --bg-tertiary: #5f3b1a; + --bg-color-secondary-hover: rgb(122, 115, 95); + --bg-translucent: rgba(32, 10, 35, 0.45); + } +} + +.bg { + position: fixed; + top: 0; + left: 0; + height: 100%; + width: 100%; + background: var(--bg-secondary); + opacity: 0.3; } .nav { @@ -181,6 +284,7 @@ span { background: var(--bg-secondary); + color: var(--primary); padding: 2px 4px; border-radius: 7px; margin-right: 2px; @@ -211,6 +315,7 @@ .left { display: flex; margin-left: 16px; + color: var(--secondary); opacity: 0.5; transition: all ease-in-out 120ms; diff --git a/src/renderer/pages/Pile/Settings/Settings.module.scss b/src/renderer/pages/Pile/Settings/Settings.module.scss index 185b149..b1073bd 100644 --- a/src/renderer/pages/Pile/Settings/Settings.module.scss +++ b/src/renderer/pages/Pile/Settings/Settings.module.scss @@ -45,7 +45,7 @@ input { background-color: var(--bg-tertiary); position: fixed; inset: 0; - animation: overlayShow 150ms cubic-bezier(0.16, 1, 0.3, 1); + animation: overlayShow 120ms cubic-bezier(0.16, 1, 0.3, 1); opacity: 0.9; z-index: 4; } @@ -196,6 +196,46 @@ input { } } +.themes { + display: flex; + margin: -5px; + margin-bottom: 0px; + + .theme { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 32px; + width: 30px; + background: var(--bg-secondary); + margin: 5px; + border-radius: 12px; + + .color1 { + flex: 1 0 auto; + border-radius: 10px; + margin: 2px; + // margin-bottom: 0; + } + + .color2 { + flex: 1 0 auto; + border-radius: 0 0 10px 10px; + margin: 3px; + margin-top: 0; + } + + &:hover { + cursor: pointer; + background: var(--bg-tertiary); + } + + &.current { + background: var(--primary); + } + + } +} @keyframes overlayShow { from { diff --git a/src/renderer/pages/Pile/Settings/index.jsx b/src/renderer/pages/Pile/Settings/index.jsx index f7d3e7f..28e4b06 100644 --- a/src/renderer/pages/Pile/Settings/index.jsx +++ b/src/renderer/pages/Pile/Settings/index.jsx @@ -3,10 +3,15 @@ import { SettingsIcon, CrossIcon } from 'renderer/icons'; import { useEffect, useState } from 'react'; import * as Dialog from '@radix-ui/react-dialog'; import { useAIContext } from 'renderer/context/AIContext'; +import { + availableThemes, + usePilesContext, +} from 'renderer/context/PilesContext'; export default function Settings() { const { ai, prompt, getKey, setKey } = useAIContext(); const [key, setCurrentKey] = useState(''); + const { currentTheme, setTheme } = usePilesContext(); const retrieveKey = async () => { const k = await getKey(); @@ -27,6 +32,30 @@ export default function Settings() { } }; + const renderThemes = () => { + return Object.keys(availableThemes).map((theme) => { + const colors = availableThemes[theme]; + return ( + + ); + }); + }; return ( @@ -34,13 +63,21 @@ export default function Settings() {
- + Settings Configuration options for your Pile and AI + +
+ +
{renderThemes()}
+
+