summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorrealtradam <[email protected]>2024-05-21 23:32:53 -0400
committerrealtradam <[email protected]>2024-05-21 23:32:53 -0400
commit80d64e04441ced7caecd238ae232e749d8e0dddf (patch)
treec41d7803a15aa99b51703bbecc56ec2ed2233431 /src
downloadmalcz.com-80d64e04441ced7caecd238ae232e749d8e0dddf.tar.gz
malcz.com-80d64e04441ced7caecd238ae232e749d8e0dddf.zip
initial setup of seperating frontend
Diffstat (limited to 'src')
-rw-r--r--src/App.css42
-rw-r--r--src/App.tsx7
-rw-r--r--src/assets/react.svg1
-rw-r--r--src/components/App.jsx7
-rw-r--r--src/components/Blogs.jsx66
-rw-r--r--src/components/Button.jsx15
-rw-r--r--src/components/Game.jsx23
-rw-r--r--src/components/GameCard.jsx26
-rw-r--r--src/components/Games.jsx93
-rw-r--r--src/components/Home.jsx43
-rw-r--r--src/components/Layout.jsx60
-rw-r--r--src/components/index.jsx10
-rw-r--r--src/controllers/application.js9
-rw-r--r--src/controllers/hello_controller.js7
-rw-r--r--src/controllers/index.js8
-rw-r--r--src/index.css154
-rw-r--r--src/main.tsx10
-rw-r--r--src/routes/index.jsx35
-rw-r--r--src/vite-env.d.ts1
19 files changed, 617 insertions, 0 deletions
diff --git a/src/App.css b/src/App.css
new file mode 100644
index 0000000..b9d355d
--- /dev/null
+++ b/src/App.css
@@ -0,0 +1,42 @@
+#root {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: filter 300ms;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+ filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ a:nth-of-type(2) .logo {
+ animation: logo-spin infinite 20s linear;
+ }
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/src/App.tsx b/src/App.tsx
new file mode 100644
index 0000000..b594288
--- /dev/null
+++ b/src/App.tsx
@@ -0,0 +1,7 @@
+import React from "react";
+import Routes from "./routes";
+
+export default (props) => {
+ return (<Routes />);
+}
+
diff --git a/src/assets/react.svg b/src/assets/react.svg
new file mode 100644
index 0000000..6c87de9
--- /dev/null
+++ b/src/assets/react.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg> \ No newline at end of file
diff --git a/src/components/App.jsx b/src/components/App.jsx
new file mode 100644
index 0000000..da6a873
--- /dev/null
+++ b/src/components/App.jsx
@@ -0,0 +1,7 @@
+import React from "react";
+import Routes from "../routes";
+
+export default (props) => {
+ return (<Routes />);
+}
+
diff --git a/src/components/Blogs.jsx b/src/components/Blogs.jsx
new file mode 100644
index 0000000..f52f286
--- /dev/null
+++ b/src/components/Blogs.jsx
@@ -0,0 +1,66 @@
+import React, { useState, useEffect } from "react";
+import { Link, useNavigate } from "react-router-dom";
+
+const Blogs = () => {
+ const navigate = useNavigate();
+ const [blogs, setBlogs] = useState([]);
+
+ useEffect(() => {
+ const url = "/api/v1/blogs/index";
+ fetch(url).then((response) => {
+ if (response.ok) {
+ return response.json();
+ }
+ throw new Error("Network response was not ok.");
+ }).then((response) => setBlogs(response)).catch(() => navigate("/"));
+ }, []);
+
+ const allBlogs = blogs.map((blog, index) => (
+ <div key={index} className="col-md-6 col-lg-4">
+ <div className="card mb-4">
+ <img src={blog.image} className="card-img-top" alt={`${blog.name} image`}/>
+ <div className="card-body">
+ <h5 className="card-title">{blog.name}</h5>
+ <Link to={`/blog/${blog.id}`} className="btn custom-button">
+ View Post
+ </Link>
+ </div>
+ </div>
+ </div>
+ ));
+ const noBlog = (
+ <div className="vw-100 vh-50 dflex align-items-center justify-content-center">
+ <h4> Nothing Yet! </h4>
+ </div>
+ );
+
+ return (
+ <>
+ <section className="jumbotron jumbotron-fluid text-center">
+ <div className="container py-5">
+ <h1 className="display-4">Welcome to my Blog</h1>
+ <p className="lead text-muted">
+ Yup, this is my blog and stuff. Enjoy it :)
+ </p>
+ </div>
+ </section>
+ <div className="py-5">
+ <main className="container">
+ <div className="text-end mb-3">
+ <Link to="/blog" className="btn custom-button">
+ Write New Blog
+ </Link>
+ </div>
+ <div className="row">
+ {blogs.length > 0 ? allBlogs : noBlog}
+ </div>
+ <Link to="/" className="btn btn-link">
+ Home
+ </Link>
+ </main>
+ </div>
+ </>
+ );
+};
+
+export default Blogs;
diff --git a/src/components/Button.jsx b/src/components/Button.jsx
new file mode 100644
index 0000000..de199d0
--- /dev/null
+++ b/src/components/Button.jsx
@@ -0,0 +1,15 @@
+import React from "react";
+import { Link } from "react-router-dom";
+
+export default function Button ({ link, width = 36, height = 16, spinner = 4 })
+{
+ return (
+ <>
+ <div className={`w-${ width } h-${ height } relative grid rounded-[5px] cursor-pointer overflow-hidden place-items-center before:content-[''] before:absolute before:w-${ spinner } before:bg-amber-400 before:rotate-[32deg] before:h-[1%] before:transition-all before:duration-500 before:ease-linear before:animate-[buttonSpin_1.5s_linear_infinite] hover:before:h-[2800%] hover:before:transition-all hover:before:duration-0 hover:before:ease-linear after:absolute after:content-[''] after:bg-stone-800 after:rounded-[5px] after:inset-0 after:transition-all after:duration-200 after:ease-in-out hover:after:inset-[5px] hover:after:transition-all hover:after:duration-200 hover:after:ease-in-out`}>
+ <div className="z-[3]">
+ { link }
+ </div>
+ </div>
+ </>
+ )
+};
diff --git a/src/components/Game.jsx b/src/components/Game.jsx
new file mode 100644
index 0000000..8b80b8e
--- /dev/null
+++ b/src/components/Game.jsx
@@ -0,0 +1,23 @@
+import React, { useState, useEffect } from "react";
+import { useParams } from "react-router-dom";
+//import { Link } from "react-router-dom";
+import GameCard from "./GameCard";
+import Button from "./Button";
+
+//<Route path="/games/:user/:game" element={<Game />} />
+
+//export default () => (
+export default function Games () {
+ let { user, game } = useParams();
+//http://localhost:3000/api/v1/game/realtradam/orc-arena-of-time/index.html
+ return(
+ <>
+ <div>
+ <div className="flex flex-col gap-16 max-w-6xl shrink">
+ <div className="title font-bold text-6xl font-title">Orc: Arena of Time</div>
+ <iframe style={{ aspectRatio: 1 }} className="bg-black aspect-square max-h-[90vh] rounded" src="http://localhost:3000/api/v1/game/realtradam/orc-arena-of-time/index.html" title={game}></iframe>
+ </div>
+ </div>
+ </>
+ );
+};
diff --git a/src/components/GameCard.jsx b/src/components/GameCard.jsx
new file mode 100644
index 0000000..9cd815d
--- /dev/null
+++ b/src/components/GameCard.jsx
@@ -0,0 +1,26 @@
+import React from "react";
+//import { Link } from "react-router-dom";
+
+//game = {
+// card_img: "",
+// char_img: "",
+// title_img: ""
+//}
+
+export default function GameCard ({ link = "./", width = "72", game = { card_img: "https://ggayane.github.io/css-experiments/cards/dark_rider-cover.jpg", char_img: "https://ggayane.github.io/css-experiments/cards/dark_rider-character.png", title_img: "https://ggayane.github.io/css-experiments/cards/dark_rider-title.png" } })
+{
+
+ return (
+ <>
+ <a href={ link } className="block w-min pt-10 px-1" target="_blank">
+ <div className="gameCard">
+ <div className="gameCardWrapper">
+ <img src={`/api/v1/games_img/realtradam/${game.titleSlug}.png?type=card`} className="gameCardCoverImg" />
+ </div>
+ <img src={`/api/v1/games_img/realtradam/${game.titleSlug}.png?type=title`} className="gameTitleImg p-5%" />
+ <img src={`/api/v1/games_img/realtradam/${game.titleSlug}.png?type=char`} className="gameCharacterImg" />
+ </div>
+ </a>
+ </>
+ )
+};
diff --git a/src/components/Games.jsx b/src/components/Games.jsx
new file mode 100644
index 0000000..f1545b8
--- /dev/null
+++ b/src/components/Games.jsx
@@ -0,0 +1,93 @@
+import React, { useState, useEffect } from "react";
+//import { Link } from "react-router-dom";
+import GameCard from "./GameCard";
+import Button from "./Button";
+
+//export default () => (
+export default function Games () {
+ const [games, setGames] = useState([]);
+ useEffect(() => {
+ const url = "/api/v1/games";
+ fetch(url).then((response) => {
+ if (response.ok) {
+ return response.json();
+ }
+ throw new Error("Network response was not ok.");
+ }).then((response) => setGames(response)).catch(() => navigate("/"));
+ }, []);
+ const allGames = games.map((game) => (
+ <GameCard game={game} key={game.id}/>
+ ));
+ var handleSubmit = (e) => {
+ e.preventDefault() //stops submit from happening
+ const form = e.target;
+ const formData = new FormData()
+ formData.append('game[title]', form.title.value)
+ for(let i =0; i < form.game_files.files.length; i++)
+ {
+ formData.append('game[game_files][]', form.game_files.files[i], form.game_files.files[i].value);
+ }
+ formData.append('game[card_img]', form.card_img.files[0], form.card_img.value);
+ formData.append('game[char_img]', form.char_img.files[0], form.char_img.value);
+ formData.append('game[title_img]', form.title_img.files[0], form.title_img.value);
+
+ for (var pair of formData.entries()) {
+ console.log(pair[0] + ', ' + pair[1])
+ };
+
+ fetch('http://127.0.0.1:3000/api/v1/games', {
+ method: 'post',
+ body: formData,
+ });
+ }
+ return(
+ <>
+ <div>
+ <div className="flex flex-col gap-16 max-w-6xl shrink">
+ <div className="title font-bold text-6xl font-title">Games</div>
+ <div className="">
+ <div className="jumbotron jumbotron-fluid bg-transparent">
+ <div className="container secondary-color">
+ <form onSubmit={handleSubmit} action="/upload" method="post" className="flex flex-col gap-4">
+ <div>
+ <label>Title</label>
+ <input type="text" name="title" />
+ </div>
+ <div>
+ <label>Files</label>
+ <input type="file" multiple="multiple" name="game_files" />
+ </div>
+ <div>
+ <label>Card Image</label>
+ <input type="file" name="card_img" />
+ </div>
+ <div>
+ <label>Character Image</label>
+ <input type="file" name="char_img" />
+ </div>
+ <div>
+ <label>Title Image</label>
+ <input type="file" name="title_img" />
+ </div>
+ <div style={{ boxShadow: 'rgba(255,255,255,.1) 0 1px 0,rgba(0,0,0,.8) 0 1px 7px 0 inset' }} className="p-[5px] w-min h-min bg-stone-800 rounded-[5px]">
+ <Button width={ 28 } height={ 12 } link={ <button type="submit" className="w-28 h-12 bg-stone-transparent text-stone-50 rounded">Submit</button> }/>
+ </div>
+
+ </form>
+ </div>
+ </div>
+ </div>
+ { allGames }
+ <div className="flex flex-row flex-wrap gap-20 justify-around">
+ <GameCard />
+ <GameCard />
+ <GameCard />
+ <GameCard />
+ <GameCard />
+ <GameCard />
+ </div>
+ </div>
+ </div>
+ </>
+ );
+};
diff --git a/src/components/Home.jsx b/src/components/Home.jsx
new file mode 100644
index 0000000..863d81d
--- /dev/null
+++ b/src/components/Home.jsx
@@ -0,0 +1,43 @@
+import React, { } from "react";
+//import { Link } from "react-router-dom";
+import GameCard from "./GameCard";
+
+//export default () => (
+export default function Home () {
+ var handleSubmit = (e) => {
+ e.preventDefault() //stops submit from happening
+
+ const formData = new FormData()
+ formData.append('game[title]', e.target.title.value)
+ formData.append('game[game_file]', e.target.game_file.files[0], e.target.game_file.value)
+
+ for (var pair of formData.entries()) {
+ console.log(pair[0] + ', ' + pair[1])
+ };
+
+ fetch('http://127.0.0.1:3000/api/v1/games', {
+ method: 'post',
+ body: formData,
+ });
+ }
+ return(
+ <>
+ <div>
+ <div className="flex flex-col gap-16 max-w-6xl shrink">
+ <div className="title font-bold text-6xl font-title">Get To Know Me a Little</div>
+ <div className="">
+ <div className="jumbotron jumbotron-fluid bg-transparent">
+ <div className="container secondary-color">
+ <h1 className="text-2xl">Debug! Again</h1>
+ <p className="">
+Ea optio vitae culpa voluptatem consectetur. Ab quisquam sed ipsum. Perspiciatis minus odit quas qui consequuntur dicta reiciendis a. Nihil minima sed aliquam.
+ </p>
+ <hr className="my-4" />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </>
+ );
+};
diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx
new file mode 100644
index 0000000..79e7813
--- /dev/null
+++ b/src/components/Layout.jsx
@@ -0,0 +1,60 @@
+import React from "react";
+import { Outlet, Link } from "react-router-dom";
+import Button from "./Button";
+export default function Layout ({userData})
+{
+ console.log(userData);
+ //const [userData, setUserData] = useState({ name: "" });
+
+ // if the user tries to access the isolated domain then we redirect them
+ // this is NOT done for security, only for good UX
+ // rails serves the react app no matter what
+ // so the app would be broken when served on the isolated domain
+ const domain = window.location.host;
+ console.log(domain);
+ if(domain === "localhost:3000")
+ {
+ window.location.replace("http://127.0.0.1:3000");
+ }
+
+ return (
+ <>
+ <div id="page" className="star flex flex-row min-h-screen max-h-screen bg-amber-400 text-stone-950 text-xl bg-star bg-repeat bg-[length:170px_170px]">
+ <div id="sidebar" className="flex flex-row shrink-0 grow-0 h-vh w-64 items-top bg-stone-800">
+ <nav id="sidebar-content" dir="rtl" className="text-stone-50 p-6 w-full h-screen overflow-y-auto overflow-x-hidden">
+ <div dir='ltr'>
+ { userData.name ? <div className="flex items-end gap-2 pb-2"> <div className="text-xs"> Logged in as: </div> <div>{userData.name}</div> </div> : <a href="https://github.com/login/oauth/authorize?client_id=74468ad0847e527262d9" className="pb-2"> Login with Github </a> }
+ <div className="text-3xl py-10 text-center font-title">Adam Malczewski</div>
+ <div className="flex flex-col items-center gap-1 w-full">
+ <Button link={ <Link to="/" className="absolute flex top-0 left-0 w-36 h-16 text-stone-50 bg-transparent justify-center items-center" role="button"><div className="h-min">About Me</div></Link> }/>
+ <Button link={ <Link to="/blogs" className="absolute flex top-0 left-0 w-36 h-16 text-stone-50 bg-transparent justify-center items-center" role="button"><div className="h-min">Blog</div></Link> }/>
+ <Button link={ <Link to="/games" className="absolute flex top-0 left-0 w-36 h-16 text-stone-50 bg-transparent justify-center items-center" role="button"><div className="h-min">Games</div></Link> }/>
+ <Button link={ <div className="text-stone-50 bg-transparent w-36 h-16 flex justify-center items-center">
+ <a id="contact" href="mailto:[email protected]" className="w-36 h-16 relative text-center whitespace-nowrap flex justify-center items-center">
+ <div className="contact w-36 h-16 flex items-center justify-center">
+ <span className="h-min">Contact</span>
+ </div>
+ <div className="contact w-36 h-16 flex items-center justify-center">
+ <span className="text-sm h-min">[email protected]</span>
+ </div>
+ </a>
+ </div> }/>
+ <div className="socials flex flex-row place-content-center gap-1">
+ <Button link={<a id="contact" href="https://github.com/realtradam" className="absolute flex top-0 left-0 w-10 h-16 text-stone-50 bg-transparent justify-center items-center"><i className="fa-brands fa-github"></i></a>} width={10} height={16} spinner={3}/>
+ <Button link={<a id="contact" href="https://www.linkedin.com/in/adammalczewski/" className="absolute flex top-0 left-0 w-10 h-16 text-stone-50 bg-transparent justify-center items-center"><i className="fa-brands fa-linkedin"></i></a>} width={10} height={16} spinner={3}/>
+ <Button link={<a id="contact" href="https://tradam.itch.io" className="absolute flex top-0 left-0 w-10 h-16 text-stone-50 bg-transparent justify-center items-center"><i className="fa-brands fa-itch-io"></i></a>} width={10} height={16} spinner={3}/>
+ </div>
+ </div>
+ </div>
+ </nav>
+ <div id="sawtooth-wrap" className="sawtooth-left-wrap h-full">
+ <div id="sawtooth" className="sawtooth-left w-4 h-full bg-amber-400"></div>
+ </div>
+ </div>
+ <div id="radial-wrap" className="shrink w-full max-h-vh h-vh overflow-auto overflow-x-hidden">
+ <div id="content" className="flex justify-center items-center w-full p-20"> <Outlet /> </div>
+ </div>
+ </div>
+ </>
+ )
+};
diff --git a/src/components/index.jsx b/src/components/index.jsx
new file mode 100644
index 0000000..0044916
--- /dev/null
+++ b/src/components/index.jsx
@@ -0,0 +1,10 @@
+import React from "react";
+import { createRoot } from "react-dom/client";
+import App from "./App";
+
+document.addEventListener("turbo:load", () => {
+ const root = createRoot(
+ document.body.appendChild(document.createElement("div"))
+ );
+ root.render(<App />);
+});
diff --git a/src/controllers/application.js b/src/controllers/application.js
new file mode 100644
index 0000000..1213e85
--- /dev/null
+++ b/src/controllers/application.js
@@ -0,0 +1,9 @@
+import { Application } from "@hotwired/stimulus"
+
+const application = Application.start()
+
+// Configure Stimulus development experience
+application.debug = false
+window.Stimulus = application
+
+export { application }
diff --git a/src/controllers/hello_controller.js b/src/controllers/hello_controller.js
new file mode 100644
index 0000000..5975c07
--- /dev/null
+++ b/src/controllers/hello_controller.js
@@ -0,0 +1,7 @@
+import { Controller } from "@hotwired/stimulus"
+
+export default class extends Controller {
+ connect() {
+ this.element.textContent = "Hello World!"
+ }
+}
diff --git a/src/controllers/index.js b/src/controllers/index.js
new file mode 100644
index 0000000..d0685d3
--- /dev/null
+++ b/src/controllers/index.js
@@ -0,0 +1,8 @@
+// This file is auto-generated by ./bin/rails stimulus:manifest:update
+// Run that command whenever you add a new controller or create them with
+// ./bin/rails generate stimulus controllerName
+
+import { application } from "./application"
+
+import HelloController from "./hello_controller"
+application.register("hello", HelloController)
diff --git a/src/index.css b/src/index.css
new file mode 100644
index 0000000..8ea4fad
--- /dev/null
+++ b/src/index.css
@@ -0,0 +1,154 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/*
+
+@layer components {
+.btn-primary {
+@apply py-2 px-4 bg-blue-200;
+}
+}
+
+ */
+.gameCard {
+ aspect-ratio: 5/7;
+ width: 300px;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: flex-end;
+ perspective: 2500px;
+}
+
+.gameCardCoverImg {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ image-rendering: pixelated;
+}
+
+.gameCardWrapper {
+ transition: all 0.5s;
+ position: absolute;
+ width: 100%;
+ z-index: -1;
+ box-shadow: -15px 15px 32px -8px rgba(0, 0, 0, 0.75)
+}
+
+.gameCard:hover .gameCardWrapper {
+ transform: perspective(900px) translateY(-5%) rotateX(25deg) translateZ(0);
+ box-shadow: -10px 35px 32px -8px rgba(0, 0, 0, 0.75);
+ -webkit-box-shadow: 2px 35px 32px -8px rgba(0, 0, 0, 0.75);
+ -moz-box-shadow: 2px 35px 32px -8px rgba(0, 0, 0, 0.75);
+}
+
+.gameCardWrapper::before,
+.gameCardWrapper::after {
+ content: "";
+ opacity: 0;
+ width: 100%;
+ height: 80px;
+ transition: all 0.5s;
+ position: absolute;
+ left: 0;
+}
+.gameCardWrapper::before {
+ top: 0;
+ height: 100%;
+ background-image: linear-gradient(
+ to top,
+ transparent 46%,
+ rgba(12, 13, 19, 0.5) 68%,
+ rgba(12, 13, 19) 97%
+ );
+}
+.gameCardWrapper::after {
+ bottom: 0;
+ opacity: 1;
+ background-image: linear-gradient(
+ to bottom,
+ transparent 46%,
+ rgba(12, 13, 19, 0.5) 68%,
+ rgba(12, 13, 19) 97%
+ );
+}
+
+.gameCard:hover .gameCardWrapper::before,
+.gameCardWrapper::after {
+ opacity: 1;
+}
+
+.gameCard:hover .gameCardWrapper::after {
+ height: 120px;
+}
+.gameTitleImg {
+ width: 100%;
+ transition: transform 0.5s;
+ image-rendering: pixelated;
+}
+.gameCard:hover .gameTitleImg {
+ transform: translate3d(0%, -50px, 100px);
+}
+
+.gameCharacterImg {
+ width: 100%;
+ opacity: 0;
+ transition: all 0.5s;
+ position: absolute;
+ z-index: -1;
+ image-rendering: pixelated;
+}
+
+.gameCard:hover .gameCharacterImg {
+ opacity: 1;
+ transform: translate3d(0%, -30%, 100px);
+}
+
+@keyframes pan {
+ 0% {
+ background-position: 0% 0%;
+ }
+ 100% {
+ background-position: 340px -170px;
+ }
+}
+
+#radial-wrap {
+ background: linear-gradient(90deg, rgba(251,191,36,1) 1%, rgba(251,191,36,0) 10%, rgba(251,191,36,0) 90%, rgba(251,191,36,1) 99%);
+}
+
+.button:hover::before {
+ width: 5000px;
+}
+
+@keyframes buttonSpin {
+ from {
+ transform: rotate(32deg);
+ }
+ to {
+ transform: rotate(calc(360deg + 32deg));
+ filter: hue-rotate(360deg);
+ }
+}
+
+.contact { transition: opacity 1s ease; position: absolute;}
+.contact + .contact,
+ a:hover .contact:first-child { opacity: 0; }
+ a:hover .contact:first-child + .contact { opacity: 1; }
+.contact + .contact { pointer-events: none; }
+
+@layer utilities {
+ .star {
+ animation: pan 80s linear infinite;
+ }
+ .sawtooth-right {
+ clip-path: polygon(0% -1%, -1% 100.0%, 101% 98.0%, -1% 96.0%, 101% 94.0%, -1% 92.0%, 101% 90.0%, -1% 88.0%, 101% 86.0%, -1% 84.0%, 101% 82.0%, -1% 80.0%, 101% 78.0%, -1% 76.0%, 101% 74.0%, -1% 72.0%, 101% 70.0%, -1% 68.0%, 101% 66.0%, -1% 64.0%, 101% 62.0%, -1% 60.0%, 101% 58.0%, -1% 56.0%, 101% 54.0%, -1% 52.0%, 101% 50.0%, -1% 48.0%, 101% 46.0%, -1% 44.0%, 101% 42.0%, -1% 40.0%, 101% 38.0%, -1% 36.0%, 101% 34.0%, -1% 32.0%, 101% 30.0%, -1% 28.0%, 101% 26.0%, -1% 24.0%, 101% 22.0%, -1% 20.0%, 101% 18.0%, -1% 16.0%, 101% 14.0%, -1% 12.0%, 101% 10.0%, -1% 8.0%, 101% 6.0%, -1% 4.0%, 101% 2.0%);
+ }
+ .sawtooth-left {
+ clip-path: polygon(102% 0%, 102% 100.0%, 0% 98.0%, 100% 96.0%, 0% 94.0%, 100% 92.0%, 0% 90.0%, 100% 88.0%, 0% 86.0%, 100% 84.0%, 0% 82.0%, 100% 80.0%, 0% 78.0%, 100% 76.0%, 0% 74.0%, 100% 72.0%, 0% 70.0%, 100% 68.0%, 0% 66.0%, 100% 64.0%, 0% 62.0%, 100% 60.0%, 0% 58.0%, 100% 56.0%, 0% 54.0%, 100% 52.0%, 0% 50.0%, 100% 48.0%, 0% 46.0%, 100% 44.0%, 0% 42.0%, 100% 40.0%, 0% 38.0%, 100% 36.0%, 0% 34.0%, 100% 32.0%, 0% 30.0%, 100% 28.0%, 0% 26.0%, 100% 24.0%, 0% 22.0%, 100% 20.0%, 0% 18.0%, 100% 16.0%, 0% 14.0%, 100% 12.0%, 0% 10.0%, 100% 8.0%, 0% 6.0%, 100% 4.0%, 0% 2.0%);
+ }
+ .sawtooth-left-wrap {
+ filter: drop-shadow(-10px 5px 4px rgba(0, 0, 0, 0.8));
+ }
+}
diff --git a/src/main.tsx b/src/main.tsx
new file mode 100644
index 0000000..3d7150d
--- /dev/null
+++ b/src/main.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App.tsx'
+import './index.css'
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+ <React.StrictMode>
+ <App />
+ </React.StrictMode>,
+)
diff --git a/src/routes/index.jsx b/src/routes/index.jsx
new file mode 100644
index 0000000..1b778ef
--- /dev/null
+++ b/src/routes/index.jsx
@@ -0,0 +1,35 @@
+import React, { useState, useEffect } from "react";
+import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
+import Home from "../components/Home";
+import Blogs from "../components/Blogs";
+import Games from "../components/Games";
+import Game from "../components/Game";
+import Layout from "../components/Layout";
+
+export default function index()
+{
+ const [userData, setUserData] = useState({});
+ const url = "/api/v1/auth/data";
+ useEffect(() => {
+ fetch(url).then((response) => {
+ if(response.ok) {
+ return response.json();
+ }
+ throw new Error("Network response was not ok.");
+ }).then((response) => setUserData(response.user_data));}, []);
+ // get user data here
+ // then pass it in as 'props' into the components
+ return (<>
+ {/*<h1>{userData.login}</h1>*/}
+ <Router>
+ <Routes>
+ <Route path="/" element = {<Layout userData={userData}/>}>
+ <Route index element={<Home />} />
+ <Route path="/blogs" element={<Blogs />} />
+ <Route path="/games" element={<Games />} />
+ <Route path="/games/:user/:game" element={<Game />} />
+ </Route>
+ </Routes>
+ </Router>
+ </>);
+}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1 @@
+/// <reference types="vite/client" />