diff --git a/src/App.tsx b/src/App.tsx index add7c08..aadff37 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,13 @@ import { Miscellaneous } from "./engine/config"; export const App = () => { return (
+ +

the abstraction engine

diff --git a/src/css/modal.css b/src/css/modal.css new file mode 100644 index 0000000..bd6f2a3 --- /dev/null +++ b/src/css/modal.css @@ -0,0 +1,67 @@ +/* The Modal (background) */ +.modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + justify-content: center; /* Center horizontally */ + align-items: center; /* Center vertically */ + background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */ + overflow: auto; /* Enable scroll if needed */ + animation: fadeIn 0.25s; /* Fade in the background */ +} + +/* Modal Content */ +.modal-content { + display: flex; + background-color: #282828; /* Gruvbox background */ + color: #ebdbb2; /* Gruvbox foreground */ + margin: auto; + padding: 20px; + border: 1px solid #928374; /* Gruvbox grey */ + width: 40%; /* Adjust as needed */ + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); + animation: scaleUp 0.25s; /* Scale animation */ + border-radius: 8px; /* Rounded corners */ + justify-content: center; /* Center horizontally */ +} + +/* Animations */ +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +@keyframes scaleUp { + from { + transform: scale(0.5); + } + to { + transform: scale(1); + } +} + +@keyframes scaleDown { + from { + transform: scale(1); + } + to { + transform: scale(0.5); + } +} diff --git a/src/css/style.css b/src/css/style.css index 8f72fce..2ff3cb2 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -1,5 +1,6 @@ @import url("./theme.css"); @import url("./tf.css"); +@import url("./modal.css"); @font-face { font-family: "scientifica"; diff --git a/src/engine/TheAbstractionEngine.ts b/src/engine/TheAbstractionEngine.ts index 78d4f88..15ef011 100644 --- a/src/engine/TheAbstractionEngine.ts +++ b/src/engine/TheAbstractionEngine.ts @@ -39,9 +39,9 @@ export class TheAbstractionEngine { const player = new Player(); this.game.addEntity(player); - const box = new FunctionBox({ x: 3, y: 1 }); + const box = new FunctionBox({ x: 3, y: 1 }, "λ x . (x)"); this.game.addEntity(box); - const box2 = new FunctionBox({ x: 4, y: 1 }); + const box2 = new FunctionBox({ x: 4, y: 1 }, "λ x . (x)"); this.game.addEntity(box2); } diff --git a/src/engine/config/constants.ts b/src/engine/config/constants.ts index 5dcd60c..288513a 100644 --- a/src/engine/config/constants.ts +++ b/src/engine/config/constants.ts @@ -54,4 +54,6 @@ export namespace Miscellaneous { export const GRID_CELL_WIDTH = Math.floor(WIDTH / GRID_COLUMNS); export const GRID_CELL_HEIGHT = Math.floor(HEIGHT / GRID_ROWS); + + export const MODAL_ID = "modal"; } diff --git a/src/engine/entities/FunctionBox.ts b/src/engine/entities/FunctionBox.ts index 393514e..57eeedb 100644 --- a/src/engine/entities/FunctionBox.ts +++ b/src/engine/entities/FunctionBox.ts @@ -8,6 +8,7 @@ import { Sprite, } from "../components"; import { Coord2D } from "../interfaces"; +import { openModal, closeModal } from "../utils"; export class FunctionBox extends Entity { private static spriteSpec: SpriteSpec = SPRITE_SPECS.get( @@ -52,15 +53,23 @@ export class FunctionBox extends Entity { this.hooks.set(ComponentNames.Highlight, { add: () => { - this.addComponent(new Interactable(() => this.viewInsides())); + let modalOpen = false; + const interaction = () => { + if (modalOpen) { + modalOpen = false; + closeModal(); + return; + } + modalOpen = true; + openModal(this.code); + }; + + this.addComponent(new Interactable(interaction)); }, remove: () => { + closeModal(); this.removeComponent(ComponentNames.Interactable); }, }); } - - public viewInsides() { - console.log("I am a function box!"); - } } diff --git a/src/engine/systems/Input.ts b/src/engine/systems/Input.ts index df4d651..3da018d 100644 --- a/src/engine/systems/Input.ts +++ b/src/engine/systems/Input.ts @@ -52,6 +52,9 @@ export class Input extends System { } interactable.interact(); + KeyConstants.ActionKeys.get(Action.INTERACT)!.forEach((key) => + this.keyReleased(key), + ); } public handleMovement(entity: Entity) { diff --git a/src/engine/utils/index.ts b/src/engine/utils/index.ts index 439e664..78b600e 100644 --- a/src/engine/utils/index.ts +++ b/src/engine/utils/index.ts @@ -1,3 +1,4 @@ export * from "./clamp"; export * from "./dotProduct"; export * from "./rotateVector"; +export * from "./modal"; diff --git a/src/engine/utils/modal.ts b/src/engine/utils/modal.ts new file mode 100644 index 0000000..e7b36b1 --- /dev/null +++ b/src/engine/utils/modal.ts @@ -0,0 +1,38 @@ +import { Miscellaneous } from "../config"; + +let modalOpen = false; + +export const openModal = (content: string, id = Miscellaneous.MODAL_ID) => { + const modal = document.getElementById(id); + if (modal && !modalOpen) { + modal.style.display = "flex"; + modal.style.animation = "fadeIn 0.25s"; + + modal.innerHTML = ``; + const modalContent = document.querySelector(".modal-content"); + if (modalContent) { + modalContent.style.animation = "scaleUp 0.25s"; + } + + modalOpen = true; + } +}; + +export const closeModal = (id = Miscellaneous.MODAL_ID) => { + const modal = document.getElementById(id); + if (modal && modalOpen) { + modal.style.animation = "fadeOut 0.25s"; + + const modalContent = document.querySelector(".modal-content"); + if (modalContent) { + modalContent.style.animation = "scaleDown 0.25s"; + } + + setTimeout(() => { + modal.innerHTML = ""; + modal.style.display = "none"; + + modalOpen = false; + }, 250); + } +};