diff --git a/README.DOCKER.md b/README.DOCKER.md index 4dfbef045..c3b38224d 100644 --- a/README.DOCKER.md +++ b/README.DOCKER.md @@ -49,7 +49,7 @@ Make an changes you need to `config/docker.json` then build the image. If it doe "web_port" : 8000, "enable_v3" : true, "mongodb_uri": "mongodb://172.17.0.2/homebrewery", -"enable_themes" : true, +"enable_themes" : true } ``` @@ -90,6 +90,13 @@ docker run --name homebrewery-mongodb -d --restart unless-stopped -v mongodata:/ docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v $(pwd)/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest ``` +**NOTE:** If you are running from the Windows command line, this will not work as `$(pwd)` is not valid syntax. Use this command instead: +```shell +# Make sure you run this in the homebrewery directory +docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v %cd%/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest +``` + + ## Updating the Image When Homebrewery code updates, your docker container will not automatically follow the changes. To do so you will need to rebuild your homebrewery image. @@ -117,3 +124,9 @@ docker-compose build homebrewery docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v $(pwd)/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest ``` +**NOTE:** If you are running from the Windows command line, this will not work as `$(pwd)` is not valid syntax. Use this command instead: +```shell +# Make sure you run this in the homebrewery directory +docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v %cd%/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest +``` + diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index 29973d221..787c2a3eb 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -7,15 +7,17 @@ import LockTools from './lockTools/lockTools.jsx'; const tabGroups = ['brew', 'notifications', 'authors', 'locks']; +const ADMIN_TAB = 'HB_adminPage_currentTab'; + const Admin = ()=>{ const [currentTab, setCurrentTab] = useState(''); useEffect(()=>{ - setCurrentTab(localStorage.getItem('hbAdminTab') || 'brew'); + setCurrentTab(localStorage.getItem(ADMIN_TAB) || 'brew'); }, []); useEffect(()=>{ - localStorage.setItem('hbAdminTab', currentTab); + localStorage.setItem(ADMIN_TAB, currentTab); }, [currentTab]); return ( diff --git a/client/components/splitPane/splitPane.jsx b/client/components/splitPane/splitPane.jsx index 4c77d81a5..78ba59ed3 100644 --- a/client/components/splitPane/splitPane.jsx +++ b/client/components/splitPane/splitPane.jsx @@ -2,7 +2,8 @@ require('./splitPane.less'); const React = require('react'); const { useState, useEffect } = React; -const storageKey = 'naturalcrit-pane-split'; +const PANE_WIDTH_KEY = 'HB_editor_splitWidth'; +const LIVE_SCROLL_KEY = 'HB_editor_liveScroll'; const SplitPane = (props)=>{ const { @@ -18,9 +19,9 @@ const SplitPane = (props)=>{ const [liveScroll, setLiveScroll] = useState(false); useEffect(()=>{ - const savedPos = window.localStorage.getItem(storageKey); + const savedPos = window.localStorage.getItem(PANE_WIDTH_KEY); setDividerPos(savedPos ? limitPosition(savedPos, 0.1 * (window.innerWidth - 13), 0.9 * (window.innerWidth - 13)) : window.innerWidth / 2); - setLiveScroll(window.localStorage.getItem('liveScroll') === 'true'); + setLiveScroll(window.localStorage.getItem(LIVE_SCROLL_KEY) === 'true'); window.addEventListener('resize', handleResize); return ()=>window.removeEventListener('resize', handleResize); @@ -29,13 +30,13 @@ const SplitPane = (props)=>{ const limitPosition = (x, min = 1, max = window.innerWidth - 13)=>Math.round(Math.min(max, Math.max(min, x))); //when resizing, the divider should grow smaller if less space is given, then grow back if the space is restored, to the original position - const handleResize = ()=>setDividerPos(limitPosition(window.localStorage.getItem(storageKey), 0.1 * (window.innerWidth - 13), 0.9 * (window.innerWidth - 13))); + const handleResize = ()=>setDividerPos(limitPosition(window.localStorage.getItem(PANE_WIDTH_KEY), 0.1 * (window.innerWidth - 13), 0.9 * (window.innerWidth - 13))); const handleUp =(e)=>{ e.preventDefault(); if(isDragging) { onDragFinish(dividerPos); - window.localStorage.setItem(storageKey, dividerPos); + window.localStorage.setItem(PANE_WIDTH_KEY, dividerPos); } setIsDragging(false); }; @@ -52,7 +53,7 @@ const SplitPane = (props)=>{ }; const liveScrollToggle = ()=>{ - window.localStorage.setItem('liveScroll', String(!liveScroll)); + window.localStorage.setItem(LIVE_SCROLL_KEY, String(!liveScroll)); setLiveScroll(!liveScroll); }; diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index be394c2c7..a19d33375 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -24,6 +24,8 @@ const PAGEBREAK_REGEX_LEGACY = /\\page(?:break)?/m; const COLUMNBREAK_REGEX_LEGACY = /\\column(:?break)?/m; const PAGE_HEIGHT = 1056; +const TOOLBAR_STATE_KEY = 'HB_renderer_toolbarState'; + const INITIAL_CONTENT = dedent` @@ -122,7 +124,7 @@ const BrewRenderer = (props)=>{ //useEffect to store or gather toolbar state from storage useEffect(()=>{ - const toolbarState = JSON.parse(window.localStorage.getItem('hb_toolbarState')); + const toolbarState = JSON.parse(window.localStorage.getItem(TOOLBAR_STATE_KEY)); toolbarState && setDisplayOptions(toolbarState); }, []); @@ -284,7 +286,7 @@ const BrewRenderer = (props)=>{ const handleDisplayOptionsChange = (newDisplayOptions)=>{ setDisplayOptions(newDisplayOptions); - localStorage.setItem('hb_toolbarState', JSON.stringify(newDisplayOptions)); + localStorage.setItem(TOOLBAR_STATE_KEY, JSON.stringify(newDisplayOptions)); }; const pagesStyle = { diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.jsx b/client/homebrew/brewRenderer/toolBar/toolBar.jsx index 6938eacb7..4aee3b6bd 100644 --- a/client/homebrew/brewRenderer/toolBar/toolBar.jsx +++ b/client/homebrew/brewRenderer/toolBar/toolBar.jsx @@ -9,6 +9,8 @@ import { Anchored, AnchoredBox, AnchoredTrigger } from '../../../components/Anch const MAX_ZOOM = 300; const MIN_ZOOM = 10; +const TOOLBAR_VISIBILITY = 'HB_renderer_toolbarVisibility'; + const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPages, headerState, setHeaderState })=>{ const [pageNum, setPageNum] = useState(1); @@ -21,8 +23,8 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa }, [visiblePages]); useEffect(()=>{ - const Visibility = localStorage.getItem('hb_toolbarVisibility'); - if (Visibility) setToolsVisible(Visibility === 'true'); + const Visibility = localStorage.getItem(TOOLBAR_VISIBILITY); + if(Visibility) setToolsVisible(Visibility === 'true'); }, []); @@ -100,7 +102,7 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 9f9e23625..a067ac4af 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -10,7 +10,7 @@ const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx'); const SnippetBar = require('./snippetbar/snippetbar.jsx'); const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); -const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME'; +const EDITOR_THEME_KEY = 'HB_editor_theme'; const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; const SNIPPETBREAK_REGEX_V3 = /^\\snippet\ .*$/; @@ -140,7 +140,7 @@ const Editor = createClass({ handleViewChange : function(newView){ this.props.setMoveArrows(newView === 'text'); - + this.setState({ view : newView }, ()=>{ diff --git a/client/homebrew/homebrew.jsx b/client/homebrew/homebrew.jsx index f670df8ab..bf51babc8 100644 --- a/client/homebrew/homebrew.jsx +++ b/client/homebrew/homebrew.jsx @@ -4,6 +4,8 @@ import './homebrew.less'; import React from 'react'; import { StaticRouter as Router, Route, Routes, useParams, useSearchParams } from 'react-router'; +import { updateLocalStorage } from './utils/updateLocalStorage/updateLocalStorageKeys.js'; + import HomePage from './pages/homePage/homePage.jsx'; import EditPage from './pages/editPage/editPage.jsx'; import UserPage from './pages/userPage/userPage.jsx'; @@ -57,6 +59,7 @@ const Homebrew = (props)=>{ } return null; }; + updateLocalStorage(); return ( diff --git a/client/homebrew/navbar/recent.navitem.jsx b/client/homebrew/navbar/recent.navitem.jsx index a6cbbf406..4c4722515 100644 --- a/client/homebrew/navbar/recent.navitem.jsx +++ b/client/homebrew/navbar/recent.navitem.jsx @@ -5,8 +5,8 @@ const Moment = require('moment'); const Nav = require('naturalcrit/nav/nav.jsx'); -const EDIT_KEY = 'homebrewery-recently-edited'; -const VIEW_KEY = 'homebrewery-recently-viewed'; +const EDIT_KEY = 'HB_nav_recentlyEdited'; +const VIEW_KEY = 'HB_nav_recentlyViewed'; const RecentItems = createClass({ diff --git a/client/homebrew/pages/accountPage/accountPage.jsx b/client/homebrew/pages/accountPage/accountPage.jsx index 598683504..b69eb6e3e 100644 --- a/client/homebrew/pages/accountPage/accountPage.jsx +++ b/client/homebrew/pages/accountPage/accountPage.jsx @@ -13,7 +13,7 @@ const AccountPage = (props)=>{ // initialize save location from local storage based on user id React.useEffect(()=>{ if(!saveLocation && accountDetails.username) { - SAVEKEY = `HOMEBREWERY-DEFAULT-SAVE-LOCATION-${accountDetails.username}`; + SAVEKEY = `HB_editor_defaultSave_${accountDetails.username}`; // if no SAVEKEY in local storage, default save location to Google Drive if user has Google account. let saveLocation = window.localStorage.getItem(SAVEKEY); saveLocation = saveLocation ?? (accountDetails.googleId ? 'GOOGLE-DRIVE' : 'HOMEBREWERY'); diff --git a/client/homebrew/pages/basePages/listPage/listPage.jsx b/client/homebrew/pages/basePages/listPage/listPage.jsx index ec557ffb1..4afc14364 100644 --- a/client/homebrew/pages/basePages/listPage/listPage.jsx +++ b/client/homebrew/pages/basePages/listPage/listPage.jsx @@ -7,7 +7,9 @@ const moment = require('moment'); const BrewItem = require('./brewItem/brewItem.jsx'); -const USERPAGE_KEY_PREFIX = 'HOMEBREWERY-LISTPAGE'; +const USERPAGE_SORT_DIR = 'HB_listPage_sortDir'; +const USERPAGE_SORT_TYPE = 'HB_listPage_sortType'; +const USERPAGE_GROUP_VISIBILITY_PREFIX = 'HB_listPage_visibility_group'; const DEFAULT_SORT_TYPE = 'alpha'; const DEFAULT_SORT_DIR = 'asc'; @@ -50,12 +52,12 @@ const ListPage = createClass({ // LOAD FROM LOCAL STORAGE if(typeof window !== 'undefined') { - const newSortType = (this.state.sortType ?? (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-SORTTYPE`) || DEFAULT_SORT_TYPE)); - const newSortDir = (this.state.sortDir ?? (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-SORTDIR`) || DEFAULT_SORT_DIR)); + const newSortType = (this.state.sortType ?? (localStorage.getItem(USERPAGE_SORT_TYPE) || DEFAULT_SORT_TYPE)); + const newSortDir = (this.state.sortDir ?? (localStorage.getItem(USERPAGE_SORT_DIR) || DEFAULT_SORT_DIR)); this.updateUrl(this.state.filterString, newSortType, newSortDir); const brewCollection = this.props.brewCollection.map((brewGroup)=>{ - brewGroup.visible = (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-VISIBILITY-${brewGroup.class}`) ?? 'true')=='true'; + brewGroup.visible = (localStorage.getItem(`${USERPAGE_GROUP_VISIBILITY_PREFIX}_${brewGroup.class}`) ?? 'true')=='true'; return brewGroup; }); @@ -73,10 +75,10 @@ const ListPage = createClass({ saveToLocalStorage : function() { this.state.brewCollection.map((brewGroup)=>{ - localStorage.setItem(`${USERPAGE_KEY_PREFIX}-VISIBILITY-${brewGroup.class}`, `${brewGroup.visible}`); + localStorage.setItem(`${USERPAGE_GROUP_VISIBILITY_PREFIX}_${brewGroup.class}`, `${brewGroup.visible}`); }); - localStorage.setItem(`${USERPAGE_KEY_PREFIX}-SORTTYPE`, this.state.sortType); - localStorage.setItem(`${USERPAGE_KEY_PREFIX}-SORTDIR`, this.state.sortDir); + localStorage.setItem(USERPAGE_SORT_TYPE, this.state.sortType); + localStorage.setItem(USERPAGE_SORT_DIR, this.state.sortDir); }, renderBrews : function(brews){ diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index aff5dd3ea..e3d449a55 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -1,48 +1,53 @@ /* eslint-disable max-lines */ import './editPage.less'; -import React, { useState, useEffect, useRef, useCallback } from 'react'; +// Common imports +import React, { useState, useEffect, useRef } from 'react'; import request from '../../utils/request-middleware.js'; import Markdown from 'naturalcrit/markdown.js'; -import _ from 'lodash';; -import { makePatches, stringifyPatches } from '@sanity/diff-match-patch'; -import { md5 } from 'hash-wasm'; -import { gzipSync, strToU8 } from 'fflate'; -import { Meta } from 'vitreum/headtags'; +import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; +import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js'; + +import SplitPane from 'client/components/splitPane/splitPane.jsx'; +import Editor from '../../editor/editor.jsx'; +import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; import Nav from 'naturalcrit/nav/nav.jsx'; import Navbar from '../../navbar/navbar.jsx'; import NewBrewItem from '../../navbar/newbrew.navitem.jsx'; import AccountNavItem from '../../navbar/account.navitem.jsx'; -import ShareNavItem from '../../navbar/share.navitem.jsx'; import ErrorNavItem from '../../navbar/error-navitem.jsx'; import HelpNavItem from '../../navbar/help.navitem.jsx'; import VaultNavItem from '../../navbar/vault.navitem.jsx'; import PrintNavItem from '../../navbar/print.navitem.jsx'; import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx'; -import SplitPane from 'client/components/splitPane/splitPane.jsx'; -import Editor from '../../editor/editor.jsx'; -import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; +// Page specific imports +import { Meta } from 'vitreum/headtags'; +import _ from 'lodash'; +import { md5 } from 'hash-wasm'; +import { gzipSync, strToU8 } from 'fflate'; +import { makePatches, stringifyPatches } from '@sanity/diff-match-patch'; +import ShareNavItem from '../../navbar/share.navitem.jsx'; import LockNotification from './lockNotification/lockNotification.jsx'; - -import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; -import { printCurrentBrew, fetchThemeBundle } from '../../../../shared/helpers.js'; - import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js'; - import googleDriveIcon from '../../googleDrive.svg'; const SAVE_TIMEOUT = 10000; const UNSAVED_WARNING_TIMEOUT = 900000; //Warn user afer 15 minutes of unsaved changes const UNSAVED_WARNING_POPUP_TIMEOUT = 4000; //Show the warning for 4 seconds -const BREWKEY = 'homebrewery-new'; -const STYLEKEY = 'homebrewery-new-style'; -const SNIPKEY = 'homebrewery-new-snippets'; -const METAKEY = 'homebrewery-new-meta'; + +const AUTOSAVE_KEY = 'HB_editor_autoSaveOn'; +const BREWKEY = 'HB_newPage_content'; +const STYLEKEY = 'HB_newPage_style'; +const SNIPKEY = 'HB_newPage_snippets'; +const METAKEY = 'HB_newPage_meta'; + + +const useLocalStorage = false; const EditPage = (props)=>{ props = { @@ -74,10 +79,8 @@ const EditPage = (props)=>{ const trySaveRef = useRef(trySave); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges - const useLocalStorage = false; - useEffect(()=>{ - const autoSavePref = JSON.parse(localStorage.getItem('AUTOSAVE_ON') ?? true); + const autoSavePref = JSON.parse(localStorage.getItem(AUTOSAVE_KEY) ?? true); setAutoSaveEnabled(autoSavePref); setWarnUnsavedChanges(!autoSavePref); setHTMLErrors(Markdown.validate(currentBrew.text)); @@ -120,18 +123,6 @@ const EditPage = (props)=>{ editorRef.current?.update(); }; - const handleEditorViewPageChange = (pageNumber)=>{ - setCurrentEditorViewPageNum(pageNumber); - }; - - const handleEditorCursorPageChange = (pageNumber)=>{ - setCurrentEditorCursorPageNum(pageNumber); - }; - - const handleBrewRendererPageChange = (pageNumber)=>{ - setCurrentBrewRendererPageNum(pageNumber); - }; - const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata' if (subfield == 'renderer' || subfield == 'theme') fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme); @@ -331,7 +322,7 @@ const EditPage = (props)=>{ const toggleAutoSave = ()=>{ clearTimeout(warnUnsavedTimeout.current); clearTimeout(saveTimeout.current); - localStorage.setItem('AUTOSAVE_ON', JSON.stringify(!autoSaveEnabled)); + localStorage.setItem(AUTOSAVE_KEY, JSON.stringify(!autoSaveEnabled)); setAutoSaveEnabled(!autoSaveEnabled); setWarnUnsavedChanges(autoSaveEnabled); }; @@ -361,11 +352,11 @@ const EditPage = (props)=>{ {renderSaveButton()} {renderAutoSaveButton()} } - - - + + + @@ -391,8 +382,8 @@ const EditPage = (props)=>{ userThemes={props.userThemes} themeBundle={themeBundle} updateBrew={updateBrew} - onCursorPageChange={handleEditorCursorPageChange} - onViewPageChange={handleEditorViewPageChange} + onCursorPageChange={setCurrentEditorCursorPageNum} + onViewPageChange={setCurrentEditorViewPageNum} currentEditorViewPageNum={currentEditorViewPageNum} currentEditorCursorPageNum={currentEditorCursorPageNum} currentBrewRendererPageNum={currentBrewRendererPageNum} @@ -405,7 +396,7 @@ const EditPage = (props)=>{ themeBundle={themeBundle} errors={HTMLErrors} lang={currentBrew.lang} - onPageChange={handleBrewRendererPageChange} + onPageChange={setCurrentBrewRendererPageNum} currentEditorViewPageNum={currentEditorViewPageNum} currentEditorCursorPageNum={currentEditorCursorPageNum} currentBrewRendererPageNum={currentBrewRendererPageNum} diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 16811576e..fdc439ab5 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -1,32 +1,38 @@ +/* eslint-disable max-lines */ import './homePage.less'; -import React from 'react'; -import { useEffect, useState, useRef } from 'react'; -import request from '../../utils/request-middleware.js'; -import Markdown from 'naturalcrit/markdown.js'; -import { Meta } from 'vitreum/headtags'; +// Common imports +import React, { useState, useEffect, useRef } from 'react'; +import request from '../../utils/request-middleware.js'; +import Markdown from 'naturalcrit/markdown.js'; -import Nav from 'naturalcrit/nav/nav.jsx'; -import Navbar from '../../navbar/navbar.jsx'; -import NewBrewItem from '../../navbar/newbrew.navitem.jsx'; -import HelpNavItem from '../../navbar/help.navitem.jsx'; -import VaultNavItem from '../../navbar/vault.navitem.jsx'; -import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx'; -import AccountNavItem from '../../navbar/account.navitem.jsx'; -import ErrorNavItem from '../../navbar/error-navitem.jsx'; -import { fetchThemeBundle } from '../../../../shared/helpers.js'; +import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; +import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js'; -import SplitPane from 'client/components/splitPane/splitPane.jsx'; -import Editor from '../../editor/editor.jsx'; -import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; +import SplitPane from 'client/components/splitPane/splitPane.jsx'; +import Editor from '../../editor/editor.jsx'; +import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; -import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; +import Nav from 'naturalcrit/nav/nav.jsx'; +import Navbar from '../../navbar/navbar.jsx'; +import NewBrewItem from '../../navbar/newbrew.navitem.jsx'; +import AccountNavItem from '../../navbar/account.navitem.jsx'; +import ErrorNavItem from '../../navbar/error-navitem.jsx'; +import HelpNavItem from '../../navbar/help.navitem.jsx'; +import VaultNavItem from '../../navbar/vault.navitem.jsx'; +import PrintNavItem from '../../navbar/print.navitem.jsx'; +import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx'; + +// Page specific imports +import { Meta } from 'vitreum/headtags'; const BREWKEY = 'homebrewery-new'; const STYLEKEY = 'homebrewery-new-style'; const SNIPKEY = 'homebrewery-new-snippets'; const METAKEY = 'homebrewery-new-meta'; +const useLocalStorage = false; + const HomePage =(props)=>{ props = { brew : DEFAULT_BREW, @@ -37,7 +43,7 @@ const HomePage =(props)=>{ const [currentBrew , setCurrentBrew] = useState(props.brew); const [welcomeText , setWelcomeText] = useState(props.brew.text); const [error , setError] = useState(undefined); - const [HTMLErrors , setHTMLErrors ] = useState(Markdown.validate(props.brew.text)); + const [HTMLErrors , setHTMLErrors] = useState(Markdown.validate(props.brew.text)); const [currentEditorViewPageNum , setCurrentEditorViewPageNum] = useState(1); const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1); const [currentBrewRendererPageNum, setCurrentBrewRendererPageNum] = useState(1); @@ -46,10 +52,24 @@ const HomePage =(props)=>{ const editorRef = useRef(null); - const useLocalStorage = false; - useEffect(()=>{ fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme); + + const handleControlKeys = (e)=>{ + if(!(e.ctrlKey || e.metaKey)) return; + if(e.keyCode === 83) trySaveRef.current(true); + if(e.keyCode === 80) printCurrentBrew(); + if([83, 80].includes(e.keyCode)) { + e.stopPropagation(); + e.preventDefault(); + } + }; + + document.addEventListener('keydown', handleControlKeys); + + return () => { + document.removeEventListener('keydown', handleControlKeys); + }; }, []); const save = ()=>{ @@ -69,18 +89,6 @@ const HomePage =(props)=>{ editorRef.current.update(); }; - const handleEditorViewPageChange = (pageNumber)=>{ - setCurrentEditorViewPageNum(pageNumber); - }; - - const handleEditorCursorPageChange = (pageNumber)=>{ - setCurrentEditorCursorPageNum(pageNumber); - }; - - const handleBrewRendererPageChange = (pageNumber)=>{ - setCurrentBrewRendererPageNum(pageNumber); - }; - const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata' if (subfield == 'renderer' || subfield == 'theme') fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme); @@ -117,6 +125,7 @@ const HomePage =(props)=>{ null } + @@ -138,8 +147,8 @@ const HomePage =(props)=>{ renderer={currentBrew.renderer} showEditButtons={false} themeBundle={themeBundle} - onCursorPageChange={handleEditorCursorPageChange} - onViewPageChange={handleEditorViewPageChange} + onCursorPageChange={setCurrentEditorCursorPageNum} + onViewPageChange={setCurrentEditorViewPageNum} currentEditorViewPageNum={currentEditorViewPageNum} currentEditorCursorPageNum={currentEditorCursorPageNum} currentBrewRendererPageNum={currentBrewRendererPageNum} @@ -148,7 +157,7 @@ const HomePage =(props)=>{ text={currentBrew.text} style={currentBrew.style} renderer={currentBrew.renderer} - onPageChange={handleBrewRendererPageChange} + onPageChange={setCurrentBrewRendererPageNum} currentEditorViewPageNum={currentEditorViewPageNum} currentEditorCursorPageNum={currentEditorCursorPageNum} currentBrewRendererPageNum={currentBrewRendererPageNum} diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index a22373d4a..d1d1fa75c 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -1,30 +1,40 @@ -/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/ +/* eslint-disable max-lines */ import './newPage.less'; +// Common imports import React, { useState, useEffect, useRef } from 'react'; import request from '../../utils/request-middleware.js'; import Markdown from 'naturalcrit/markdown.js'; -import Nav from 'naturalcrit/nav/nav.jsx'; -import Navbar from '../../navbar/navbar.jsx'; -import AccountNavItem from '../../navbar/account.navitem.jsx'; -import ErrorNavItem from '../../navbar/error-navitem.jsx'; -import HelpNavItem from '../../navbar/help.navitem.jsx'; -import PrintNavItem from '../../navbar/print.navitem.jsx'; -import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx'; +import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; +import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js'; import SplitPane from 'client/components/splitPane/splitPane.jsx'; import Editor from '../../editor/editor.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; -import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; -import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js'; +import Nav from 'naturalcrit/nav/nav.jsx'; +import Navbar from '../../navbar/navbar.jsx'; +import NewBrewItem from '../../navbar/newbrew.navitem.jsx'; +import AccountNavItem from '../../navbar/account.navitem.jsx'; +import ErrorNavItem from '../../navbar/error-navitem.jsx'; +import HelpNavItem from '../../navbar/help.navitem.jsx'; +import VaultNavItem from '../../navbar/vault.navitem.jsx'; +import PrintNavItem from '../../navbar/print.navitem.jsx'; +import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx'; -const BREWKEY = 'homebrewery-new'; -const STYLEKEY = 'homebrewery-new-style'; -const SNIPKEY = 'homebrewery-new-snippets'; -const METAKEY = 'homebrewery-new-meta'; -const SAVEKEYPREFIX = 'HOMEBREWERY-DEFAULT-SAVE-LOCATION-'; +// Page specific imports +import { Meta } from 'vitreum/headtags'; + + +const BREWKEY = 'HB_newPage_content'; +const STYLEKEY = 'HB_newPage_style'; +const METAKEY = 'HB_newPage_metadata'; +const SNIPKEY = 'HB_newPage_snippets'; +const SAVEKEYPREFIX = 'HB_editor_defaultSave_'; + + +const useLocalStorage = true; const NewPage = (props) => { props = { @@ -44,13 +54,22 @@ const NewPage = (props) => { const editorRef = useRef(null); - const useLocalStorage = true; - useEffect(() => { - document.addEventListener('keydown', handleControlKeys); loadBrew(); fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme); + const handleControlKeys = (e)=>{ + if(!(e.ctrlKey || e.metaKey)) return; + if(e.keyCode === 83) trySaveRef.current(true); + if(e.keyCode === 80) printCurrentBrew(); + if([83, 80].includes(e.keyCode)) { + e.stopPropagation(); + e.preventDefault(); + } + }; + + document.addEventListener('keydown', handleControlKeys); + return () => { document.removeEventListener('keydown', handleControlKeys); }; @@ -84,34 +103,10 @@ const NewPage = (props) => { window.history.replaceState({}, window.location.title, '/new/'); }; - const handleControlKeys = (e) => { - if (!(e.ctrlKey || e.metaKey)) return; - const S_KEY = 83; - const P_KEY = 80; - if (e.keyCode === S_KEY) save(); - if (e.keyCode === P_KEY) printCurrentBrew(); - if (e.keyCode === S_KEY || e.keyCode === P_KEY) { - e.preventDefault(); - e.stopPropagation(); - } - }; - const handleSplitMove = ()=>{ editorRef.current.update(); }; - const handleEditorViewPageChange = (pageNumber)=>{ - setCurrentEditorViewPageNum(pageNumber); - }; - - const handleEditorCursorPageChange = (pageNumber)=>{ - setCurrentEditorCursorPageNum(pageNumber); - }; - - const handleBrewRendererPageChange = (pageNumber)=>{ - setCurrentBrewRendererPageNum(pageNumber); - }; - const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata' if (subfield == 'renderer' || subfield == 'theme') fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme); @@ -190,8 +185,10 @@ const NewPage = (props) => { {error ? : renderSaveButton()} + + @@ -210,8 +207,8 @@ const NewPage = (props) => { renderer={currentBrew.renderer} userThemes={props.userThemes} themeBundle={themeBundle} - onCursorPageChange={handleEditorCursorPageChange} - onViewPageChange={handleEditorViewPageChange} + onCursorPageChange={setCurrentEditorCursorPageNum} + onViewPageChange={setCurrentEditorViewPageNum} currentEditorViewPageNum={currentEditorViewPageNum} currentEditorCursorPageNum={currentEditorCursorPageNum} currentBrewRendererPageNum={currentBrewRendererPageNum} @@ -224,7 +221,7 @@ const NewPage = (props) => { themeBundle={themeBundle} errors={HTMLErrors} lang={currentBrew.lang} - onPageChange={handleBrewRendererPageChange} + onPageChange={setCurrentBrewRendererPageNum} currentEditorViewPageNum={currentEditorViewPageNum} currentEditorCursorPageNum={currentEditorCursorPageNum} currentBrewRendererPageNum={currentBrewRendererPageNum} diff --git a/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js new file mode 100644 index 000000000..b4a05974f --- /dev/null +++ b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js @@ -0,0 +1,35 @@ + +const getLocalStorageMap = function(){ + const localStorageMap = { + 'AUTOSAVE_ON' : 'HB_editor_autoSaveOn', + 'HOMEBREWERY-EDITOR-THEME' : 'HB_editor_theme', + 'liveScroll' : 'HB_editor_liveScroll', + 'naturalcrit-pane-split' : 'HB_editor_splitWidth', + + 'HOMEBREWERY-LISTPAGE-SORTDIR' : 'HB_listPage_sortDir', + 'HOMEBREWERY-LISTPAGE-SORTTYPE' : 'HB_listPage_sortType', + 'HOMEBREWERY-LISTPAGE-VISIBILITY-published' : 'HB_listPage_visibility_group_published', + 'HOMEBREWERY-LISTPAGE-VISIBILITY-unpublished' : 'HB_listPage_visibility_group_unpublished', + + 'hbAdminTab' : 'HB_adminPage_currentTab', + + 'homebrewery-new' : 'HB_newPage_content', + 'homebrewery-new-meta' : 'HB_newPage_metadata', + 'homebrewery-new-style' : 'HB_newPage_style', + + 'homebrewery-recently-edited' : 'HB_nav_recentlyEdited', + 'homebrewery-recently-viewed' : 'HB_nav_recentlyViewed', + + 'hb_toolbarState' : 'HB_renderer_toolbarState', + 'hb_toolbarVisibility' : 'HB_renderer_toolbarVisibility' + }; + + if(global?.account?.username){ + const username = global.account.username; + localStorageMap[`HOMEBREWERY-DEFAULT-SAVE-LOCATION-${username}`] = `HB_editor_defaultSave_${username}`; + } + + return localStorageMap; +}; + +export default getLocalStorageMap; \ No newline at end of file diff --git a/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js new file mode 100644 index 000000000..ac61d4add --- /dev/null +++ b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js @@ -0,0 +1,30 @@ +import getLocalStorageMap from './localStorageKeyMap.js'; + +describe('getLocalStorageMap', ()=>{ + it('no username', ()=>{ + const account = global.account; + + delete global.account; + + const map = getLocalStorageMap(); + + global.account = account; + + expect(map).toBeInstanceOf(Object); + expect(Object.entries(map)).toHaveLength(16); + }); + + it('no username', ()=>{ + const account = global.account; + + global.account = { username: 'test' }; + + const map = getLocalStorageMap(); + + global.account = account; + + expect(map).toBeInstanceOf(Object); + expect(Object.entries(map)).toHaveLength(17); + expect(map).toHaveProperty('HOMEBREWERY-DEFAULT-SAVE-LOCATION-test', 'HB_editor_defaultSave_test'); + }); +}); \ No newline at end of file diff --git a/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js b/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js new file mode 100644 index 000000000..1a8231f73 --- /dev/null +++ b/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js @@ -0,0 +1,25 @@ +import getLocalStorageMap from './localStorageKeyMap.js'; + +const updateLocalStorage = function(){ + // Return if no window and thus no local storage + if(typeof window === 'undefined') return; + + // Return if the local storage key map has no content + const localStorageKeyMap = getLocalStorageMap(); + if(Object.keys(localStorageKeyMap).length == 0) return; + + const storage = window.localStorage; + + Object.keys(localStorageKeyMap).forEach((key)=>{ + if(storage[key]){ + if(!storage[localStorageKeyMap[key]]){ + const data = storage.getItem(key); + storage.setItem(localStorageKeyMap[key], data); + }; + storage.removeItem(key); + } + }); + +}; + +export { updateLocalStorage }; \ No newline at end of file