index.astro 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. ---
  2. import Layout from "../layouts/Layout.astro";
  3. import Taskbar from "../components/taskbar.astro";
  4. import App from "../components/app.astro";
  5. import Aboutme from "../components/aboutme.astro";
  6. import Redirect from "../components/redirect.astro";
  7. import Contact from "../components/contact.astro";
  8. import Pgp from "../components/pgp.astro";
  9. import Projects from "../components/projects.astro";
  10. import Duolingo from "../components/duolingo.astro";
  11. import GitHubGraph from "../components/githubgraph.astro";
  12. import NowPlaying from "../components/nowplaying.astro";
  13. import Ram from "../components/ram.astro";
  14. // Projects
  15. import Summize from "../components/projects/summize.astro";
  16. import Notion from "../components/projects/notion.astro";
  17. // import Imdb from "../components/projects/imdb.astro";
  18. import "../styles/global.css";
  19. import me from "../assets/apps/me.png";
  20. import github from "../assets/apps/github.png";
  21. import pastwork from "../assets/apps/pastWork.png";
  22. import projects from "../assets/apps/projects.png";
  23. import blog from "../assets/apps/blog.png";
  24. import contact from "../assets/apps/contact.png";
  25. import pgp from "../assets/apps/pgp.png";
  26. import Glance from "../components/projects/glance.astro";
  27. import ramIcon from "../assets/apps/blog.png";
  28. function dragElement(elmnt) {
  29. var pos1 = 0,
  30. pos2 = 0,
  31. pos3 = 0,
  32. pos4 = 0;
  33. if (document.getElementById(elmnt.id + "header")) {
  34. document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
  35. document.getElementById(elmnt.id + "header").ontouchstart = dragMouseDown;
  36. } else {
  37. elmnt.onmousedown = dragMouseDown;
  38. elmnt.ontouchstart = dragMouseDown;
  39. }
  40. function dragMouseDown(e) {
  41. // e.preventDefault();
  42. raiseUpSpec(elmnt.id);
  43. if (e.type == "touchstart") {
  44. pos3 = e.touches[0].clientX;
  45. pos4 = e.touches[0].clientY;
  46. } else {
  47. pos3 = e.clientX;
  48. pos4 = e.clientY;
  49. }
  50. document.onmouseup = closeDragElement;
  51. document.ontouchend = closeDragElement;
  52. document.onmousemove = elementDrag;
  53. document.ontouchmove = elementDrag;
  54. }
  55. function elementDrag(e) {
  56. // e.preventDefault();
  57. if (e.type == "touchmove") {
  58. pos1 = pos3 - e.touches[0].clientX;
  59. pos2 = pos4 - e.touches[0].clientY;
  60. pos3 = e.touches[0].clientX;
  61. pos4 = e.touches[0].clientY;
  62. } else {
  63. pos1 = pos3 - e.clientX;
  64. pos2 = pos4 - e.clientY;
  65. pos3 = e.clientX;
  66. pos4 = e.clientY;
  67. }
  68. elmnt.style.top = elmnt.offsetTop - pos2 + "px";
  69. elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
  70. }
  71. function closeDragElement() {
  72. document.onmouseup = null;
  73. document.ontouchend = null;
  74. document.onmousemove = null;
  75. document.ontouchmove = null;
  76. }
  77. }
  78. /** Raise up window with given ID */
  79. function raiseUpSpec(id: string) {
  80. console.log("raising ", id);
  81. let els = document.getElementsByClassName("window");
  82. let elArray = Array.from(els as HTMLCollectionOf<HTMLElement>);
  83. // find the highest z-index
  84. let highestIndex = 0;
  85. for (let element in elArray) {
  86. let zindex = parseInt(elArray[element].style.zIndex);
  87. if (zindex > highestIndex) {
  88. highestIndex = zindex;
  89. }
  90. }
  91. // set the highest z-index plus one
  92. document.getElementById(id).style.zIndex = (highestIndex + 1).toString();
  93. }
  94. function updateRedirectMessage() {
  95. const redirectElement = document.getElementById("Redirect");
  96. const redirectUrl = redirectElement.dataset.redirecturl; // Access the data attribute
  97. const messageElement = redirectElement.querySelector("h2");
  98. messageElement.innerHTML = `You are about to be redirected to <a class="redirUrl" style=" cursor: pointer;
  99. color: blue;
  100. text-decoration: underline; " href="${redirectUrl}"">${redirectUrl.replace("https://", "")}</a>`;
  101. const buttonElement = redirectElement.querySelector("#okButton");
  102. // open redirect url
  103. buttonElement.setAttribute(
  104. "onclick",
  105. `window.location.href = "${redirectUrl}"`
  106. );
  107. }
  108. let apps: app[] = [
  109. {
  110. name: "About Me",
  111. logo: me.src,
  112. onclick: () => {
  113. raiseUpSpec("About Me");
  114. document.getElementById("About Me").style.display = "block";
  115. },
  116. row: 1,
  117. },
  118. // {
  119. // name: "Blog",
  120. // logo: blog.src,
  121. // onclick: () => {
  122. // raiseUpSpec("Redirect");
  123. // document.getElementById("Redirect").style.display = "block";
  124. // document.getElementById("Redirect").dataset.redirecturl =
  125. // "https://blog.simo.ng/";
  126. // updateRedirectMessage();
  127. // },
  128. // row: 1,
  129. // },
  130. {
  131. name: "Projects",
  132. logo: projects.src,
  133. onclick: () => {
  134. raiseUpSpec("Projects ");
  135. document.getElementById("Projects ").style.display = "block";
  136. },
  137. row: 1,
  138. },
  139. // {
  140. // name: "Past Work",
  141. // logo: pastwork.src,
  142. // row: 1,
  143. // },
  144. {
  145. name: "Git",
  146. logo: github.src,
  147. onclick: () => {
  148. // ignore
  149. raiseUpSpec("Redirect");
  150. document.getElementById("Redirect").style.display = "block";
  151. document.getElementById("Redirect").dataset.redirecturl =
  152. "https://git.simo.ng/simo";
  153. updateRedirectMessage();
  154. },
  155. row: 2,
  156. },
  157. {
  158. name: "RAM",
  159. logo: ramIcon.src,
  160. onclick: () => {
  161. raiseUpSpec("ram");
  162. document.getElementById("ram").style.display = "block";
  163. },
  164. row: 2,
  165. },
  166. {
  167. name: "Contact",
  168. logo: contact.src,
  169. row: 2,
  170. onclick: () => {
  171. raiseUpSpec("contact");
  172. document.getElementById("contact").style.display = "block";
  173. },
  174. },
  175. {
  176. name: "PGP Key",
  177. logo: pgp.src,
  178. row: 1,
  179. onclick: () => {
  180. raiseUpSpec("pgp");
  181. document.getElementById("pgp").classList.add("fullscreen");
  182. document.getElementById("pgp").style.display = "block";
  183. },
  184. },
  185. ];
  186. let projectsArr: project[] = [
  187. {
  188. title: "Glance",
  189. id: "glance",
  190. },
  191. {
  192. title: "Summize",
  193. id: "summize",
  194. },
  195. {
  196. title: "Notion2Canvas",
  197. id: "notion",
  198. },
  199. ];
  200. const row1Items = apps.filter((item) => item.row === 1);
  201. const row2Items = apps.filter((item) => item.row === 2);
  202. let clientFunctions: Function[] | String[] = [
  203. raiseUpSpec,
  204. updateRedirectMessage,
  205. dragElement,
  206. updateRedirectMessage,
  207. ];
  208. clientFunctions = clientFunctions.map((item) => String(item));
  209. apps = apps.map((item) => {
  210. item.onclick = String(item.onclick);
  211. return item;
  212. });
  213. ---
  214. <Layout title="Simo">
  215. <div style="width: 100%; height: calc(100vh - 3.5rem); ">
  216. <Pgp />
  217. <div style="display: flex;">
  218. <div
  219. style="height: 20rem; display: flex; flex-direction: column; align-items: flex-start;"
  220. >
  221. {row1Items.map((item) => <App {item} />)}
  222. </div>
  223. <div
  224. style="height: 20rem; display: flex; flex-direction: column; align-items: flex-start;"
  225. >
  226. {row2Items.map((item) => <App {item} />)}
  227. </div>
  228. </div>
  229. <Aboutme />
  230. <Redirect />
  231. <Contact />
  232. <iframe
  233. id="SimoSearch"
  234. title="SimoSearch"
  235. src="https://search.simo.ng/#embed"
  236. loading="lazy"
  237. referrerpolicy="no-referrer"
  238. allowfullscreen
  239. style="
  240. display: none;
  241. position: absolute;
  242. left: 62%;
  243. top: 10%;
  244. border: 0;
  245. outline: 0;
  246. background: transparent;
  247. "
  248. ></iframe>
  249. <Ram />
  250. <NowPlaying />
  251. <Projects projects={projectsArr} />
  252. <Summize />
  253. <Notion />
  254. <Glance />
  255. <Duolingo />
  256. <GitHubGraph />
  257. </div>
  258. <Taskbar />
  259. </Layout>
  260. <script define:vars={{ apps, projectsArr, clientFunctions }}>
  261. let dino = `
  262. ██████████████
  263. ████░░████████████
  264. ██████████████████
  265. ██████████████████
  266. ██████████████████
  267. ████████
  268. ██████████████░░
  269. ██████
  270. ██ ██████████
  271. ██▒▒ ▒▒▒▒██████████▒▒▒▒
  272. ████▓▓ ██████████████ ▒▒
  273. ██████▒▒▒▒████████████████
  274. ██████████████████████████
  275. ██████████████████████
  276. ██████████████████
  277. ▒▒██████████████
  278. ▒▒██████▒▒██▓▓
  279. ████ ▓▓
  280. ██▒▒ ▓▓
  281. ██ ██
  282. `;
  283. console.log(dino);
  284. for (func in clientFunctions) {
  285. eval(clientFunctions[func]);
  286. }
  287. Array.from(document.getElementsByClassName("project")).forEach((project) => {
  288. // console.log(projectsArr[0].id + "item");
  289. let id = projectsArr.find((i) => i.id + "item" == project.id).id;
  290. // console.log(id);
  291. if (id == "pgpcord") {
  292. project.onclick = () => {
  293. setTimeout(() => {
  294. raiseUpSpec("redirect");
  295. document.getElementById("redirect").style.display = "block";
  296. document.getElementById("redirect").dataset.redirecturl =
  297. "https://blog.simo.ng/articles/WIP/pgpcord";
  298. updateRedirectMessage();
  299. }, 1);
  300. };
  301. return;
  302. }
  303. project.onclick = () => {
  304. setTimeout(() => {
  305. console.log(id)
  306. document.getElementsByClassName(id)[0].style.display = "block";
  307. raiseUpSpec(document.getElementsByClassName(id)[0].id);
  308. }, 1);
  309. };
  310. });
  311. Array.from(document.getElementsByClassName("window")).forEach((window) => {
  312. dragElement(window);
  313. window.querySelectorAll('.title-bar-controls button').forEach((btn) => {
  314. btn.addEventListener('mousedown', (e) => e.stopPropagation());
  315. btn.addEventListener('touchstart', (e) => e.stopPropagation());
  316. });
  317. window.addEventListener("click", () => {
  318. raiseUpSpec(window.id);
  319. });
  320. Array.from(document.querySelectorAll(".projectwindow a")).forEach(
  321. (link) => {
  322. link.addEventListener("click", (e) => {
  323. document.getElementById("redirect").style.display = "block";
  324. document.getElementById("redirect").dataset.redirecturl = link.href;
  325. updateRedirectMessage();
  326. e.preventDefault();
  327. setTimeout(() => {
  328. raiseUpSpec("redirect");
  329. }, 1);
  330. return false;
  331. });
  332. }
  333. );
  334. Array.from(window.getElementsByClassName("close")).forEach((button, index) => {
  335. if (index === 0) {
  336. button.addEventListener("click", () => {
  337. minimizeWindow(window.id);
  338. });
  339. } else {
  340. button.addEventListener("click", () => {
  341. window.classList.add("closed");
  342. removeFromTaskbar(window.id);
  343. const onEnd = () => {
  344. window.classList.remove("closed");
  345. window.style.display = "none";
  346. };
  347. window.addEventListener('animationend', onEnd, { once: true });
  348. setTimeout(() => {
  349. if (window.style.display !== 'none') {
  350. window.classList.remove('closed');
  351. window.style.display = 'none';
  352. }
  353. }, 250);
  354. });
  355. }
  356. });
  357. });
  358. apps.forEach((app) => {
  359. let itemName = app.name.replace(" ", "");
  360. // console.log(itemName)
  361. if (app.onclick == "undefined") {
  362. return;
  363. }
  364. document.getElementById(itemName).addEventListener("click", () => {
  365. const appFunc = eval(app.onclick);
  366. appFunc();
  367. });
  368. });
  369. function minimizeWindow(windowId) {
  370. const window = document.getElementById(windowId);
  371. addToTaskbar(windowId);
  372. const windowRect = window.getBoundingClientRect();
  373. const taskbarButton = document.getElementById(`taskbar-${windowId}`);
  374. const buttonRect = taskbarButton.getBoundingClientRect();
  375. const translateX = buttonRect.left - windowRect.left;
  376. const translateY = buttonRect.top - windowRect.top;
  377. window.style.transition = "all 0.3s ease-out";
  378. window.style.transform = `translate(${translateX}px, ${translateY}px) scale(0.1)`;
  379. window.style.opacity = "0";
  380. setTimeout(() => {
  381. window.style.display = "none";
  382. window.style.transition = "";
  383. window.style.transform = "";
  384. window.style.opacity = "";
  385. }, 300);
  386. }
  387. function restoreWindow(windowId) {
  388. const window = document.getElementById(windowId);
  389. const taskbarButton = document.getElementById(`taskbar-${windowId}`);
  390. const buttonRect = taskbarButton.getBoundingClientRect();
  391. const windowRect = window.getBoundingClientRect();
  392. const translateX = buttonRect.left - windowRect.left;
  393. const translateY = buttonRect.top - windowRect.top;
  394. window.style.transform = `translate(${translateX}px, ${translateY}px) scale(0.1)`;
  395. window.style.opacity = "0";
  396. window.style.display = "block";
  397. removeFromTaskbar(windowId);
  398. raiseUpSpec(windowId);
  399. requestAnimationFrame(() => {
  400. window.style.transition = "all 0.3s ease-out";
  401. window.style.transform = "translate(0, 0) scale(1)";
  402. window.style.opacity = "1";
  403. setTimeout(() => {
  404. window.style.transition = "";
  405. window.style.transform = "";
  406. window.style.opacity = "";
  407. }, 300);
  408. });
  409. }
  410. function addToTaskbar(windowId) {
  411. const taskbarWindows = document.getElementById("taskbar-windows");
  412. if (document.getElementById(`taskbar-${windowId}`)) {
  413. return;
  414. }
  415. const window = document.getElementById(windowId);
  416. const titleBar = window.querySelector(".title-bar-text");
  417. const title = titleBar ? titleBar.textContent : windowId;
  418. const icon = "";
  419. const button = document.createElement("button");
  420. button.id = `taskbar-${windowId}`;
  421. button.style.cssText = `
  422. min-width: 140px;
  423. max-width: 180px;
  424. height: 2.25rem;
  425. padding: 0 0.5rem;
  426. overflow: hidden;
  427. cursor: pointer;
  428. background-color: #c0c0c0;
  429. box-shadow: -2px -2px #e0dede, -2px 0 #e0dede, 0 -2px #e0dede, -4px -4px white, -4px 0 white, 0 -4px white, 2px 2px #818181, 0 2px #818181, 2px 0 #818181, 2px -2px #e0dede, -2px 2px #818181, -4px 2px white, -4px 4px black, 4px 4px black, 4px 0 black, 0 4px black, 2px -4px white, 4px -4px black;
  430. display: flex;
  431. align-items: center;
  432. gap: 0.35rem;
  433. border: none;
  434. `;
  435. const iconSpan = document.createElement("span");
  436. iconSpan.textContent = icon;
  437. iconSpan.style.cssText = `
  438. font-size: 18px;
  439. flex-shrink: 0;
  440. line-height: 1;
  441. `;
  442. const textSpan = document.createElement("span");
  443. textSpan.textContent = title;
  444. textSpan.style.cssText = `
  445. overflow: hidden;
  446. text-overflow: ellipsis;
  447. white-space: nowrap;
  448. font-weight: bold;
  449. font-size: 11px;
  450. letter-spacing: 0.3px;
  451. `;
  452. button.appendChild(iconSpan);
  453. button.appendChild(textSpan);
  454. button.addEventListener("mousedown", () => {
  455. button.style.boxShadow = "-2px -2px #818181, -2px 0 #818181, 0 -2px #818181, -4px -4px black, -4px 0 black, 0 -4px black, 2px 2px #e0dede, 0 2px #e0dede, 2px 0 #e0dede, 2px -2px #818181, -2px 2px #e0dede, -4px 2px black, -4px 4px white, 4px 4px white, 4px 0 white, 0 4px white, 2px -4px black, 4px -4px white";
  456. });
  457. button.addEventListener("mouseup", () => {
  458. button.style.boxShadow = "-2px -2px #e0dede, -2px 0 #e0dede, 0 -2px #e0dede, -4px -4px white, -4px 0 white, 0 -4px white, 2px 2px #818181, 0 2px #818181, 2px 0 #818181, 2px -2px #e0dede, -2px 2px #818181, -4px 2px white, -4px 4px black, 4px 4px black, 4px 0 black, 0 4px black, 2px -4px white, 4px -4px black";
  459. });
  460. button.addEventListener("click", () => {
  461. restoreWindow(windowId);
  462. });
  463. taskbarWindows.appendChild(button);
  464. }
  465. function removeFromTaskbar(windowId) {
  466. const button = document.getElementById(`taskbar-${windowId}`);
  467. if (button) {
  468. button.remove();
  469. }
  470. }
  471. const startButton = document.querySelector('button[aria-label="startButton"]');
  472. if (startButton) {
  473. startButton.addEventListener('click', () => {
  474. const w = document.getElementById('SimoSearch');
  475. if (!w) return;
  476. w.style.display = 'block';
  477. w.style.zIndex = '9999';
  478. });
  479. }
  480. </script>