This commit is contained in:
Philippe Torrel
2026-08-26 12:56:36 +02:00
parent c781b8c0bf
commit 7661c951ad
20 changed files with 395 additions and 16 deletions

View File

@@ -8,11 +8,13 @@
"name": "react-app",
"version": "0.0.0",
"dependencies": {
"@splidejs/react-splide": "^0.7.12",
"axios": "^1.19.0",
"bootstrap": "^5.3.8",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-icons": "^5.7.0"
"react-icons": "^5.7.0",
"react-router-dom": "^7.18.2"
},
"devDependencies": {
"@types/react": "^19.2.18",
@@ -984,6 +986,21 @@
"dev": true,
"license": "MIT"
},
"node_modules/@splidejs/react-splide": {
"version": "0.7.12",
"resolved": "https://registry.npmjs.org/@splidejs/react-splide/-/react-splide-0.7.12.tgz",
"integrity": "sha512-UfXH+j47jsMc4x5HA/aOwuuHPqn6y9+ZTNYPWDRD8iLKvIVMZlzq2unjUEvyDAU+TTVPZOXkG2Ojeoz0P4AkZw==",
"license": "MIT",
"dependencies": {
"@splidejs/splide": "^4.1.3"
}
},
"node_modules/@splidejs/splide": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@splidejs/splide/-/splide-4.1.4.tgz",
"integrity": "sha512-5I30evTJcAJQXt6vJ26g2xEkG+l1nXcpEw4xpKh0/FWQ8ozmAeTbtniVtVmz2sH1Es3vgfC4SS8B2X4o5JMptA==",
"license": "MIT"
},
"node_modules/@types/react": {
"version": "19.2.18",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
@@ -1136,6 +1153,19 @@
"node": ">= 0.8"
}
},
"node_modules/cookie": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
"integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -1932,6 +1962,44 @@
"react": "*"
}
},
"node_modules/react-router": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.2.tgz",
"integrity": "sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
"set-cookie-parser": "^2.6.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
}
},
"node_modules/react-router-dom": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.2.tgz",
"integrity": "sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==",
"license": "MIT",
"dependencies": {
"react-router": "7.18.2"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
},
"node_modules/readdirp": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz",
@@ -2375,6 +2443,12 @@
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
"license": "MIT"
},
"node_modules/set-cookie-parser": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
"license": "MIT"
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",

View File

@@ -10,11 +10,13 @@
"preview": "vite preview"
},
"dependencies": {
"@splidejs/react-splide": "^0.7.12",
"axios": "^1.19.0",
"bootstrap": "^5.3.8",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-icons": "^5.7.0"
"react-icons": "^5.7.0",
"react-router-dom": "^7.18.2"
},
"devDependencies": {
"@types/react": "^19.2.18",

View File

@@ -1,5 +1,7 @@
import FooterMain from './components/footers/FooterMain';
import HeaderMain from './components/headers/HeaderMain';
import NavMain from './components/navs/NavMain';
import Router from './routes/Router';
function App(props) {
// const { } = props;
@@ -7,8 +9,9 @@ function App(props) {
return (
<>
<HeaderMain />
<main>
<p>Hello</p>
<NavMain />
<main id="main">
<Router />
</main>
<FooterMain />
</>

View File

@@ -1,3 +1,5 @@
import NavSocial from '../navs/NavSocial';
const FooterMain = (props) => {
// const { } = props;
@@ -35,7 +37,7 @@ const FooterMain = (props) => {
<div className="col-12 col-md-4">
<div className="box">
<h2>Social Media</h2>
{/* social media icons */}
<NavSocial />
</div>
</div>
</div>

View File

@@ -1,8 +1,16 @@
import LogoMain from '../logos/LogoMain';
import SliderSplide from '../sliders/SliderSplide';
const HeaderMain = () => {
const images = [
{ path: '/img/slides/slide-01.jpg', title: 'Classroom' },
{ path: '/img/slides/slide-02.jpg', title: 'Mountains' },
{ path: '/img/slides/slide-03.jpg', title: 'Canyons' },
];
return (
<header className="m-header-main header-main">
<SliderSplide images={images} />
<div className="content-box">
<LogoMain />
</div>

View File

@@ -0,0 +1,57 @@
import { NavLink } from 'react-router-dom';
const NavMain = () => {
return (
<nav className="m-nav-main nav-main navbar navbar-expand-lg bg-light" data-bs-theme="light">
<div className="container-fluid">
<button
className="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNav"
aria-controls="navbarNav"
aria-expanded="false"
aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item">
<NavLink className="nav-link" to="/">
Home
</NavLink>
</li>
<li className="nav-item dropdown">
<NavLink
className="nav-link dropdown-toggle"
to="/projects"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false">
Projects
</NavLink>
<ul className="dropdown-menu">
<li>
<NavLink className="dropdown-item" to="/projects/">
Project 1
</NavLink>
</li>
</ul>
</li>
<li className="nav-item">
<NavLink className="nav-link" to="/about">
About
</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to="/contact">
Contact
</NavLink>
</li>
</ul>
</div>
</div>
</nav>
);
};
export default NavMain;

View File

@@ -0,0 +1,33 @@
import { FaInstagram, FaXTwitter, FaYoutube, FaMeta } from 'react-icons/fa6';
const NavSocial = (props) => {
// const { } = props;
return (
<nav className="m-nav-social nav-social">
<ul className="list">
<li>
<a href="#" aria-label="X (Twitter)">
<FaXTwitter />
</a>
</li>
<li>
<a href="#" aria-label="Youtube">
<FaYoutube />
</a>
</li>
<li>
<a href="#" aria-label="Meta">
<FaMeta />
</a>
</li>
<li>
<a href="#" aria-label="Instagram">
<FaInstagram />
</a>
</li>
</ul>
</nav>
);
};
export default NavSocial;

View File

@@ -0,0 +1,33 @@
import { Splide, SplideSlide } from '@splidejs/react-splide';
const SliderSplide = (props) => {
const {
images = [],
label = 'Slides',
options = {
rewind: true,
height: '100%',
autoplay: true,
speed: 800,
type: 'fade',
},
} = props;
return (
<>
{images.length > 0 && (
<div className="m-slider-splide slider-splide">
<Splide aria-label={label} options={options}>
{images.map(({ path, title }, idx) => (
// <SplideSlide key={`splide-slide-${idx}`} style={{ backgroundImage: `url(${path})` }}>
<SplideSlide key={`splide-slide-${idx}`} style={{ backgroundImage: `url(${path})` }}>
<img src={path} alt={title} />
</SplideSlide>
))}
</Splide>
</div>
)}
</>
);
};
export default SliderSplide;

View File

@@ -1,13 +1,18 @@
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
// eigene separate Gestaltung mit main.scss (beinhaltet boostrap)
import './styles/main.scss';
import 'bootstrap'; // bootstrap JS wird über esbuild aus node_modules ausgelesen und eingebunden (bundled)
import App from './App.jsx';
createRoot(document.getElementById('root')).render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>,
);

View File

@@ -0,0 +1,13 @@
const About = (props) => {
// const { } = props;
return (
<div className="page page-about">
<div className="container py-3">
<h1>About</h1>
<p>Welcome to the Single-Page-Application (SPA) with React. This is the About page.</p>
</div>
</div>
);
};
export default About;

View File

@@ -0,0 +1,16 @@
const Contact = (props) => {
// const { } = props;
return (
<div className="page page-contact">
<div className="container py-3">
<h1>Contact</h1>
<p>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Iste suscipit eos autem iure soluta laboriosam in
perferendis atque explicabo, possimus eius? Ea magnam sed atque exercitationem officiis ipsum, deserunt iste.
</p>
</div>
</div>
);
};
export default Contact;

View File

@@ -0,0 +1,13 @@
const Home = (props) => {
// const { } = props;
return (
<div className="page page-home">
<div className="container py-3">
<h1>Hello, Spa!</h1>
<p>Welcome to the Single-Page-Application (SPA) with React. This is the Home page.</p>
</div>
</div>
);
};
export default Home;

View File

@@ -0,0 +1,17 @@
import { Route, Routes } from 'react-router-dom';
import Home from '../pages/Home';
import About from '../pages/About';
import Contact from '../pages/Contact';
const Router = (props) => {
// const { } = props;
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
);
};
export default Router;

View File

@@ -10,3 +10,5 @@ $color-white: white; // falls weiß geändert wird z.B.: #f8f8f8
$color-dark-blue: #283e4a;
$linear-gradient-dark: linear-gradient(180deg, rgba(40, 62, 74, 1) 0%, rgba(24, 32, 38, 1) 100%);
$color-link: $color-2;

View File

@@ -44,3 +44,8 @@ h6 {
font-family: $font-headline;
font-weight: 700;
}
a {
color: $color-link;
text-decoration: none;
}

View File

@@ -1,4 +1,4 @@
// @import 'splide-4.1.4/themes/default/index';
// @import 'splide-4.1.4/core/index';
@import 'splide-4.1.4/themes/default/index';
@import 'splide-4.1.4/core/index';
// @import 'toastify-1.12/toastify';

View File

@@ -4,6 +4,12 @@
padding: 3rem 0;
[class^='col'] {
color: $color-white;
display: flex;
justify-content: center;
@include media-breakpoint-up(md) {
justify-content: flex-start;
}
h2,
h3,
h4,
@@ -13,6 +19,18 @@
padding: 0.5rem 0;
margin-bottom: 1rem;
letter-spacing: 2px;
text-align: center;
}
}
@include media-breakpoint-up(sm) {
h1,
h2,
h3,
h4,
h5,
h6 {
text-align: left;
}
}
@@ -20,9 +38,12 @@
flex-direction: column;
> div {
&:nth-child(1) {
order: 2;
order: 3;
}
&:nth-child(2) {
order: 2;
}
&:nth-child(3) {
order: 1;
}
}
@@ -31,7 +52,7 @@
// @media (min-width:576px) {
@include media-breakpoint-up(sm) {
.row {
flex-direction: row;
flex-direction: row-reverse;
}
}
}

View File

@@ -41,6 +41,11 @@
overflow: hidden;
.splide__track {
height: 100%;
.splide__slide img {
object-fit: cover;
width: 100%;
height: 100%;
}
.splider-content {
&::after {
content: '';
@@ -55,11 +60,6 @@
height: 100%;
padding: 0;
img {
object-fit: cover;
width: 100%;
height: 100%;
}
}
}
}

View File

@@ -3,6 +3,7 @@
@import 'header-main';
// @import 'inputAmount';
@import 'logo-main';
@import 'nav-menu';
// @import 'nav-menu';
@import 'nav-social';
// @import 'menu-main';
// @import 'product-manager';

View File

@@ -0,0 +1,74 @@
@use 'sass:color';
.nav-social {
ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
justify-content: flex-start;
align-items: center;
li {
a {
color: $color-white;
display: inline-block;
padding: 0.5rem;
margin: 3px;
background-color: color.scale($color-dark-blue, $lightness: 10%);
// background-color: lighten($color-dark-blue, 5%); // deprecated
border-radius: 50%;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
transition: all 0.4s ease-out;
&:hover,
&:focus {
background-color: color.scale($color-dark-blue, $lightness: 20%);
}
&[aria-label='Youtube'] {
&:hover,
&:focus {
background-color: #f00;
}
}
&[aria-label='Meta'] {
&:hover,
&:focus {
background-color: #0064e0;
}
}
&[aria-label^='X '] {
&:hover,
&:focus {
background-color: #000;
}
}
&[aria-label^='X '] {
&:hover,
&:focus {
background-color: #000;
}
}
&[aria-label^='Instagram'] {
&:hover,
&:focus {
// background: linear-gradient(
// 9deg,
// rgba(254, 218, 117, 1) 10%,
// rgba(250, 126, 30, 1) 30%,
// rgba(239, 100, 57, 1) 43%,
// rgba(214, 41, 118, 1) 55%,
// rgba(150, 47, 191, 1) 67%,
// rgba(79, 91, 213, 1) 81%
// );
background-color: #405de6;
}
}
}
}
}
}