Add macOS traffic light controls and enhance window management
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Introduced a new MacOSTrafficLights component to manage window controls (close, minimize, fullscreen) with custom SVG icons. - Updated DashboardWindowButtons to integrate the new traffic light controls for macOS. - Enhanced window control functionality in mainWindow.js to toggle fullscreen mode. - Added CSS styles for traffic light indicators to improve visual representation. - Refactored DashboardNavigation to streamline the handling of fullscreen state.
@ -190,6 +190,27 @@ html.macos-vibrancy .dark-mode .ant-layout.main-content-layout .ant-card {
|
||||
background: rgba(31, 31, 31, 0.5) !important;
|
||||
}
|
||||
|
||||
.redTrafficLight {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: #fe5f57;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.yellowTrafficLight {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: #febc2e;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.greenTrafficLight {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: #28c840;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.electron-navigation {
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
8
assets/trafficlights/closecolored.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(241,0,27);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.3 21.1,81.8 42.7,81.8Z" style="fill:rgb(255,92,96);"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 804 B |
12
assets/trafficlights/closedowncolored.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(202,2,24);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.3 21.1,81.8 42.7,81.8Z" style="fill:rgb(212,76,80);"/>
|
||||
<g>
|
||||
<path d="M22.5,57.8L57.8,22.5C59.2,21.1 61.4,21.1 62.8,22.5L62.9,22.6C64.3,24 64.3,26.2 62.9,27.6L27.6,62.9C26.2,64.3 24,64.3 22.6,62.9L22.5,62.8C21.2,61.4 21.2,59.2 22.5,57.8Z" style="fill:rgb(128,47,49);stroke:rgb(128,47,49);stroke-width:2.5px;"/>
|
||||
<path d="M27.6,22.5L62.9,57.8C64.3,59.2 64.3,61.4 62.9,62.8L62.8,62.9C61.4,64.3 59.2,64.3 57.8,62.9L22.5,27.6C21.1,26.2 21.1,24 22.5,22.6L22.6,22.5C24,21.2 26.2,21.2 27.6,22.5Z" style="fill:rgb(128,47,49);stroke:rgb(128,47,49);stroke-width:2.5px;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
12
assets/trafficlights/closehovercolored.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(241,0,27);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.3 21.1,81.8 42.7,81.8Z" style="fill:rgb(255,92,96);"/>
|
||||
<g>
|
||||
<path d="M22.5,57.8L57.8,22.5C59.2,21.1 61.4,21.1 62.8,22.5L62.9,22.6C64.3,24 64.3,26.2 62.9,27.6L27.6,62.9C26.2,64.3 24,64.3 22.6,62.9L22.5,62.8C21.2,61.4 21.2,59.2 22.5,57.8Z" style="fill:rgb(128,47,49);stroke:rgb(128,47,49);stroke-width:2.5px;"/>
|
||||
<path d="M27.6,22.5L62.9,57.8C64.3,59.2 64.3,61.4 62.9,62.8L62.8,62.9C61.4,64.3 59.2,64.3 57.8,62.9L22.5,27.6C21.1,26.2 21.1,24 22.5,22.6L22.6,22.5C24,21.2 26.2,21.2 27.6,22.5Z" style="fill:rgb(128,47,49);stroke:rgb(128,47,49);stroke-width:2.5px;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
16
assets/trafficlights/exitfullscreendowncolored.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(66,130,52);"/>
|
||||
<g>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.2 21.1,81.8 42.7,81.8Z" style="fill:rgb(46,164,75);"/>
|
||||
<g transform="matrix(0,-0.842628,0.842628,0,6.811922,78.99493)">
|
||||
<g transform="matrix(-1,0,-0,-1,106.637317,63.746683)">
|
||||
<path d="M28.052,20.855L57.9,20.8C61.5,20.8 64.4,23.7 64.4,27.3L64.444,57.088L28.052,20.855Z" style="fill:rgb(17,49,7);"/>
|
||||
</g>
|
||||
<g transform="matrix(-1,0,-0,-1,63.293317,107.454683)">
|
||||
<path d="M56.994,64.5L27.6,64.5C24,64.5 21.1,61.6 21.1,58L21.1,28.154L56.994,64.5Z" style="fill:rgb(17,49,7);"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
18
assets/trafficlights/exitfullscreenhovercolored.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(0,183,30);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.2 21.1,81.8 42.7,81.8Z" style="fill:rgb(54,198,89);"/>
|
||||
<g transform="matrix(0,-0.842628,0.842628,0,6.811922,78.99493)">
|
||||
<g>
|
||||
<g transform="matrix(-1,0,0,-1,106.637317,63.746683)">
|
||||
<path d="M28.052,20.855L57.9,20.8C61.5,20.8 64.4,23.7 64.4,27.3L64.444,57.088L28.052,20.855Z" style="fill:rgb(1,97,0);"/>
|
||||
</g>
|
||||
<g transform="matrix(-1,0,0,-1,63.293317,107.454683)">
|
||||
<path d="M56.994,64.5L27.6,64.5C24,64.5 21.1,61.6 21.1,58L21.1,28.154L56.994,64.5Z" style="fill:rgb(1,97,0);"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
8
assets/trafficlights/fullscreencolored.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(0,183,30);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.2 21.1,81.8 42.7,81.8Z" style="fill:rgb(54,198,89);"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 804 B |
11
assets/trafficlights/fullscreendowncolored.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(66,130,52);"/>
|
||||
<g>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.2 21.1,81.8 42.7,81.8Z" style="fill:rgb(46,164,75);"/>
|
||||
<g transform="matrix(0,-0.842628,0.842628,0,6.811922,78.99493)">
|
||||
<path d="M28.052,20.855L57.9,20.8C61.5,20.8 64.4,23.7 64.4,27.3L64.444,57.088L28.052,20.855ZM56.994,64.5L27.6,64.5C24,64.5 21.1,61.6 21.1,58L21.1,28.154L56.994,64.5Z" style="fill:rgb(17,49,7);"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
11
assets/trafficlights/fullscreenhovercolored.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(0,183,30);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.2 21.1,81.8 42.7,81.8Z" style="fill:rgb(54,198,89);"/>
|
||||
<g transform="matrix(0,-0.842628,0.842628,0,6.811922,78.99493)">
|
||||
<path d="M28.052,20.855L57.9,20.8C61.5,20.8 64.4,23.7 64.4,27.3L64.444,57.088L28.052,20.855ZM56.994,64.5L27.6,64.5C24,64.5 21.1,61.6 21.1,58L21.1,28.154L56.994,64.5Z" style="fill:rgb(17,49,7);"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
8
assets/trafficlights/minimizecolored.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(239,174,0);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.3 21.1,81.8 42.7,81.8Z" style="fill:rgb(250,200,0);"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 805 B |
9
assets/trafficlights/minimizedowncolored.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(200,146,0);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.3 21.1,81.8 42.7,81.8Z" style="fill:rgb(208,165,5);"/>
|
||||
<path d="M22.154,39.1L63.792,39.1C65.692,39.1 67.292,40.7 67.292,42.6L67.292,42.7C67.292,44.6 65.692,46.2 63.792,46.2L22.154,46.2C20.254,46.2 18.654,44.6 18.654,42.7L18.654,42.6C18.654,40.7 20.154,39.1 22.154,39.1Z" style="fill:rgb(126,100,12);stroke:rgb(126,100,12);stroke-width:3.5px;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
9
assets/trafficlights/minimizehovercolored.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(239,174,0);"/>
|
||||
<path d="M42.7,81.8C64.3,81.8 81.8,64.3 81.8,42.7C81.8,21.1 64.3,3.6 42.7,3.6C21.1,3.6 3.6,21.1 3.6,42.7C3.6,64.3 21.1,81.8 42.7,81.8Z" style="fill:rgb(250,200,0);"/>
|
||||
<path d="M22.154,39.1L63.792,39.1C65.692,39.1 67.292,40.7 67.292,42.6L67.292,42.7C67.292,44.6 65.692,46.2 63.792,46.2L22.154,46.2C20.254,46.2 18.654,44.6 18.654,42.7L18.654,42.6C18.654,40.7 20.154,39.1 22.154,39.1Z" style="fill:rgb(126,100,12);stroke:rgb(126,100,12);stroke-width:3.5px;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
8
assets/trafficlights/nofocus.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g>
|
||||
<path d="M42.7,85.4C66.3,85.4 85.4,66.3 85.4,42.7C85.4,19.1 66.3,0 42.7,0C19.1,0 0,19.1 0,42.7C0,66.3 19.1,85.4 42.7,85.4Z" style="fill:rgb(209,208,210);fill-opacity:0.3;"/>
|
||||
<path d="M42.7,81.7C64.3,81.7 81.8,64.2 81.8,42.6C81.8,21 64.3,3.5 42.7,3.5C21.1,3.5 3.6,21 3.6,42.6C3.6,64.2 21.1,81.7 42.7,81.7Z" style="fill:rgb(199,199,199);fill-opacity:0.3;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 839 B |
@ -106,6 +106,7 @@ static const void *kElectrobunChromeObserverKey = &kElectrobunChromeObserverKey;
|
||||
static bool applyTrafficLightsPosition(NSWindow *window, CGFloat x,
|
||||
CGFloat yFromTop);
|
||||
static void refreshWindowChrome(NSWindow *window);
|
||||
static BOOL isWindowFullScreen(NSWindow *window);
|
||||
|
||||
@implementation ElectrobunWindowChromeObserver
|
||||
|
||||
@ -134,6 +135,10 @@ static void refreshWindowChrome(NSWindow *window);
|
||||
selector:@selector(refreshChrome)
|
||||
name:NSWindowDidBecomeKeyNotification
|
||||
object:window];
|
||||
[center addObserver:self
|
||||
selector:@selector(refreshChrome)
|
||||
name:NSWindowWillEnterFullScreenNotification
|
||||
object:window];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -265,6 +265,9 @@ export function setupMainWindowIPC() {
|
||||
case 'close':
|
||||
win.close()
|
||||
break
|
||||
case 'fullscreen':
|
||||
win.setFullScreen(!win.isFullScreen())
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ const DashboardNavigation = () => {
|
||||
icon: <ProductionIcon />
|
||||
})
|
||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||
const { platform, isElectron, isFullScreen, setSidebarViewMenu } =
|
||||
const { platform, isElectron, setSidebarViewMenu } =
|
||||
useContext(ElectronContext)
|
||||
const { availableUpdate, checkForUpdates } = useAppUpdateContext()
|
||||
const mainMenuItems = useMemo(
|
||||
@ -140,9 +140,7 @@ const DashboardNavigation = () => {
|
||||
setSidebarViewMenu(sections)
|
||||
}, [isElectron, setSidebarViewMenu])
|
||||
|
||||
const showAppLogo =
|
||||
(isElectron && platform == 'darwin' && isFullScreen == true) ||
|
||||
(isElectron && platform != 'darwin')
|
||||
const showAppLogo = isElectron && platform != 'darwin'
|
||||
const isMacOSApp = isElectron && platform == 'darwin'
|
||||
const isOtherApp = isElectron && platform != 'darwin'
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import XMarkIcon from '../../Icons/XMarkIcon'
|
||||
import MinusIcon from '../../Icons/MinusIcon'
|
||||
import ContractIcon from '../../Icons/ContractIcon'
|
||||
import ExpandIcon from '../../Icons/ExpandIcon'
|
||||
import MacOSTrafficLights from './MacOSTrafficLights'
|
||||
|
||||
const DashboardWindowButtons = () => {
|
||||
const { isMaximized, handleWindowControl, platform, isFullScreen } =
|
||||
@ -17,14 +18,21 @@ const DashboardWindowButtons = () => {
|
||||
onClick={() => handleWindowControl('close')}
|
||||
/>
|
||||
)
|
||||
const maximizeButton = (
|
||||
const minimizeButton = (
|
||||
<Button
|
||||
icon={<MinusIcon />}
|
||||
type={'text'}
|
||||
onClick={() => handleWindowControl('minimize')}
|
||||
/>
|
||||
)
|
||||
const minimizeButton = (
|
||||
const fullscreenButton = (
|
||||
<Button
|
||||
icon={isFullScreen ? <ContractIcon /> : <ExpandIcon />}
|
||||
type={'text'}
|
||||
onClick={() => handleWindowControl('fullscreen')}
|
||||
/>
|
||||
)
|
||||
const maximizeButton = (
|
||||
<Button
|
||||
icon={isMaximized ? <ContractIcon /> : <ExpandIcon />}
|
||||
type={'text'}
|
||||
@ -32,29 +40,41 @@ const DashboardWindowButtons = () => {
|
||||
/>
|
||||
)
|
||||
|
||||
return (
|
||||
<Flex align='center'>
|
||||
{platform == 'darwin' ? (
|
||||
isFullScreen == false ? (
|
||||
const customWindowControls = (
|
||||
<div
|
||||
className='electrobun-webkit-app-region-no-drag'
|
||||
style={{ width: '95px', marginRight: '2.5px' }}
|
||||
>
|
||||
<Flex style={{ position: 'relative', zIndex: 9999 }}>
|
||||
{platform == 'darwin' ? (
|
||||
<>
|
||||
<div style={{ width: '82px' }} />
|
||||
<Divider
|
||||
type='vertical'
|
||||
style={{ height: '14px', margin: '3px 6px 0 0' }}
|
||||
/>
|
||||
{closeButton}
|
||||
{minimizeButton}
|
||||
{fullscreenButton}
|
||||
</>
|
||||
) : null
|
||||
) : (
|
||||
<div
|
||||
className='electrobun-webkit-app-region-no-drag'
|
||||
style={{ width: '95px', marginRight: '2.5px' }}
|
||||
>
|
||||
<Flex style={{ position: 'relative', zIndex: 9999 }}>
|
||||
) : (
|
||||
<>
|
||||
{maximizeButton}
|
||||
{minimizeButton}
|
||||
{closeButton}
|
||||
</Flex>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<Flex align='center'>
|
||||
{platform == 'darwin' ? (
|
||||
<>
|
||||
<MacOSTrafficLights />
|
||||
<Divider
|
||||
type='vertical'
|
||||
style={{ height: '14px', margin: '3px 6px 0 0' }}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
customWindowControls
|
||||
)}
|
||||
</Flex>
|
||||
)
|
||||
|
||||
212
src/components/Dashboard/common/MacOSTrafficLights.jsx
Normal file
@ -0,0 +1,212 @@
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Flex } from 'antd'
|
||||
import { ElectronContext } from '../context/ElectronContext'
|
||||
|
||||
import CloseColored from '../../../../assets/trafficlights/closecolored.svg?react'
|
||||
import CloseHoverColored from '../../../../assets/trafficlights/closehovercolored.svg?react'
|
||||
import CloseDownColored from '../../../../assets/trafficlights/closedowncolored.svg?react'
|
||||
import MinimizeColored from '../../../../assets/trafficlights/minimizecolored.svg?react'
|
||||
import MinimizeHoverColored from '../../../../assets/trafficlights/minimizehovercolored.svg?react'
|
||||
import MinimizeDownColored from '../../../../assets/trafficlights/minimizedowncolored.svg?react'
|
||||
import FullscreenColored from '../../../../assets/trafficlights/fullscreencolored.svg?react'
|
||||
import FullscreenHoverColored from '../../../../assets/trafficlights/fullscreenhovercolored.svg?react'
|
||||
import FullscreenDownColored from '../../../../assets/trafficlights/fullscreendowncolored.svg?react'
|
||||
import ExitFullscreenHoverColored from '../../../../assets/trafficlights/exitfullscreenhovercolored.svg?react'
|
||||
import ExitFullscreenDownColored from '../../../../assets/trafficlights/exitfullscreendowncolored.svg?react'
|
||||
import NoFocus from '../../../../assets/trafficlights/nofocus.svg?react'
|
||||
|
||||
const TRAFFIC_LIGHT_SIZE = 12
|
||||
|
||||
const TRAFFIC_LIGHT_BUTTON_STYLE = {
|
||||
width: TRAFFIC_LIGHT_SIZE,
|
||||
height: TRAFFIC_LIGHT_SIZE,
|
||||
padding: 0,
|
||||
border: 'none',
|
||||
background: 'transparent',
|
||||
cursor: 'default',
|
||||
lineHeight: 0,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
|
||||
const TRAFFIC_LIGHT_ICON_STYLE = {
|
||||
width: TRAFFIC_LIGHT_SIZE,
|
||||
height: TRAFFIC_LIGHT_SIZE,
|
||||
display: 'block'
|
||||
}
|
||||
|
||||
function getTrafficLightIcon({ isEnabled, isFocused, isActive, isHovered, icons }) {
|
||||
if (!isEnabled || !isFocused) {
|
||||
return icons.noFocus
|
||||
}
|
||||
if (isActive) {
|
||||
return icons.down
|
||||
}
|
||||
if (isHovered) {
|
||||
return icons.hover
|
||||
}
|
||||
return icons.colored
|
||||
}
|
||||
|
||||
const TrafficLightButton = ({
|
||||
action,
|
||||
icons,
|
||||
isGroupHovered,
|
||||
activeAction,
|
||||
isEnabled,
|
||||
isWindowFocused,
|
||||
onActive,
|
||||
onAction
|
||||
}) => {
|
||||
const Icon = getTrafficLightIcon({
|
||||
isEnabled,
|
||||
isFocused: isWindowFocused,
|
||||
isActive: activeAction === action,
|
||||
isHovered: isGroupHovered,
|
||||
icons
|
||||
})
|
||||
|
||||
const handleMouseDown = (event) => {
|
||||
if (!isEnabled) return
|
||||
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
onActive(action)
|
||||
onAction(action)
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
aria-label={action}
|
||||
aria-disabled={!isEnabled}
|
||||
disabled={!isEnabled}
|
||||
className='electrobun-webkit-app-region-no-drag'
|
||||
style={TRAFFIC_LIGHT_BUTTON_STYLE}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseUp={isEnabled ? () => onActive(null) : undefined}
|
||||
>
|
||||
<Icon style={TRAFFIC_LIGHT_ICON_STYLE} />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
TrafficLightButton.propTypes = {
|
||||
action: PropTypes.string.isRequired,
|
||||
icons: PropTypes.shape({
|
||||
colored: PropTypes.elementType.isRequired,
|
||||
hover: PropTypes.elementType.isRequired,
|
||||
down: PropTypes.elementType.isRequired,
|
||||
noFocus: PropTypes.elementType.isRequired
|
||||
}).isRequired,
|
||||
isGroupHovered: PropTypes.bool.isRequired,
|
||||
activeAction: PropTypes.string,
|
||||
isEnabled: PropTypes.bool.isRequired,
|
||||
isWindowFocused: PropTypes.bool.isRequired,
|
||||
onActive: PropTypes.func.isRequired,
|
||||
onAction: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
const MacOSTrafficLights = () => {
|
||||
const { handleWindowControl, isFullScreen } = useContext(ElectronContext)
|
||||
const [isGroupHovered, setIsGroupHovered] = useState(false)
|
||||
const [activeAction, setActiveAction] = useState(null)
|
||||
const [isWindowFocused, setIsWindowFocused] = useState(
|
||||
() => document.hasFocus?.() ?? true
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const handleFocus = () => setIsWindowFocused(true)
|
||||
const handleBlur = () => setIsWindowFocused(false)
|
||||
|
||||
window.addEventListener('focus', handleFocus)
|
||||
window.addEventListener('blur', handleBlur)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('focus', handleFocus)
|
||||
window.removeEventListener('blur', handleBlur)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const fullscreenIcons = isFullScreen
|
||||
? {
|
||||
colored: FullscreenColored,
|
||||
hover: ExitFullscreenHoverColored,
|
||||
down: ExitFullscreenDownColored,
|
||||
noFocus: NoFocus
|
||||
}
|
||||
: {
|
||||
colored: FullscreenColored,
|
||||
hover: FullscreenHoverColored,
|
||||
down: FullscreenDownColored,
|
||||
noFocus: NoFocus
|
||||
}
|
||||
|
||||
const handleAction = (action) => {
|
||||
handleWindowControl(action)
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex
|
||||
className='electrobun-webkit-app-region-no-drag'
|
||||
style={{
|
||||
width: '56.6px',
|
||||
marginLeft: '12.5px',
|
||||
marginRight: '12.5px',
|
||||
position: 'relative',
|
||||
zIndex: 9999
|
||||
}}
|
||||
gap={8}
|
||||
onMouseEnter={() => setIsGroupHovered(true)}
|
||||
onMouseLeave={() => {
|
||||
setIsGroupHovered(false)
|
||||
setActiveAction(null)
|
||||
}}
|
||||
>
|
||||
<TrafficLightButton
|
||||
action='close'
|
||||
icons={{
|
||||
colored: CloseColored,
|
||||
hover: CloseHoverColored,
|
||||
down: CloseDownColored,
|
||||
noFocus: NoFocus
|
||||
}}
|
||||
isGroupHovered={isGroupHovered}
|
||||
activeAction={activeAction}
|
||||
isEnabled
|
||||
isWindowFocused={isWindowFocused}
|
||||
onActive={setActiveAction}
|
||||
onAction={handleAction}
|
||||
/>
|
||||
<TrafficLightButton
|
||||
action='minimize'
|
||||
icons={{
|
||||
colored: MinimizeColored,
|
||||
hover: MinimizeHoverColored,
|
||||
down: MinimizeDownColored,
|
||||
noFocus: NoFocus
|
||||
}}
|
||||
isGroupHovered={isGroupHovered}
|
||||
activeAction={activeAction}
|
||||
isEnabled={!isFullScreen}
|
||||
isWindowFocused={isWindowFocused}
|
||||
onActive={setActiveAction}
|
||||
onAction={handleAction}
|
||||
/>
|
||||
<TrafficLightButton
|
||||
action='fullscreen'
|
||||
icons={fullscreenIcons}
|
||||
isGroupHovered={isGroupHovered}
|
||||
activeAction={activeAction}
|
||||
isEnabled
|
||||
isWindowFocused={isWindowFocused}
|
||||
onActive={setActiveAction}
|
||||
onAction={handleAction}
|
||||
/>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default MacOSTrafficLights
|
||||
@ -93,6 +93,7 @@ function setupWindowEvents(window) {
|
||||
// Electrobun emits resize/focus, not Electron's maximize/fullscreen events.
|
||||
window.on?.('resize', broadcastWindowState)
|
||||
window.on?.('focus', broadcastWindowState)
|
||||
window.on?.('move', broadcastWindowState)
|
||||
}
|
||||
|
||||
export function setupMainWindowMessaging(window = mainWindow) {
|
||||
@ -229,6 +230,14 @@ export function handleWindowControl(action) {
|
||||
mainWindow.maximize?.()
|
||||
}
|
||||
break
|
||||
case 'fullscreen':
|
||||
if (mainWindow.isFullScreen?.()) {
|
||||
mainWindow.setFullScreen?.(false)
|
||||
} else {
|
||||
mainWindow.setFullScreen?.(true)
|
||||
}
|
||||
setTimeout(broadcastWindowState, 100)
|
||||
break
|
||||
case 'close':
|
||||
mainWindow.close?.()
|
||||
break
|
||||
|
||||