make windows work properly
9
assets/apps.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<svg version="1.1" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1" y="1" width="30" height="30" rx="8" ry="8" fill="#2db0ff"/>
|
||||||
|
<g fill="#ffffff" stroke-width="1.0001">
|
||||||
|
<rect x="5" y="5" width="10" height="10" rx="4" ry="4"/>
|
||||||
|
<path d="m9 17c-2.216 0-4 1.784-4 4v2c0 2.216 1.784 4 4 4h2c2.216 0 4-1.784 4-4v-2c0-2.216-1.784-4-4-4h-2zm0 1h2c1.662 0 3 1.338 3 3v2c0 1.662-1.338 3-3 3h-2c-1.662 0-3-1.338-3-3v-2c0-1.662 1.338-3 3-3z" opacity=".45"/>
|
||||||
|
<path d="m21 17c-2.216 0-4 1.784-4 4v2c0 2.216 1.784 4 4 4h2c2.216 0 4-1.784 4-4v-2c0-2.216-1.784-4-4-4zm0 1h2c1.662 0 3 1.338 3 3v2c0 1.662-1.338 3-3 3h-2c-1.662 0-3-1.338-3-3v-2c0-1.662 1.338-3 3-3z" opacity=".45"/>
|
||||||
|
<path d="m21 5c-2.216 0-4 1.784-4 4v2c0 2.216 1.784 4 4 4h2c2.216 0 4-1.784 4-4v-2c0-2.216-1.784-4-4-4zm0 1h2c1.662 0 3 1.338 3 3v2c0 1.662-1.338 3-3 3h-2c-1.662 0-3-1.338-3-3v-2c0-1.662 1.338-3 3-3z" opacity=".45"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 923 B |
Before Width: | Height: | Size: 798 B |
Before Width: | Height: | Size: 439 B |
BIN
assets/home.png
Before Width: | Height: | Size: 405 B |
1
assets/homebank.svg
Normal file
After Width: | Height: | Size: 7.4 KiB |
1
assets/image.svg
Normal file
After Width: | Height: | Size: 7.4 KiB |
1
assets/trash.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="a" x1="32.432" x2="32.432" y1="4.138" y2="23.904" gradientUnits="userSpaceOnUse"><stop stop-color="#d1d1d1" offset="0"/><stop stop-color="#a6a6a6" offset="1"/></linearGradient></defs><image x="7.5" y="45.241" width="49" height="21" image-rendering="optimizeQuality" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAVCAYAAADvoQY8AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA GXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAVJJREFUWIXdltuOwyAMRAnp//9x YV8gmgxj7GxJW9USwrkAPli+pPQDsn14PUp9hxH87xbQLakBXT1LeTjflXHbROc1llQxK12tGWQG oYzNoPNIYlZiAfAoaQSSIAoCDckw5xQDiUJEAArpEoYh0KBMY59AeIZ7QBbEE0A2eH8CQQgG2GEg zH/jIAKCQKWdVxrMs30fPKI8gQAPglBGr0jTFfbpMB2gpPEM9MgBwbfbQTwPrBJrv9zm2uzB2Dig My2yAvZOABbOiF4SSQxhZQvO43eKl3qHOrLTBurWPQ+s8IyqBZhie3Bjyj1gEMLL7VZL8Kpn1M1j RuJxCuqUztkJPxR411OdCvIrRc4yngG42KEHBi9Yh1oVmyv3nW2HVbGl92eHqdjwKvZVCK9iRxrD kPvVLb+ri3Wbv+iB1r9WLFyBmOnqWcqKlmGV3F1/vlv+ANnpsi80YU39AAAAAElFTkSuQmCC"/><path d="M32 3C19.256 3 8.924 5.583 8.924 8.77l.04.33c.688 3.032 10.737 5.438 23.036 5.438 12.3 0 22.352-2.407 23.036-5.439l.04-.33C55.076 5.583 44.744 3 32 3zM14.539 54.516zm.266.748zm1.024 1.413zm32.39.001zm-31.226.973zm1.469.886zm1.744.784zm25.38-.784zm-1.745.784z" color="#000" fill="url(#a)" opacity=".6"/><path d="m8.924 8.768 5.525 44.978c0 4.16 7.869 7.533 17.575 7.533 9.707 0 17.576-3.372 17.576-7.533l5.476-44.978c-.001 3.186-10.332 5.769-23.076 5.769S8.925 11.954 8.924 8.768zm46.152 0z" color="#000" fill="#f5f5f5" opacity=".915"/></svg>
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/wallpaper3.png
Normal file
After Width: | Height: | Size: 2.3 MiB |
4
assets/web.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="32" height="32" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1" y="1" width="30" height="30" rx="8" ry="8" fill="#4386f5"/>
|
||||||
|
<path d="M8.421 12.259a11.621 11.621 0 0 0 8.515 3.653 11.342 11.342 0 0 0 7.014-2.436l-.502-.988a10.171 10.171 0 0 1-6.512 2.356 10.457 10.457 0 0 1-8.02-3.68zm-.944 5.038c4.588 3.918 11.153 4.65 16.447 1.88l-.026-1.21c-5.145 2.974-11.718 2.233-16.156-1.87Zm4.376 6.062 1.262.291a12.108 12.108 0 0 1-.935-4.465c-.247-4.385 1.641-8.567 5.012-11.33l-1.13-.44a14.7 14.7 0 0 0-4.95 11.788c.018 1.412.274 2.806.741 4.156zm5.815.873.997-.44a13.754 13.754 0 0 1-2.55-7.977c0-2.736.794-5.347 2.285-7.57l-1.04-.371a14.733 14.733 0 0 0-2.312 7.94c0 3.045.917 5.948 2.62 8.418zm5.197-3.282.715-.812a9.652 9.652 0 0 1-4.862-8.276 9.523 9.523 0 0 1 .644-3.591l-1.032-.292a10.542 10.542 0 0 0-.68 3.892 10.716 10.716 0 0 0 5.215 9.079zm-10.694-5.144c.75 0 1.368-.627 1.368-1.385a1.377 1.377 0 1 0-2.753 0c0 .758.617 1.385 1.385 1.385zm6.759.732a1.36 1.36 0 0 0 0-2.717 1.36 1.36 0 0 0-1.368 1.35c0 .758.609 1.367 1.368 1.367zm-2.63 5.1c.76 0 1.368-.609 1.368-1.376a1.37 1.37 0 0 0-1.368-1.377 1.38 1.38 0 0 0-1.385 1.377c0 .767.618 1.376 1.385 1.376zM16 25c4.924 0 9-4.085 9-9 0-4.924-4.085-9-9.008-9C11.077 7 7 11.076 7 16c0 4.915 4.086 9 9 9zm0-1.2c-4.261 0-7.8-3.538-7.8-7.8 0-4.262 3.53-7.8 7.792-7.8 4.261 0 7.808 3.538 7.808 7.8 0 4.262-3.538 7.8-7.8 7.8z" fill="#fff" stroke-width=".75294"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -1,3 +1,7 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@ -9,7 +13,7 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-image: url("./assets/wallpaper2.jpg");
|
background-image: url("./assets/wallpaper3.png");
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
|
@ -9,7 +9,13 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
|
"postcss": "^8.4.38",
|
||||||
|
"tailwindcss": "^3.4.4",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^5.2.0"
|
"vite": "^5.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"date-fns": "^3.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
@ -1,14 +1,29 @@
|
|||||||
|
import Application from "./applications/application";
|
||||||
|
import FileManager from "./applications/fileManager";
|
||||||
|
|
||||||
export default class Applications {
|
export default class Applications {
|
||||||
applications: unknown[];
|
/** currently openedd applications */
|
||||||
|
applications: Application[];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.applications = [];
|
this.applications = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
addApplication(application: unknown) {
|
addApplication(application: Application) {
|
||||||
this.applications.push(application);
|
this.applications.push(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
getApplications() {
|
getApplications() {
|
||||||
return this.applications;
|
return this.applications;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openFileManager(): FileManager {
|
||||||
|
if (this.applications.find(app => app instanceof FileManager)) {
|
||||||
|
console.log("skipping file manager");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const app = new FileManager()
|
||||||
|
this.applications.push(app);
|
||||||
|
return app
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
22
src/os/applications/application.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export default class Application {
|
||||||
|
name: string;
|
||||||
|
constructor(name: string) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescription() {
|
||||||
|
return "This is a base class for all applications";
|
||||||
|
}
|
||||||
|
|
||||||
|
getIcon() {
|
||||||
|
return "💻";
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
console.log(`Running ${this.getName()}`);
|
||||||
|
}
|
||||||
|
}
|
24
src/os/applications/fileManager.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import Application from "./application";
|
||||||
|
import Window from "../../ui/window";
|
||||||
|
|
||||||
|
|
||||||
|
export default class FileManager extends Application {
|
||||||
|
/** the ui element for this application */
|
||||||
|
ui_element: Window;
|
||||||
|
icon: string = "📁";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super("File Manager");
|
||||||
|
this.ui_element = new Window(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescription() {
|
||||||
|
return "This is a file manager";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** returns the ui for this application */
|
||||||
|
run(){
|
||||||
|
const el = this.ui_element.start()
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,6 @@ export default class Cursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start(e: MouseEvent) {
|
start(e: MouseEvent) {
|
||||||
console.log(e);
|
//console.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,4 +23,13 @@ export default class OS {
|
|||||||
console.log("start os");
|
console.log("start os");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open_application(id: string) {
|
||||||
|
console.log("open application", id);
|
||||||
|
if (id == 'file_manager') {
|
||||||
|
this.applications.openFileManager();
|
||||||
|
}
|
||||||
|
this.ui.updateDesktop();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
export default class Component {
|
export default class Component {
|
||||||
element: HTMLDivElement = document.createElement("div");
|
element: HTMLDivElement = document.createElement("div");
|
||||||
|
|
||||||
|
constructor(id: string) {
|
||||||
|
this.element.id = id
|
||||||
|
}
|
||||||
|
|
||||||
addChild(child: HTMLDivElement) {
|
addChild(child: HTMLDivElement) {
|
||||||
this.element.appendChild(child);
|
this.element.appendChild(child);
|
||||||
}
|
}
|
||||||
|
@ -4,51 +4,59 @@ import Window from "./window";
|
|||||||
|
|
||||||
export default class Desktop extends Component {
|
export default class Desktop extends Component {
|
||||||
shortcuts: DesktopShortcut[] = [];
|
shortcuts: DesktopShortcut[] = [];
|
||||||
windows: Window[] = [];
|
shortcuts_container: HTMLDivElement;
|
||||||
|
windows_container: HTMLDivElement;
|
||||||
|
os: OS;
|
||||||
|
|
||||||
constructor() {
|
constructor(os: OS) {
|
||||||
super();
|
super();
|
||||||
|
this.os = os
|
||||||
|
this.element.classList.add("grid","grid-flow-col", "grid-cols-1");
|
||||||
|
this.element.classList.add("w-full", "h-full", "gap-8", "p-2");
|
||||||
this.element.id = "desktop";
|
this.element.id = "desktop";
|
||||||
this.element.style.height = "100%";
|
|
||||||
this.element.style.width = "100%";
|
|
||||||
this.element.style.display = "grid";
|
|
||||||
this.element.style.gap = "10px";
|
|
||||||
this.element.style.padding = "10px";
|
|
||||||
|
|
||||||
this.element.style.display = "grid";
|
|
||||||
this.element.style.gridAutoFlow = "column";
|
|
||||||
|
|
||||||
this.element.style.gridTemplateColumns =
|
this.element.style.gridTemplateColumns =
|
||||||
"repeat(auto-fill, minmax(60px, 1fr))";
|
"repeat(auto-fill, minmax(60px, 1fr))";
|
||||||
this.element.style.gridTemplateRows =
|
this.element.style.gridTemplateRows =
|
||||||
"repeat(auto-fill, minmax(60px, 1fr))";
|
"repeat(auto-fill, minmax(60px, 1fr))";
|
||||||
|
|
||||||
|
this.shortcuts_container = new Component('shortcuts_container');
|
||||||
|
this.windows_container = new Component('windows_container');
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDesktop() {
|
updateDesktop() {
|
||||||
this.element.replaceChildren(...this.shortcuts.map((e) => e.element));
|
const windows = this.os.applications.getApplications()
|
||||||
|
console.log(windows)
|
||||||
|
this.shortcuts_container.element.replaceChildren(...this.shortcuts.map(s => s.start()));
|
||||||
|
this.windows_container.element.replaceChildren(...windows.map(w => w.ui_element.start()));
|
||||||
}
|
}
|
||||||
|
|
||||||
addApplicationShortcut(shortcut: DesktopShortcut) {
|
addApplicationShortcut(shortcut: DesktopShortcut) {
|
||||||
this.shortcuts.push(shortcut);
|
this.shortcuts.push(shortcut);
|
||||||
this.updateDesktop();
|
this.updateDesktop()
|
||||||
}
|
}
|
||||||
|
|
||||||
addOpenedWindow(w: Window) {
|
addOpenedWindow(w: Window) {
|
||||||
this.windows.push(w);
|
this.windows.push(w);
|
||||||
this.element.appendChild(w.start());
|
this.updateDesktop()
|
||||||
}
|
}
|
||||||
|
|
||||||
initDesktopShortcuts() {
|
initDesktopShortcuts() {
|
||||||
this.addApplicationShortcut(
|
this.addApplicationShortcut(
|
||||||
new DesktopShortcut("../../assets/home.png", "Home"),
|
new DesktopShortcut("../../assets/homebank.svg", "Home", this.os, 'file_manager'),
|
||||||
);
|
);
|
||||||
this.addApplicationShortcut(
|
this.addApplicationShortcut(
|
||||||
new DesktopShortcut("../../assets/file-image.png", "img_12131995.png"),
|
new DesktopShortcut("../../assets/image.svg", "fun.png", this.os, 'image_viewer'),
|
||||||
|
);
|
||||||
|
this.addApplicationShortcut(
|
||||||
|
new DesktopShortcut("../../assets/trash.svg", "trash", this.os, 'file_manager'),
|
||||||
);
|
);
|
||||||
this.addOpenedWindow(new Window());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
|
this.addChild(this.shortcuts_container.element)
|
||||||
|
this.addChild(this.windows_container.element)
|
||||||
this.initDesktopShortcuts();
|
this.initDesktopShortcuts();
|
||||||
return this.element;
|
return this.element;
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,48 @@
|
|||||||
|
import OS from "../os";
|
||||||
import Component from "./component";
|
import Component from "./component";
|
||||||
|
|
||||||
export default class DesktopShortcut extends Component {
|
export default class DesktopShortcut extends Component {
|
||||||
icon: string;
|
icon: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
os: OS
|
||||||
|
|
||||||
constructor(icon: string, title: string) {
|
constructor(icon: string, title: string, os: OS, id: string) {
|
||||||
super();
|
super();
|
||||||
this.icon = icon;
|
this.icon = icon;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
this.id = id;
|
||||||
|
this.os = os;
|
||||||
|
|
||||||
this.element.style.borderRadius = "10px";
|
this.element.classList.add("text-white", "cursor-pointer", "flex", "flex-col", "justify-center", "items-center", "p-2");
|
||||||
this.element.style.cursor = "pointer";
|
|
||||||
this.element.style.color = "white";
|
|
||||||
this.element.style.justifyContent = "center";
|
|
||||||
this.element.style.display = "flex";
|
|
||||||
this.element.style.flexDirection = "column";
|
|
||||||
this.element.style.alignItems = "center";
|
|
||||||
this.element.style.padding = "6px";
|
|
||||||
|
|
||||||
this.element.addEventListener("mouseover", () => {
|
|
||||||
this.element.style.border = "1px solid #0000005f";
|
|
||||||
});
|
|
||||||
|
|
||||||
this.element.addEventListener("mouseout", () => {
|
|
||||||
this.element.style.border = "1px solid #00000000";
|
|
||||||
});
|
|
||||||
|
|
||||||
const _icon = document.createElement("img");
|
const _icon = document.createElement("img");
|
||||||
const _title = document.createElement("p");
|
const _title = document.createElement("p");
|
||||||
|
|
||||||
_icon.src = this.icon;
|
_icon.src = this.icon;
|
||||||
_icon.style.width = "30px";
|
_icon.style.width = "60px";
|
||||||
|
|
||||||
_title.textContent = this.title;
|
_title.textContent = this.title;
|
||||||
_title.style.margin = "0";
|
_title.classList.add( "font-bold", "text-md", "mt-1", "break-normal");
|
||||||
_title.style.fontSize = "12px";
|
|
||||||
_title.style.marginTop = "4px";
|
|
||||||
_title.style.wordWrap = "anywhere";
|
|
||||||
|
|
||||||
this.addChild(_icon);
|
this.addChild(_icon);
|
||||||
this.addChild(_title);
|
this.addChild(_title);
|
||||||
|
|
||||||
|
this.element.addEventListener("click", () => this.open_application());
|
||||||
|
}
|
||||||
|
|
||||||
|
getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitle() {
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIcon() {
|
||||||
|
return this.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
open_application() {
|
||||||
|
this.os.open_application(this.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ export default class UI extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
console.log("start ui");
|
|
||||||
this.element.id = "ui";
|
this.element.id = "ui";
|
||||||
document.body.appendChild(this.element);
|
document.body.appendChild(this.element);
|
||||||
|
|
||||||
@ -30,7 +29,7 @@ export default class UI extends Component {
|
|||||||
this.addChild(this.topbar.start());
|
this.addChild(this.topbar.start());
|
||||||
|
|
||||||
this.navbar = new NavBar();
|
this.navbar = new NavBar();
|
||||||
this.desktop = new Desktop();
|
this.desktop = new Desktop(this.os);
|
||||||
|
|
||||||
const desktop_container = document.createElement("div");
|
const desktop_container = document.createElement("div");
|
||||||
desktop_container.id = "desktop_container";
|
desktop_container.id = "desktop_container";
|
||||||
@ -43,4 +42,8 @@ export default class UI extends Component {
|
|||||||
|
|
||||||
return this.element;
|
return this.element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateDesktop() {
|
||||||
|
this.desktop.updateDesktop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,47 @@
|
|||||||
import Component from "./component"
|
import Component from "./component"
|
||||||
|
|
||||||
export default class NavBar extends Component {
|
export default class NavBar extends Component {
|
||||||
|
applications: HTMLDivElement[] = [];
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this.element.style.display = 'flex'
|
this.element.classList.add('flex', 'flex-column', 'w-20', 'h-full', 'bg-[#000a]', 'justify-center','py-2', 'z-[12]')
|
||||||
this.element.style.flexDirection = 'column'
|
}
|
||||||
this.element.style.backgroundColor = '#000000af';
|
|
||||||
this.element.style.backdropFilter = 'blur(10px)';
|
|
||||||
this.element.style.height = '100%'
|
|
||||||
this.element.style.width = '60px'
|
|
||||||
|
|
||||||
|
init(){
|
||||||
|
this.applications.push(new Application("../../assets/apps.svg").start())
|
||||||
|
this.applications.forEach(app => this.element.appendChild(app))
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
this.element.id = 'navbar'
|
this.element.id = 'navbar'
|
||||||
|
this.init()
|
||||||
return this.element
|
return this.element
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Application extends Component {
|
||||||
|
icon: string;
|
||||||
|
constructor(icon: string) {
|
||||||
|
super();
|
||||||
|
this.icon = icon;
|
||||||
|
|
||||||
|
this.element.classList.add('cursor-pointer')
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_click_handler(){
|
||||||
|
this.element.addEventListener('click', () => {
|
||||||
|
console.log('clicked')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.setup_click_handler()
|
||||||
|
this.element.innerHTML = `
|
||||||
|
<img src="${this.icon}" style="width: 60px;">
|
||||||
|
`
|
||||||
|
return this.element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,14 +1,25 @@
|
|||||||
import Component from "./component"
|
import Component from "./component"
|
||||||
|
import { format } from "date-fns"
|
||||||
|
|
||||||
export default class TopBar extends Component {
|
export default class TopBar extends Component {
|
||||||
|
time: HTMLDivElement;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.element.style.height = "20px"
|
this.element.classList.add("w-full", "bg-black", "py-1", 'flex', 'justify-center', 'z-[11]', 'relative')
|
||||||
this.element.style.width = "100%"
|
}
|
||||||
this.element.style.backgroundColor = "black"
|
|
||||||
|
add_time(){
|
||||||
|
const date = new Date()
|
||||||
|
this.time = new Component()
|
||||||
|
this.time.element.classList.add( "text-white", "text-center", "cursor-default")
|
||||||
|
this.time.element.innerText = format(date, "MMM dd H:mm aa")
|
||||||
|
|
||||||
|
this.element.appendChild(this.time.start())
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
|
this.add_time()
|
||||||
this.element.id = 'topbar'
|
this.element.id = 'topbar'
|
||||||
return this.element
|
return this.element
|
||||||
}
|
}
|
||||||
|
131
src/ui/window.ts
@ -1,18 +1,135 @@
|
|||||||
|
import Component from "./component";
|
||||||
|
|
||||||
export default class Window {
|
export default class Window {
|
||||||
element: HTMLDivElement = document.createElement("div");
|
element: HTMLDivElement = document.createElement("div");
|
||||||
initial_size = { w: 500, h: 500 } as const;
|
initial_size = { w: 500, h: 500 } as const;
|
||||||
|
dragging = false;
|
||||||
|
header: HTMLDivElement;
|
||||||
|
/** the os application that this window is for */
|
||||||
|
application: Application;
|
||||||
|
|
||||||
constructor() {
|
constructor(application: Application) {
|
||||||
this.element.style.backgroundColor = "#ccc";
|
this.element.classList.add("bg-[#ccc]", "absolute", "rounded-lg", "shadow-xl");
|
||||||
this.element.style.width = `${this.initial_size.w}px`;
|
this.element.style.width = `${this.initial_size.w}px`;
|
||||||
this.element.style.height = `${this.initial_size.h}px`;
|
this.element.style.height = `${this.initial_size.h}px`;
|
||||||
this.element.style.position = "absolute";
|
this.application = application;
|
||||||
this.element.style.zIndex = "10";
|
|
||||||
this.element.style.borderRadius = "10px";
|
this._add_header("Hello World");
|
||||||
this.element.style.boxShadow =
|
this._add_content("This is a test");
|
||||||
"0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)";
|
this._add_resize_handles();
|
||||||
|
this._handle_drag()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _add_header(title: string): HTMLDivElement {
|
||||||
|
this.header = new Component()
|
||||||
|
this.header.element.id = "header";
|
||||||
|
this.header.element.classList.add(
|
||||||
|
"bg-[#333]", "p-2", "text-sm", "text-[#eee]", "rounded-t", "text-center", "cursor-move"
|
||||||
|
);
|
||||||
|
this.header.element.innerText = title;
|
||||||
|
this.element.appendChild(this.header.start());
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handle_drag(e: MouseEvent): void {
|
||||||
|
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
||||||
|
const dragMouseDown = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// get the mouse cursor position at startup:
|
||||||
|
pos3 = e.clientX;
|
||||||
|
pos4 = e.clientY;
|
||||||
|
document.onmouseup = closeDragElement;
|
||||||
|
// call a function whenever the cursor moves:
|
||||||
|
document.onmousemove = elementDrag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.header) {
|
||||||
|
// if present, the header is where you move the DIV from:
|
||||||
|
this.header.element.onmousedown = dragMouseDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementDrag = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// calculate the new cursor position:
|
||||||
|
pos1 = pos3 - e.clientX;
|
||||||
|
pos2 = pos4 - e.clientY;
|
||||||
|
pos3 = e.clientX;
|
||||||
|
pos4 = e.clientY;
|
||||||
|
// set the element's new position:
|
||||||
|
this.element.style.top = (this.element.offsetTop - pos2) + "px";
|
||||||
|
this.element.style.left = (this.element.offsetLeft - pos1) + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeDragElement = () =>{
|
||||||
|
// stop moving when mouse button is released:
|
||||||
|
document.onmouseup = null;
|
||||||
|
document.onmousemove = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _add_content(content: string): HTMLDivElement {
|
||||||
|
const content_element = document.createElement("div");
|
||||||
|
content_element.classList.add("bg-[#eee]", "p-2", "text-sm", "text-[#333]");
|
||||||
|
content_element.innerText = content;
|
||||||
|
this.element.appendChild(content_element);
|
||||||
|
return content_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _add_resize_handles(): void{
|
||||||
|
const color_classes = ["hover:bg-[#0af]", "transition-colors", "duration-500", "rounded-lg"]
|
||||||
|
// --- resize handle left ---
|
||||||
|
const resize_handle_left = document.createElement("div");
|
||||||
|
resize_handle_left.classList.add(
|
||||||
|
"absolute", `w-1`, "h-full", "cursor-w-resize", "top-0", "left-0",
|
||||||
|
...color_classes
|
||||||
|
);
|
||||||
|
resize_handle_left.addEventListener("mousedown", (e) => {
|
||||||
|
this._resize_start(e, 'l');
|
||||||
|
});
|
||||||
|
this.element.appendChild(resize_handle_left);
|
||||||
|
|
||||||
|
// --- resize handle right ---
|
||||||
|
const resize_handle_right = document.createElement("div");
|
||||||
|
resize_handle_right.classList.add(
|
||||||
|
"absolute", `w-1`, "h-full", "cursor-e-resize", "top-0", "right-0",
|
||||||
|
...color_classes
|
||||||
|
);
|
||||||
|
resize_handle_right.addEventListener("mousedown", (e) => {
|
||||||
|
this._resize_start(e, 'r');
|
||||||
|
});
|
||||||
|
this.element.appendChild(resize_handle_right);
|
||||||
|
|
||||||
|
// --- resize handle bottom ---
|
||||||
|
const resize_handle_bottom = document.createElement("div");
|
||||||
|
resize_handle_bottom.classList.add(
|
||||||
|
"absolute", `w-full`, `h-1`, "cursor-s-resize", "bottom-0", "left-0",
|
||||||
|
...color_classes
|
||||||
|
);
|
||||||
|
resize_handle_bottom.addEventListener("mousedown", (e) => {
|
||||||
|
this._resize_start(e, 'b');
|
||||||
|
});
|
||||||
|
this.element.appendChild(resize_handle_bottom);
|
||||||
|
|
||||||
|
// --- resize handle top ---
|
||||||
|
const resize_handle_top = document.createElement("div");
|
||||||
|
resize_handle_top.classList.add(
|
||||||
|
"absolute", `w-full`, `h-1`, "cursor-n-resize", "top-0", "left-0",
|
||||||
|
...color_classes
|
||||||
|
);
|
||||||
|
resize_handle_top.addEventListener("mousedown", (e) => {
|
||||||
|
this._resize_start(e, 't');
|
||||||
|
});
|
||||||
|
this.element.appendChild(resize_handle_top);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private _resize_start(e: MouseEvent, dir: 'l' | 'r' | 't' | 'b') {
|
||||||
|
// TODO finish
|
||||||
|
console.log({e, dir})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
start(): HTMLDivElement {
|
start(): HTMLDivElement {
|
||||||
return this.element;
|
return this.element;
|
||||||
}
|
}
|
||||||
|
8
tailwind.config.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|