From 80d64e04441ced7caecd238ae232e749d8e0dddf Mon Sep 17 00:00:00 2001 From: realtradam Date: Tue, 21 May 2024 23:32:53 -0400 Subject: initial setup of seperating frontend --- src/App.css | 42 ++++++++++ src/App.tsx | 7 ++ src/assets/react.svg | 1 + src/components/App.jsx | 7 ++ src/components/Blogs.jsx | 66 ++++++++++++++++ src/components/Button.jsx | 15 ++++ src/components/Game.jsx | 23 ++++++ src/components/GameCard.jsx | 26 ++++++ src/components/Games.jsx | 93 ++++++++++++++++++++++ src/components/Home.jsx | 43 ++++++++++ src/components/Layout.jsx | 60 ++++++++++++++ src/components/index.jsx | 10 +++ src/controllers/application.js | 9 +++ src/controllers/hello_controller.js | 7 ++ src/controllers/index.js | 8 ++ src/index.css | 154 ++++++++++++++++++++++++++++++++++++ src/main.tsx | 10 +++ src/routes/index.jsx | 35 ++++++++ src/vite-env.d.ts | 1 + 19 files changed, 617 insertions(+) create mode 100644 src/App.css create mode 100644 src/App.tsx create mode 100644 src/assets/react.svg create mode 100644 src/components/App.jsx create mode 100644 src/components/Blogs.jsx create mode 100644 src/components/Button.jsx create mode 100644 src/components/Game.jsx create mode 100644 src/components/GameCard.jsx create mode 100644 src/components/Games.jsx create mode 100644 src/components/Home.jsx create mode 100644 src/components/Layout.jsx create mode 100644 src/components/index.jsx create mode 100644 src/controllers/application.js create mode 100644 src/controllers/hello_controller.js create mode 100644 src/controllers/index.js create mode 100644 src/index.css create mode 100644 src/main.tsx create mode 100644 src/routes/index.jsx create mode 100644 src/vite-env.d.ts (limited to 'src') 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 (); +} + 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 @@ + \ 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 (); +} + 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) => ( +
+
+ {`${blog.name} +
+
{blog.name}
+ + View Post + +
+
+
+ )); + const noBlog = ( +
+

Nothing Yet!

+
+ ); + + return ( + <> +
+
+

Welcome to my Blog

+

+ Yup, this is my blog and stuff. Enjoy it :) +

+
+
+
+
+
+ + Write New Blog + +
+
+ {blogs.length > 0 ? allBlogs : noBlog} +
+ + Home + +
+
+ + ); +}; + +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 ( + <> +
+
+ { link } +
+
+ + ) +}; 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"; + +//} /> + +//export default () => ( +export default function Games () { + let { user, game } = useParams(); +//http://localhost:3000/api/v1/game/realtradam/orc-arena-of-time/index.html + return( + <> +
+
+
Orc: Arena of Time
+ +
+
+ + ); +}; 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 ( + <> + +
+
+ +
+ + +
+
+ + ) +}; 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) => ( + + )); + 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( + <> +
+
+
Games
+
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ }/> +
+ +
+
+
+
+ { allGames } +
+ + + + + + +
+
+
+ + ); +}; 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( + <> +
+
+
Get To Know Me a Little
+
+
+
+

Debug! Again

+

+Ea optio vitae culpa voluptatem consectetur. Ab quisquam sed ipsum. Perspiciatis minus odit quas qui consequuntur dicta reiciendis a. Nihil minima sed aliquam. +

+
+
+
+
+
+
+ + ); +}; 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 ( + <> +
+ + +
+
+
+
+
+
+
+ + + ) +}; 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(); +}); 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( + + + , +) 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 (<> + {/*

{userData.login}

*/} + + + }> + } /> + } /> + } /> + } /> + + + + ); +} 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 @@ +/// -- cgit v1.2.3