-
-
-
{title}
-
-
-
-
-
-
+
+
+
+
{title}
+
+
+
+
+
diff --git a/src/components/windows/WindowView.module.css b/src/components/windows/WindowView.module.css
index 4e65545..cefc332 100644
--- a/src/components/windows/WindowView.module.css
+++ b/src/components/windows/WindowView.module.css
@@ -3,15 +3,6 @@
--header-button-hover-color: rgba(255, 255, 255, 5%);
position: absolute;
- display: flex;
- flex-direction: column;
- min-width: 300px;
- min-height: 150px;
- background-color: var(--background-color-c);
- border-radius: 0.5rem;
- box-shadow: var(--window-box-shadow);
- resize: both;
- overflow: hidden;
}
@keyframes pop-in {
@@ -24,13 +15,64 @@
}
.Window-container.Maximized {
+ width: 100%;
+ height: 100%;
+ transform: none !important;
+}
+
+.Window-container.Maximized .Window-inner {
width: 100%;
height: calc(100% - var(--taskbar-height));
border-radius: 0;
- transform: none !important;
resize: none;
}
+.Window-inner {
+ display: flex;
+ flex-direction: column;
+ min-width: 300px;
+ min-height: 150px;
+ background-color: var(--background-color-c);
+ border-radius: 0.5rem;
+ box-shadow: var(--window-box-shadow);
+ resize: both;
+ overflow: hidden;
+ transform-origin: center center;
+ animation: appear 250ms ease-in-out forwards;
+}
+
+.Window-container.Minimized .Window-inner {
+ animation: disappear 250ms ease-in-out forwards;
+}
+
+@keyframes appear {
+ 0% {
+ opacity: 0;
+ transform: translateY(25vh) scale(0);
+ }
+ 25% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ transform: none;
+ }
+}
+
+@keyframes disappear {
+ 0% {
+ opacity: 1;
+ transform: none;
+ }
+ 75% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 0;
+ transform: translateY(25vh) scale(0);
+ }
+}
+
.Header {
--window-icon-size: 1.5rem;
--window-icon-margin: 0.75rem;
diff --git a/src/components/windows/WindowsView.jsx b/src/components/windows/WindowsView.jsx
index 3acd689..ea2e8e0 100644
--- a/src/components/windows/WindowsView.jsx
+++ b/src/components/windows/WindowsView.jsx
@@ -17,16 +17,22 @@ export const WindowsView = memo(() => {
// TO DO: prevent windows from being rerendered when order is changed
return (
- {sortedWindows.map(({ id, app, size, position, options }, index) =>
+ {sortedWindows.map(({ id, app, size, position, options, minimized }, index) =>
{ windowsManager.focus(id); }}
active={index === 0}
id={id}
- key={id}
app={app}
size={size}
position={position}
options={options}
+ minimized={minimized}
+ toggleMinimized={(event) => {
+ event.preventDefault();
+ event.stopPropagation();
+ windowsManager.setMinimized(id, !minimized);
+ }}
/>
)}
);
diff --git a/src/features/windows/windows.js b/src/features/windows/windows.js
index b90845c..d2f5a28 100644
--- a/src/features/windows/windows.js
+++ b/src/features/windows/windows.js
@@ -43,9 +43,10 @@ export default class WindowsManager {
size,
position,
options,
- lastInteraction: new Date().valueOf()
};
+ this.focus(id);
+
app.isActive = true;
this.updateWindows(this.windows);
@@ -96,9 +97,49 @@ export default class WindowsManager {
return;
}
+ Object.values(this.windows).forEach((window) => {
+ const isFocused = (window.id === windowId);
+ window.isFocused = isFocused;
+
+ if (isFocused) {
+ window.lastInteraction = new Date().valueOf();
+ window.minimized = false;
+ }
+ });
+
+ this.updateWindows(this.windows);
+ }
+
+ /**
+ * @param {string} windowId
+ */
+ isFocused(windowId) {
+ return this.windows[windowId].isFocused;
+ }
+
+ /**
+ * @param {string} windowId
+ * @param {boolean=} minimized
+ */
+ setMinimized(windowId, minimized) {
+ windowId = windowId.toString();
+
+ if (!this.windowIds.includes(windowId)) {
+ console.warn(`Failed to set minimized on window ${windowId}: window not found`);
+ return;
+ }
+
const window = this.windows[windowId];
- window.lastInteraction = new Date().valueOf();
-
+ window.minimized = minimized ?? !window.minimized;
+
+ this.updateWindows(this.windows);
+ }
+
+ minimizeAll() {
+ Object.values(this.windows).forEach((window) => {
+ window.minimized = true;
+ });
+
this.updateWindows(this.windows);
}
diff --git a/src/styles/global.css b/src/styles/global.css
index 25e9890..8b2137a 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -1,52 +1,6 @@
+@import "./global/variables.css";
@import "./global/fonts.css";
-
-:root {
- --pink-a: #ff9ff3;
- --pink-b: #f368e0;
- --yellow-a: #feca57;
- --yellow-b: #ff9f43;
- --red-a: #ff6b6b;
- --red-b: #ee5253;
- --light-blue-a: #48dbfb;
- --light-blue-b: #0abde3;
- --green-a: #1dd1a1;
- --green-b: #10ac84;
- --cyan-a: #00d2d3;
- --cyan-b: #01a3a4;
- --blue-a: #54a0ff;
- --blue-b: #2e86de;
- --purple-a: #5f27cd;
- --purple-b: #341f97;
- --grey-a: #c8d6e5;
- --grey-b: #8395a7;
- --dark-grey-a: hsl(211, 14%, 40%);
- --dark-grey-b: hsl(212, 29%, 19%);
- --dark-grey-c: hsl(212, 29%, 15%);
- --dark-grey-ca: hsl(212, 27%, 12%);
- --dark-grey-d: hsl(212, 14%, 10%);
- --dark-grey-e: hsl(212, 12%, 8%);
-
- --foreground-color-a: #fff;
- --foreground-color-b: var(--grey-a);
- --foreground-color-c: var(--grey-b);
-
- --background-color-a: var(--dark-grey-b);
- --background-color-b: var(--dark-grey-c);
- --background-color-ba: var(--dark-grey-ca);
- --background-color-c: var(--dark-grey-d);
- --background-color-d: var(--dark-grey-e);
-
- --background-color-a-hsl: 212, 29%, 19%;
-
- --scrollbar-color: hsla(211, 29%, 40%, 25%);
-
- --window-shadow-size: 0.3rem;
- --window-shadow-opacity: 35%;
- --window-shadow-spread: 3;
- --window-box-shadow: calc(var(--window-shadow-size) * -1) var(--window-shadow-size)
- calc(var(--window-shadow-size) * var(--window-shadow-spread)) 0px
- rgba(0, 0, 0, var(--window-shadow-opacity));
-}
+@import "./global/scrollbar.css";
html, body, #root {
width: 100%;
@@ -75,7 +29,7 @@ body {
p, a, button, input, h1, h2, h3, h4, h5, h6 {
font-family: var(--body-font-family);
- letter-spacing: 0.01em;
+ letter-spacing: normal;
}
p, a, div, span { font-size: 1em; }
@@ -104,27 +58,4 @@ code {
*::selection {
color: var(--background-color-c);
background-color: var(--grey-b);
-}
-
-*::-webkit-scrollbar {
- width: 1.25rem;
- height: 1.25rem;
-}
-
-*::-webkit-scrollbar-track {
- background: none;
-}
-
-*::-webkit-scrollbar-thumb {
- border-radius: 9999px;
- border: 5px solid transparent;
- background-color: var(--scrollbar-color);
- background-clip: padding-box;
- backdrop-filter: invert(100%);
- transition: 200ms ease-in-out;
- z-index: 1;
-}
-
-*::-webkit-scrollbar-corner {
- background-color: transparent;
}
\ No newline at end of file
diff --git a/src/styles/global/scrollbar.css b/src/styles/global/scrollbar.css
new file mode 100644
index 0000000..a7e7eba
--- /dev/null
+++ b/src/styles/global/scrollbar.css
@@ -0,0 +1,29 @@
+/* Firefox */
+* {
+ scrollbar-color: var(--scrollbar-color) transparent;
+ scrollbar-width: thin;
+}
+
+/* Chrome, Safari */
+*::-webkit-scrollbar {
+ width: 1.25rem;
+ height: 1.25rem;
+}
+
+*::-webkit-scrollbar-track {
+ background: none;
+}
+
+*::-webkit-scrollbar-thumb {
+ border-radius: 9999px;
+ border: 5px solid transparent;
+ background-color: var(--scrollbar-color);
+ background-clip: padding-box;
+ backdrop-filter: invert(100%);
+ transition: 200ms ease-in-out;
+ z-index: 1;
+}
+
+*::-webkit-scrollbar-corner {
+ background-color: transparent;
+}
\ No newline at end of file
diff --git a/src/styles/global/variables.css b/src/styles/global/variables.css
new file mode 100644
index 0000000..9d3975d
--- /dev/null
+++ b/src/styles/global/variables.css
@@ -0,0 +1,47 @@
+:root {
+ --pink-a: #ff9ff3;
+ --pink-b: #f368e0;
+ --yellow-a: #feca57;
+ --yellow-b: #ff9f43;
+ --red-a: #ff6b6b;
+ --red-b: #ee5253;
+ --light-blue-a: #48dbfb;
+ --light-blue-b: #0abde3;
+ --green-a: #1dd1a1;
+ --green-b: #10ac84;
+ --cyan-a: #00d2d3;
+ --cyan-b: #01a3a4;
+ --blue-a: #54a0ff;
+ --blue-b: #2e86de;
+ --purple-a: #5f27cd;
+ --purple-b: #341f97;
+ --grey-a: #c8d6e5;
+ --grey-b: #8395a7;
+ --dark-grey-a: hsl(211, 14%, 40%);
+ --dark-grey-b: hsl(212, 29%, 19%);
+ --dark-grey-c: hsl(212, 29%, 15%);
+ --dark-grey-ca: hsl(212, 27%, 12%);
+ --dark-grey-d: hsl(212, 14%, 10%);
+ --dark-grey-e: hsl(212, 12%, 8%);
+
+ --foreground-color-a: #fff;
+ --foreground-color-b: var(--grey-a);
+ --foreground-color-c: var(--grey-b);
+
+ --background-color-a: var(--dark-grey-b);
+ --background-color-b: var(--dark-grey-c);
+ --background-color-ba: var(--dark-grey-ca);
+ --background-color-c: var(--dark-grey-d);
+ --background-color-d: var(--dark-grey-e);
+
+ --background-color-a-hsl: 212, 29%, 19%;
+
+ --scrollbar-color: hsla(211, 29%, 40%, 25%);
+
+ --window-shadow-size: 0.3rem;
+ --window-shadow-opacity: 35%;
+ --window-shadow-spread: 3;
+ --window-box-shadow: calc(var(--window-shadow-size) * -1) var(--window-shadow-size)
+ calc(var(--window-shadow-size) * var(--window-shadow-spread)) 0px
+ rgba(0, 0, 0, var(--window-shadow-opacity));
+}
\ No newline at end of file
diff --git a/src/styles/utils.module.css b/src/styles/utils.module.css
index 180c836..7f66f88 100644
--- a/src/styles/utils.module.css
+++ b/src/styles/utils.module.css
@@ -1,22 +1,22 @@
.Text-regular {
font-size: 1em;
font-weight: 400;
- letter-spacing: 0.01em;
+ letter-spacing: normal;
}
.Text-light {
color: var(--foreground-color-c);
font-size: 0.875em;
font-weight: 300;
- letter-spacing: 0.025em;
+ letter-spacing: normal;
}
.Text-semibold {
font-weight: 500;
- letter-spacing: 0.025em;
+ letter-spacing: normal;
}
.Text-bold {
font-weight: 600;
- letter-spacing: 0.05em;
+ letter-spacing: normal;
}
\ No newline at end of file