diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..20fccdd4b84d99e50c632b9deb5d3eae964bef51 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000000000000000000000000000000000..3c032078a4a21c5c51d3c93d91717c1dabbb8cd0 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 diff --git a/components/EnergyOptionCard.js b/components/EnergyOptionCard.js new file mode 100644 index 0000000000000000000000000000000000000000..b1cf03be8b827090cdbbe3c4f204bdd43254bff0 --- /dev/null +++ b/components/EnergyOptionCard.js @@ -0,0 +1,20 @@ +import Link from 'next/link'; + +function EnergyOptionCard({ energyType, provider, location, id }) { + // Check if the id is a valid URL or fallback if needed + if (!id) { + return <div className="energy-option-card">Error: Invalid URL</div>; // Fallback message + } + + return ( + <Link href={id} passHref className="energy-option-card"> + <h3>{energyType}</h3> + <p><strong>Provider:</strong> {provider}</p> + <p><strong>Location:</strong> {location}</p> + </Link> + ); +} + +export default EnergyOptionCard; + + diff --git a/lib/db.js b/lib/db.js new file mode 100644 index 0000000000000000000000000000000000000000..f2baa3c247e32564616b914b9977cd2fb7a4ba49 --- /dev/null +++ b/lib/db.js @@ -0,0 +1,11 @@ +const { Pool } = require('pg'); + +// Create a new pool instance with your PostgreSQL connection string +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, +}); + +// Export the query function to interact with the database +module.exports = { + query: (text, params) => pool.query(text, params), +}; diff --git a/pages/2ndPage.js b/pages/2ndPage.js new file mode 100644 index 0000000000000000000000000000000000000000..7c1028c1039d97bda93bece9b2ae372351637f7e --- /dev/null +++ b/pages/2ndPage.js @@ -0,0 +1,44 @@ +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/router'; + +function ApiPage() { + const [data, setData] = useState(null); + const router = useRouter(); + + useEffect(() => { + fetch('https://jsonplaceholder.typicode.com/comments') + .then((response) => response.json()) + .then((data) => setData(data.slice(0, 10))) // Ersten 10 Daten + .catch((error) => console.error('Error fetching data:', error)); + }, []); + + const handleBack = () => { + router.push('/'); // Zurück zur Start Seite + }; + + return ( + <div> + <h1>API Seite</h1> + {data && data.length > 0 ? ( // Prüft ob data frei ist und ob es sachen hat + <div> + <h2>Ersten 10 Kommentare von der API:</h2> + <button onClick={handleBack}>Start Seite</button> + <ul> + {data.map((item) => ( + <li key={item.id}> + <p><strong>Kommentar:</strong> {item.body}</p> + </li> + ))} + </ul> + </div> + ) : ( + <p>Loading...</p> + )} + </div> + ); +} + +//<p><strong>Email:</strong> {item.name}</p> //Name +//<p><strong>Email:</strong> {item.email}</p> //Email + +export default ApiPage; diff --git a/pages/StartPage.js b/pages/StartPage.js new file mode 100644 index 0000000000000000000000000000000000000000..acebd40295f87601dae7fafe42d01d4e61194c3c --- /dev/null +++ b/pages/StartPage.js @@ -0,0 +1,19 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; + +function StartPage() { + const navigate = useNavigate(); + + const handleNavigate = () => { + navigate('/api-page'); + }; + + return ( + <div> + <h1>Welcome to the Start Page</h1> + <button onClick={handleNavigate}>Go to API Page</button> + </div> + ); +} + +export default StartPage; diff --git a/pages/_app.js b/pages/_app.js new file mode 100644 index 0000000000000000000000000000000000000000..fd2bd7690b1ba4eee5fbedc5970e49e1fb0bd070 --- /dev/null +++ b/pages/_app.js @@ -0,0 +1,7 @@ +import '../styles/global.css'; // Import the global CSS here + +function MyApp({ Component, pageProps }) { + return <Component {...pageProps} />; // Render the page component +} + +export default MyApp; // Default export of the React component diff --git a/pages/api/energy-options.js b/pages/api/energy-options.js new file mode 100644 index 0000000000000000000000000000000000000000..749213456f85010b924844956ef7e453e6dbfe36 --- /dev/null +++ b/pages/api/energy-options.js @@ -0,0 +1,42 @@ +/*import db from '../../lib/db'; // Import the database connection + +export default async function handler(req, res) { + if (req.method === 'GET') { + try { + const { rows } = await db.query('SELECT * FROM "Energy"'); + res.status(200).json({ success: true, data: rows }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } + } else { + res.status(405).json({ success: false, message: 'Method not allowed' }); + } +} +*/ + +import { Pool } from 'pg'; + +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, +}); + +export default async function handler(req, res) { + if (req.method === 'GET') { + try { + const { rows } = await pool.query('SELECT * FROM "Energy"'); + // Clean up the data to make it more readable + const formattedData = rows.map(option => ({ + id: option.id, + energyType: option.EnergyType, + provider: option.Provider, + location: option.Location, + })); + + res.status(200).json({ success: true, data: formattedData }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } + } else { + res.status(405).json({ success: false, message: 'Method not allowed' }); + } +} diff --git a/pages/backupindex.js b/pages/backupindex.js new file mode 100644 index 0000000000000000000000000000000000000000..e35137ec21e73489205266729e9a3778fd0a7578 --- /dev/null +++ b/pages/backupindex.js @@ -0,0 +1,131 @@ +import Head from 'next/head'; +import styles from '../styles/Home.module.css'; + +export default function Home() { + return ( + <div className={styles.container}> + <Head> + <title>Create Next App</title> + <link rel="icon" href="/favicon.ico" /> + </Head> + + <main> + <h1 className={styles.title}> + Welcome to <a href="https://nextjs.org">Next.js!</a> + </h1> + + <p className={styles.description}> + Get started by editing <code>pages/index.js</code> + </p> + + <div className={styles.grid}> + <a href="https://nextjs.org/docs" className={styles.card}> + <h3>Documentation →</h3> + <p>Find in-depth information about Next.js features and API.</p> + </a> + + <a href="https://nextjs.org/learn" className={styles.card}> + <h3>Learn →</h3> + <p>Learn about Next.js in an interactive course with quizzes!</p> + </a> + + <a + href="https://github.com/vercel/next.js/tree/canary/examples" + className={styles.card} + > + <h3>Examples →</h3> + <p>Discover and deploy boilerplate example Next.js projects.</p> + </a> + + <a + href="https://vercel.com/import?filter=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app" + className={styles.card} + > + <h3>Deploy →</h3> + <p> + Instantly deploy your Next.js site to a public URL with Vercel. + </p> + </a> + </div> + </main> + + <footer> + <a + href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app" + target="_blank" + rel="noopener noreferrer" + > + Powered by{' '} + <img src="/vercel.svg" alt="Vercel" className={styles.logo} /> + </a> + </footer> + + <style jsx>{` + main { + padding: 5rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + footer { + width: 100%; + height: 100px; + border-top: 1px solid #eaeaea; + display: flex; + justify-content: center; + align-items: center; + } + footer img { + margin-left: 0.5rem; + } + footer a { + display: flex; + justify-content: center; + align-items: center; + text-decoration: none; + color: inherit; + } + code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: + Menlo, + Monaco, + Lucida Console, + Liberation Mono, + DejaVu Sans Mono, + Bitstream Vera Sans Mono, + Courier New, + monospace; + } + `}</style> + + <style jsx global>{` + html, + body { + padding: 0; + margin: 0; + font-family: + -apple-system, + BlinkMacSystemFont, + Segoe UI, + Roboto, + Oxygen, + Ubuntu, + Cantarell, + Fira Sans, + Droid Sans, + Helvetica Neue, + sans-serif; + } + * { + box-sizing: border-box; + } + `}</style> + </div> + ); +} \ No newline at end of file diff --git a/pages/data.js b/pages/data.js new file mode 100644 index 0000000000000000000000000000000000000000..469a1169dc8944bfb48a0479c03a1859aa2fef28 --- /dev/null +++ b/pages/data.js @@ -0,0 +1,74 @@ +export const sculptureList = [{ + name: 'Number One', + artist: 'Marta Colvin Andrade', + description: 'Number one, also known as the lonliest Number', + url: 'https://i.etsystatic.com/36351699/r/il/f2abd8/4058257118/il_570xN.4058257118_jqrj.jpg', + alt: 'Number one, also known as the loniest Number' + }, { + name: 'Number Two', + artist: 'Eduardo Catalano', + description: 'Number Two, the Number that always has a Companion', + url: 'https://image.spreadshirtmedia.net/image-server/v1/products/T1459A839PA4459PT28D191008873W6840H10000/views/1,width=800,height=800,appearanceId=839,backgroundColor=F2F2F2/nummer-2-football-team-baseball-universitaetsbasketball-sticker.jpg', + alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + }, { + name: 'Number Three', + artist: 'John Woodrow Wilson', + description: 'all good things come in threes', + url: 'https://media.istockphoto.com/id/182804498/de/foto/die-zahl-3.jpg?s=612x612&w=0&k=20&c=spUqfmg_ECLEgh-yA54PT4IxVqPjo-IG-VcmsvozGb0=', + alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + }, { + name: 'Number Four', + artist: 'Unknown Artist', + description: 'Four in Japanese is Pronounced the same as Death/Die', + url: 'https://e7.pngegg.com/pngimages/231/185/png-clipart-logo-black-and-white-brand-number-4-angle-white.png', + alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + }, { + name: 'Number Five', + artist: 'Niki de Saint Phalle', + description: 'We have Five Fingers on each hand', + url: 'https://img.freepik.com/premium-psd/number-5_636958-6.jpg', + alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + }, { + name: 'Number Six', + artist: 'Barbara Hepworth', + description: 'Six like the number of chambers in a Revolver', + url: 'https://roflmagnets.com/312-large_default/nummer-6.jpg', + alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + }, { + name: 'Number Seven', + artist: 'Lamidi Olonade Fakeye', + description: "The Lucky Number", + url: 'https://ih1.redbubble.net/image.3277051601.5070/st,small,507x507-pad,600x600,f8f8f8.jpg', + alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + }, { + name: 'Number Eight', + artist: 'Alina Szapocznikow', + description: "an indefenitly drawable number", + url: 'https://cdn-icons-png.flaticon.com/512/10232/10232557.png', + alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + }, { + name: 'Number Nine', + artist: 'Unknown Artist', + description: 'Number of Planets, before Pluto got downgraded', + url: 'https://e7.pngegg.com/pngimages/150/753/png-clipart-9-9.png', + alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + }, { + name: 'Number Ten', + artist: 'Louise Nevelson', + description: 'Total Number of our Fingers', + url: 'https://banner2.cleanpng.com/20180810/osr/5e408d799767ef0433fb1285edb13f6f.webp', + alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + }, { + name: 'Number Eleven', + artist: 'Ranjani Shettar', + description: 'The most Oscar awards won by any film is Eleven (The Lord of the Rings: The Return of the King)', + url: 'https://image.spreadshirtmedia.net/image-server/v1/products/T1459A839PA4459PT28D15213525W9094H10000/views/1,width=800,height=800,appearanceId=839,backgroundColor=F2F2F2/number-11-sticker.jpg', + alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + }, { + name: 'Number Twelve', + artist: 'Taipei Zoo', + description: 'There are Twelve months in a year', + url: 'https://t4.ftcdn.net/jpg/00/89/85/09/360_F_89850913_ttgLJASgMujZ1kpdOKIfVBCm16XH8Zmr.jpg', + alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + }]; + \ No newline at end of file diff --git a/pages/index.js b/pages/index.js new file mode 100644 index 0000000000000000000000000000000000000000..fa70939c3e0df4016206792d600c0eaa51f0bbbd --- /dev/null +++ b/pages/index.js @@ -0,0 +1,49 @@ +import React from 'react'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import EnergyOptionCard from '../components/EnergyOptionCard'; + +/*function StartPage() { + const router = useRouter(); //Macht das man Seite Wechseln Kann + + const handleNavigate = () => { // Geht zur Zweiten Seite + router.push('/2ndPage'); + }; + + return ( + <div> + <h1>Homepage</h1> + <button onClick={handleNavigate}>Zweite Seite</button> + <li> + <img src="https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_1280.jpg"/> + </li> + </div> + ); +}*/ +function StartPage() { + const [energyOptions, setEnergyOptions] = useState([]); + + useEffect(() => { + async function fetchEnergyOptions() { + const res = await fetch('/api/energy-options'); + const data = await res.json(); + if (data.success) { + setEnergyOptions(data.data); + } + } + + fetchEnergyOptions(); + }, []); + + return ( + <div className="home-container"> + <h1>Green Energy Options</h1> + <div className="energy-options-container"> + {energyOptions.map((option, index) => ( + <EnergyOptionCard key={index} {...option} /> + ))} + </div> + </div> + ); +} +export default StartPage; diff --git a/pages/indexBackUp2.js b/pages/indexBackUp2.js new file mode 100644 index 0000000000000000000000000000000000000000..aeaa7ba06b80fe99e660f258c045438ed1cb92e2 --- /dev/null +++ b/pages/indexBackUp2.js @@ -0,0 +1,51 @@ +import { useState } from 'react'; +import { sculptureList } from './data.js'; + +export default function Gallery() { + const [index, setIndex] = useState(0); + + function handleClickfront() { + if (index == 11) { + setIndex(0); + } + else{ + setIndex(index + 1); + } + } + + function handleClickback() { + if (index == 0) { + setIndex(11); + } + else{ + setIndex(index - 1); + } + } + + let sculpture = sculptureList[index]; + return ( + <> + <button onClick={handleClickfront}> + Next + </button> + <button onClick={handleClickback}> + Back + </button> + <h2> + <i>{sculpture.name} </i> + + </h2> + <h3> + ({index + 1} of {sculptureList.length}) + </h3> + <img + src={sculpture.url} + alt={sculpture.alt} + /> + <p> + {sculpture.description} + </p> + </> + ); +} +//by {sculpture.artist} diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000000000000000000000000000000000000..e77448e5b0bdb05cce497eed09d6ab6ca5a49ca3 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,17 @@ +datasource GreenDB { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +model EnergyOption { + id Int @id @default(autoincrement()) + name String + description String + source String + location String + createdAt DateTime @default(now()) +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4965832f2c9b0605eaa189b7c7fb11124d24e48a Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/vercel.svg b/public/vercel.svg new file mode 100644 index 0000000000000000000000000000000000000000..fbf0e25a651c28931b2fe8afa2947e124eebc74f --- /dev/null +++ b/public/vercel.svg @@ -0,0 +1,4 @@ +<svg width="283" height="64" viewBox="0 0 283 64" fill="none" + xmlns="http://www.w3.org/2000/svg"> + <path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/> +</svg> \ No newline at end of file diff --git a/styles/Home.module.css b/styles/Home.module.css new file mode 100644 index 0000000000000000000000000000000000000000..cb4a97622d17466d7a9d07f448dec5eb26f0bcf3 --- /dev/null +++ b/styles/Home.module.css @@ -0,0 +1,92 @@ +.container { + min-height: 100vh; + padding: 0 0.5rem; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.title a { + color: #0070f3; + text-decoration: none; +} + +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} + +.title { + margin: 0 0 1rem; + line-height: 1.15; + font-size: 3.6rem; +} + +.title { + text-align: center; +} + +.title, +.description { + text-align: center; +} + +.description { + line-height: 1.5; + font-size: 1.5rem; +} + +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + + max-width: 800px; + margin-top: 3rem; +} + +.card { + margin: 1rem; + flex-basis: 45%; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: + color 0.15s ease, + border-color 0.15s ease; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h3 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/styles/global.css b/styles/global.css new file mode 100644 index 0000000000000000000000000000000000000000..7ca434a16761a6ac10ddb2235c197ede1edf3066 --- /dev/null +++ b/styles/global.css @@ -0,0 +1,67 @@ +html, +body { + padding: 0; + margin: 0; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + Segoe UI, + Roboto, + Oxygen, + Ubuntu, + Cantarell, + Fira Sans, + Droid Sans, + Helvetica Neue, + sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +} + +img { + max-width: 100%; + height: auto; +} + +.energy-options-container { + display: flex; + flex-wrap: wrap; + justify-content: center; /* Center items horizontally */ + gap: 20px; /* Space between cards */ + margin-top: 20px; +} + +.energy-option-card { + background-color: #c59258; + border-radius: 10px; + padding: 15px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease, background-color 0.3s ease; + cursor: pointer; /* Makes it look like a button */ + width: 250px; /* Set width for each card */ + text-align: left; + display: flex; + flex-direction: column; +} + +.energy-option-card:hover { + transform: scale(1.05); +} + +.energy-option-card h3 { + color: #3733ff; + font-size: 1.5rem; +} + +.energy-option-card p { + font-size: 1rem; + color: rgb(3, 3, 3); +}