diff --git a/index.html b/index.html index a4b611c7..e34b429c 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,11 @@ - + - Josh Ashton diff --git a/package-lock.json b/package-lock.json index 8e82a9ea..fc65bccc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "swiper": "^10.0.0" }, "devDependencies": { - "vite": "^4.0.4" + "vite": "^4.0.4", + "vite-plugin-terminal": "^1.2.0" } }, "node_modules/@esbuild/android-arm": { @@ -453,6 +454,73 @@ "react": ">=16.3" } }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-strip": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-strip/-/plugin-strip-3.0.4.tgz", + "integrity": "sha512-LDRV49ZaavxUo2YoKKMQjCxzCxugu1rCPQa0lDYBOWLj6vtzBMr8DcoJjsmg+s450RbKbe3qI9ZLaSO+O1oNbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, "node_modules/@zeit/schemas": { "version": "2.36.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.36.0.tgz", @@ -879,6 +947,13 @@ "@esbuild/win32-x64": "0.18.20" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -1037,6 +1112,13 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -1049,6 +1131,16 @@ "loose-envify": "cli.js" } }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -1115,6 +1207,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1222,6 +1324,19 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { "version": "8.4.49", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", @@ -1477,6 +1592,21 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1568,6 +1698,16 @@ "node": ">= 4.7.0" } }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -1580,6 +1720,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true, + "license": "MIT" + }, "node_modules/update-check": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", @@ -1664,6 +1811,54 @@ } } }, + "node_modules/vite-plugin-terminal": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-terminal/-/vite-plugin-terminal-1.2.0.tgz", + "integrity": "sha512-IIw1V+IySth8xlrGmH4U7YmfTp681vTzYpa7b8A3KNCJ2oW1BGPPwW8tSz6BQTvSgbRmrP/9NsBLsfXkN4e8sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-strip": "^3.0.2", + "debug": "^4.3.4", + "kolorist": "^1.7.0", + "sirv": "^2.0.2", + "ufo": "^1.1.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/patak-dev" + }, + "peerDependencies": { + "vite": "^2.0.0||^3.0.0||^4.0.0||^5.0.0" + } + }, + "node_modules/vite-plugin-terminal/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/vite-plugin-terminal/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 4102d611..2946d30f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "swiper": "^10.0.0" }, "devDependencies": { - "vite": "^4.0.4" + "vite": "^4.0.4", + "vite-plugin-terminal": "^1.2.0" }, "name": "portfolio", "version": "0.0.1", diff --git a/src/App.jsx b/src/App.jsx index d72f52c9..092399f5 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,12 +1,9 @@ -import React, { useEffect, useState } from "react"; +import React, { useState, useEffect } from "react"; import VerticalSlider from "./components/VerticalSlider"; import Primary from "./Primary"; -import Skills from "./Skills"; import Projects from "./Projects"; -import Contact from "./Contact"; -import About from "./About"; -import ProjectCard from "./components/ProjectCard"; import "./main.css"; +import { terminal } from "virtual:terminal"; /** * TODO: Read in data from a plain text file for easier editing in the future. @@ -16,12 +13,19 @@ export default function App() { const [isMobile, setIsMobile] = useState(window.innerWidth <= 790); useEffect(() => { - const handleResize = () => setIsMobile(window.innerWidth <= 790); + const handleResize = () => { + const mediaQuery = window.matchMedia("(max-width: 790px)"); + setIsMobile(mediaQuery.matches); + }; + + handleResize(); // Initial check on mount window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); }, []); const initState = isMobile ? [true, false, false] : [true, true, true]; + terminal.log("isMobile: " + isMobile); // DATA VARIABLES /* @@ -37,7 +41,7 @@ export default function App() { { title: "One AI", descriptionA: - "An end-to-end self-hosted Artificial Intelligence solution, using Meta's Ollama platform to run Large Language Models. Go was used for the backend as a wrapper API and the frontend is Flutter for its write once, build anywhere ideology. Here are some of the implemented features:", + "An end-to-end self-hosted Artificial Intelligence solution, using Meta's Ollama platform to run Large Language Models. Go was used for the backend as a wrapper API and the frontend is Flutter. Here are some of the implemented features:", featureList: [ "user authentication", "AES encryption", @@ -97,5 +101,6 @@ export default function App() { />, , ]; + return ; } diff --git a/src/Primary.jsx b/src/Primary.jsx index 35b7585b..fe546f3a 100644 --- a/src/Primary.jsx +++ b/src/Primary.jsx @@ -1,6 +1,7 @@ // TODO: Replace h4 callToAction with a GREEN button callToAction. -import React, { useState } from "react"; +import React, { useState, useRef } from "react"; import SkillCard from "./components/SkillCard"; +import { terminal } from "virtual:terminal"; export default function Primary({ primaryText, @@ -10,6 +11,7 @@ export default function Primary({ skills, initState, }) { + const [activeCardIndex, setActiveCardIndex] = useState(null); return ( <>
@@ -30,18 +32,27 @@ export default function Primary({ symbol="code" list={skills.languages} initState={initState[0]} + index={0} + isActive={activeCardIndex === 0} + onToggle={() => setActiveCardIndex(0)} /> setActiveCardIndex(1)} /> setActiveCardIndex(2)} />
diff --git a/src/components/ProjectCard.jsx b/src/components/ProjectCard.jsx index a6464176..a3a12270 100644 --- a/src/components/ProjectCard.jsx +++ b/src/components/ProjectCard.jsx @@ -20,8 +20,8 @@ export default function ProjectCard({

{title}

{descriptionA}

diff --git a/src/components/SkillCard.jsx b/src/components/SkillCard.jsx index ce8c1d98..ae37ef29 100644 --- a/src/components/SkillCard.jsx +++ b/src/components/SkillCard.jsx @@ -2,26 +2,29 @@ import React, { useState } from "react"; // TODO: Add state which only allows one skill card at a time to be expanded. // TODO: Ensure that the expandability of the skill card is only an option when @media max-width 790px (mobile) -export default function SkillCard({ header, symbol, list, initState }) { - const [isExpanded, setIsExpanded] = useState(initState); // Initial state +const SkillCard = ({ header, symbol, list, initState, isActive, onToggle }) => { + const [isExpanded, setIsExpanded] = useState(initState || isActive); const toggleExpansion = () => { setIsExpanded(!isExpanded); + onToggle(); }; return ( -
-
+
+
toggleExpansion()}> {symbol}

{header}

- {isExpanded && ( + {isActive && (
    - {list.map((item) => ( -
  • {item}
  • + {list.map((item, index) => ( +
  • {item}
  • ))}
)}
); -} +}; + +export default SkillCard; diff --git a/src/main.css b/src/main.css index 45f32628..2eb6dcd5 100644 --- a/src/main.css +++ b/src/main.css @@ -446,7 +446,7 @@ h4 { @media (max-width: 790px) { #primary { display: grid; - grid-template-rows: 50% 40% 10%; + grid-template-rows: 40% 40% 10%; grid-template-columns: 100%; } @@ -513,6 +513,11 @@ h4 { font-size: 10vw; } + #project-grid-container { + height: 90vh; + grid-template-rows: 10% 80%; + } + .project-card { display: grid; grid-template-columns: 100%; @@ -528,6 +533,10 @@ h4 { padding: 2vw; } + .project-text-column { + margin-left: 5vw; + } + .button { } } diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 00000000..7cb63e69 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,5 @@ +import Terminal from "vite-plugin-terminal"; + +export default { + plugins: [Terminal()], +};