From c8e7f559db7e022a39e6de6429dca8ca497d3625 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sun, 10 Oct 2021 07:53:01 -0700 Subject: [PATCH] Add macOS style titlebar (#23) - Add macOS titlebar icons - Add config in miscSlice - Fix title line height --- src/__tests__/App.test.tsx | 1 + src/components/layout/Titlebar.tsx | 163 +++++++++++++----- src/components/layout/styled.tsx | 25 +++ .../ConfigPanels/LookAndFeelConfig.tsx | 27 ++- src/components/shared/setDefaultSettings.ts | 4 + src/img/icons/close-mac-hover.png | Bin 0 -> 312 bytes src/img/icons/close-mac.png | Bin 0 -> 289 bytes src/img/icons/max-mac-hover.png | Bin 0 -> 329 bytes src/img/icons/max-mac.png | Bin 0 -> 290 bytes src/img/icons/min-mac-hover.png | Bin 0 -> 318 bytes src/img/icons/min-mac.png | Bin 0 -> 290 bytes src/redux/miscSlice.ts | 13 ++ src/styles/App.global.css | 19 ++ 13 files changed, 210 insertions(+), 42 deletions(-) create mode 100644 src/img/icons/close-mac-hover.png create mode 100644 src/img/icons/close-mac.png create mode 100644 src/img/icons/max-mac-hover.png create mode 100644 src/img/icons/max-mac.png create mode 100644 src/img/icons/min-mac-hover.png create mode 100644 src/img/icons/min-mac.png diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index e4d5137..74fd7d0 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -77,6 +77,7 @@ const miscState: General = { modalPages: [], isProcessingPlaylist: [], dynamicBackground: false, + titleBar: 'windows', }; const mockInitialState = { diff --git a/src/components/layout/Titlebar.tsx b/src/components/layout/Titlebar.tsx index d479a78..127d1fb 100644 --- a/src/components/layout/Titlebar.tsx +++ b/src/components/layout/Titlebar.tsx @@ -1,5 +1,12 @@ import React, { useEffect, useState } from 'react'; -import { TitleHeader, DragRegion, WindowControl, WindowControlButton } from './styled'; +import { + TitleHeader, + DragRegion, + WindowControl, + WindowControlButton, + MacControl, + MacControlButton, +} from './styled'; import { useAppSelector } from '../../redux/hooks'; import { getCurrentEntryList } from '../../shared/utils'; import logo from '../../../assets/icon.png'; @@ -7,7 +14,11 @@ import logo from '../../../assets/icon.png'; const Titlebar = ({ font }: any) => { const playQueue = useAppSelector((state) => state.playQueue); const player = useAppSelector((state) => state.player); + const misc = useAppSelector((state) => state.misc); const [title, setTitle] = useState(document.title); + const [hoverMin, setHoverMin] = useState(false); + const [hoverMax, setHoverMax] = useState(false); + const [hoverClose, setHoverClose] = useState(false); useEffect(() => { const currentEntryList = getCurrentEntryList(playQueue); @@ -27,46 +38,116 @@ const Titlebar = ({ font }: any) => { return ( -
- - - {title} - -
- - - - - - - - - - - - - - + {misc.titleBar === 'mac' && ( + <> +
+ {title} +
+ + + setHoverMin(true)} + onMouseLeave={() => setHoverMin(false)} + > + + + setHoverMax(true)} + onMouseLeave={() => setHoverMax(false)} + > + + + setHoverMax(true)} + onMouseLeave={() => setHoverMax(false)} + > + + + setHoverClose(true)} + onMouseLeave={() => setHoverClose(false)} + > + + + + + )} + + {misc.titleBar === 'windows' && ( + <> +
+ + + {title} + +
+ + + + + + + + + + + + + + + + )}
); diff --git a/src/components/layout/styled.tsx b/src/components/layout/styled.tsx index c4ff85b..ea532ba 100644 --- a/src/components/layout/styled.tsx +++ b/src/components/layout/styled.tsx @@ -71,6 +71,31 @@ export const WindowControl = styled.div` -webkit-app-region: no-drag; `; +export const MacControl = styled.div` + display: grid; + grid-template-columns: repeat(3, 30px); + position: absolute; + top: 0; + left: 0; + height: 100%; + + -webkit-app-region: no-drag; +`; + +export const MacControlButton = styled.div<{ + minButton?: boolean; + maxButton?: boolean; + restoreButton?: boolean; +}>` + user-select: none; + grid-row: 1 / span 1; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + grid-column: ${(props) => (props.minButton ? 2 : props.maxButton || props.restoreButton ? 3 : 1)}; +`; + export const WindowControlButton = styled.div<{ minButton?: boolean; maxButton?: boolean; diff --git a/src/components/settings/ConfigPanels/LookAndFeelConfig.tsx b/src/components/settings/ConfigPanels/LookAndFeelConfig.tsx index 0148168..f9547d8 100644 --- a/src/components/settings/ConfigPanels/LookAndFeelConfig.tsx +++ b/src/components/settings/ConfigPanels/LookAndFeelConfig.tsx @@ -12,7 +12,7 @@ import { import ListViewConfig from './ListViewConfig'; import { Fonts } from '../Fonts'; import { useAppDispatch } from '../../../redux/hooks'; -import { setTheme, setFont, setDynamicBackground } from '../../../redux/miscSlice'; +import { setTheme, setFont, setDynamicBackground, setMiscSetting } from '../../../redux/miscSlice'; import { songColumnPicker, songColumnList, @@ -83,6 +83,7 @@ const LookAndFeelConfig = () => { { settings.setSync('font', e); @@ -91,6 +92,30 @@ const LookAndFeelConfig = () => { />
+
+ Titlebar style (requires app restart) + +
+ { + settings.setSync('titleBarStyle', e); + dispatch(setMiscSetting({ setting: 'titleBar', value: e })); + }} + /> +
+

Select the columns you want displayed on pages with a list-view.

{ settings.setSync('cachePath', path.join(path.dirname(settings.file()))); } + if (force || !settings.hasSync('titleBarStyle')) { + settings.setSync('titleBarStyle', 'windows'); + } + if (force || !settings.hasSync('scrobble')) { settings.setSync('scrobble', false); } diff --git a/src/img/icons/close-mac-hover.png b/src/img/icons/close-mac-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..7f371fdad6a87eff3ac79b0b8341aa56071d7df8 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!Lyz&jv*HQYbTxLZFb;swVxQF;%o-Z zQw~!OYN~TB;P7%vnyBzE*{F%ra)ZrDgCG6>b&kz`E*V~-^Zs&-*$>-8uV0=tp6sD2 zw5-K#(X`0de5gI!uWZ2Ma9#9M=o;TU$|=h%`Wg*HLQ~j|p9#Et zH!`OA%9=Au;?GvRyr}c;%#plm{;T`GC*6pAC9%#iS?`Vfs*TEG*B6*=xAi^!oa@<& zOl#eBj;T>sw>jL;7Hm#_wxxHfUufRHiGBsu;(Sas4ED)hyg%av9s@nb;OXk;vd$@? F2>|jocVYkl literal 0 HcmV?d00001 diff --git a/src/img/icons/close-mac.png b/src/img/icons/close-mac.png new file mode 100644 index 0000000000000000000000000000000000000000..9c6ca5c017db35fbe6e01494b6352af380df39f3 GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X4tu&dhE&{2`t$$4J+o>QqGL_{8Zw7>3u+K+#)#Sd?nx0h!qZOv?bWJA>g#qx$PLNSRC_%}&L8pkLG@TjnVl{)9J zrOi@Wy5UshWfQ6XCMF*7hEuXf(+{`>Wc>gAo!{Bm1E{RmZ_djEO@k?+4hwtLrKUgf kVHZ(fvT){11|}YcK#AbGL$1H;f!<;8boFyt=akR{074;di2wiq literal 0 HcmV?d00001 diff --git a/src/img/icons/max-mac-hover.png b/src/img/icons/max-mac-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..d890aa296a8a0303a6bcd76d34e4507cb9a551d8 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!F!%Ajv*HQYbV|3Z88uz*1xLZ$PwO{7S@_% z2BC1pHA#mU_UvTn-qG0U=%9NqoXhJXdt-c2W_7*Yi`cch)@5=ztzSG-$6&{ye>EE_ zIBznU$=j(Vd*7UN`P~ie7o0C1o%nd?M44>VE$yfEA?2&OCY{>T@l&F{YeqOn;G10Y zl=ZSg+zWZCe+W4HO}>@D#qwj5z~O5L+9jG-m(G}3_xtw!3mdoTcbyD2U^Oy%BW~5! zSu%r3bC>SYE62@0C>~3gBfHF@De&oZ?ND>EDzDTVhnF9pVX~6gTe~DWM4fI5B|i literal 0 HcmV?d00001 diff --git a/src/img/icons/max-mac.png b/src/img/icons/max-mac.png new file mode 100644 index 0000000000000000000000000000000000000000..3a86691902b1f33f1e89f4bd4f8a3c9c683a3926 GIT binary patch literal 290 zcmV+-0p0$IP)1_?Zzo44|6p*||9C**Mr4SlC#>;(vbqX885v zC&SNgKN^ADMr1?KT@Ve@%*D^cz{G^`9UCXmFm|wE^*}@J0O=*T!oVM7GqPs5LZBE( z4(c_WfoKhLHr4=x$XU}g8jpek3>SdP9mQwBMo?(~`}Yq+Ge`_12aQgg>0l`^lvO~X ojVBtH;!Fn=C#0d7nE(O|04MZQedt=SxBvhE07*qoM6N<$f&d+JB>(^b literal 0 HcmV?d00001 diff --git a/src/img/icons/min-mac-hover.png b/src/img/icons/min-mac-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..0790f584239f50f7218f737fc2f248aa1dc823fc GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!ONa5jv*HQYbTu*Y%&mNmA6>*;;2@P%bvyd|H1bEC;#YvsBOJ`aB{wq zShs5l=h6tpY033(RKKvASRPHAtHjfgu=3w4&O2HUs?MiOD|Nl2t)f=Bo%N9Dh6x6} z$-g8nUyh7vyz%A@|CBbnV_&kw%2QMNZCj4nl^XKonDT`$Fk$`OdhCW^w|2mctm~!L zZyn^5Z~1j=PnaDxSAWwF#yu*X#|&$49gCT+Wo*BM^US^0i46H&;abP0l+XkKTMc_N literal 0 HcmV?d00001 diff --git a/src/img/icons/min-mac.png b/src/img/icons/min-mac.png new file mode 100644 index 0000000000000000000000000000000000000000..54e512c79604c9dcaadfc6340341118c037d2a30 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xj(EB_hE&{2`t$$4J+o>X+Qq`6+gT^-(ITm zj$4ZJg;)XJOF9Y%&K@|@@3AMkIIj5Ll>4B$~=|0;FP zVN08(v~) => { + switch (action.payload.setting) { + case 'titleBar': + state.titleBar = action.payload.value; + break; + default: + break; + } + }, + setContextMenu: (state, action: PayloadAction) => { state.contextMenu.show = action.payload.show; state.contextMenu.xPos = action.payload.xPos; @@ -156,5 +168,6 @@ export const { setContextMenu, setExpandSidebar, setDynamicBackground, + setMiscSetting, } = miscSlice.actions; export default miscSlice.reducer; diff --git a/src/styles/App.global.css b/src/styles/App.global.css index 642191c..95a5319 100644 --- a/src/styles/App.global.css +++ b/src/styles/App.global.css @@ -106,6 +106,25 @@ body { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + user-select: none; +} + +#window-title-wrapper-mac { + white-space: nowrap; + height: 100%; + padding: 2px; + text-align: center; +} + +#window-title-mac { + max-width: 60%; + width: 100%; + display: inline-block; + vertical-align: middle; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + user-select: none; } #restore-button {