generated from lucien/actix-react-template
Compare commits
27 commits
Author | SHA1 | Date | |
---|---|---|---|
1d207b56a6 | |||
6228e839d7 | |||
![]() |
75c29c719a | ||
![]() |
2b71492587 | ||
![]() |
0508ddaa7f | ||
![]() |
b2cb9ca5c8 | ||
![]() |
1e95438b2c | ||
![]() |
0fa1a9b6f3 | ||
![]() |
6405c6db09 | ||
![]() |
f8ffe3e16f | ||
![]() |
d685e00bc3 | ||
![]() |
3f9617549d | ||
![]() |
0e31e90af9 | ||
![]() |
6e77233ac0 | ||
1ec6b1b0da | |||
![]() |
4682f8a61e | ||
b8fa053ca3 | |||
![]() |
53853dcce5 | ||
![]() |
ea2bb7ac3c | ||
![]() |
e1bcb4b022 | ||
![]() |
cbae2746fd | ||
b252122272 | |||
467d560b15 | |||
ac3fc5c391 | |||
d6f2d6cc09 | |||
e42b81539f | |||
ec2322f04c |
19 changed files with 289 additions and 42 deletions
|
@ -12,7 +12,9 @@ pub fn init() -> sqlite::Result<()> {
|
||||||
"CREATE TABLE IF NOT EXISTS articles (
|
"CREATE TABLE IF NOT EXISTS articles (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
title TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
subTitle TEXT,
|
auteur TEXT,
|
||||||
|
edited_at DATE_FORMAT('now', '%YYYY-%mm-%dd'),
|
||||||
|
published_at DATE_FORMAT('now', '%YYYY-%mm-%dd'),
|
||||||
content TEXT NOT NULL
|
content TEXT NOT NULL
|
||||||
)",
|
)",
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod create_db;
|
mod create_db;
|
||||||
use create_db::init;
|
use create_db::init;
|
||||||
|
|
||||||
use actix_web::{App, HttpServer, get, Responder, HttpResponse, http::header::ContentType};
|
use actix_web::{App, web, HttpServer, get, Responder, HttpResponse, http::header::ContentType};
|
||||||
use actix_files::Files;
|
use actix_files::Files;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sqlite::{Connection, State};
|
use sqlite::{Connection, State};
|
||||||
|
@ -11,9 +11,9 @@ use serde::{Serialize, Deserialize};
|
||||||
struct Article {
|
struct Article {
|
||||||
id: i64,
|
id: i64,
|
||||||
title: String,
|
title: String,
|
||||||
auteur: Option<String>,
|
auteur: String,
|
||||||
edited_at: Option<String>,
|
edited_at: String,
|
||||||
published_at: Option<String>,
|
published_at: String,
|
||||||
content: String,
|
content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,13 +31,13 @@ async fn get_articles() -> impl Responder {
|
||||||
while let State::Row = stmt.next().unwrap() {
|
while let State::Row = stmt.next().unwrap() {
|
||||||
let id = stmt.read::<i64, _>(0).unwrap();
|
let id = stmt.read::<i64, _>(0).unwrap();
|
||||||
let title = stmt.read::<String, _>(1).unwrap();
|
let title = stmt.read::<String, _>(1).unwrap();
|
||||||
let content = stmt.read::<String, _>(3).unwrap();
|
let content = stmt.read::<String, _>(5).unwrap();
|
||||||
articles.push(Article {
|
articles.push(Article {
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
auteur: None,
|
auteur: "".to_string(),
|
||||||
edited_at: None,
|
edited_at: "".to_string(),
|
||||||
published_at: None,
|
published_at: "".to_string(),
|
||||||
content
|
content
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,54 @@ async fn get_articles() -> impl Responder {
|
||||||
HttpResponse::Ok().json(articles)
|
HttpResponse::Ok().json(articles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[get("/api/articles/{id}")]
|
||||||
|
async fn get_article(path: web::Path<i64>) -> impl Responder {
|
||||||
|
let id = path.into_inner();
|
||||||
|
|
||||||
|
// Open the database connection
|
||||||
|
let conn = match Connection::open("./data/data.db") {
|
||||||
|
Ok(conn) => conn,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to connect to database: {}", err);
|
||||||
|
return HttpResponse::InternalServerError().body("Failed to connect to database");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the article from the database
|
||||||
|
match fetch_article_by_id(&conn, id) {
|
||||||
|
Ok(Some(article)) => HttpResponse::Ok().json(article),
|
||||||
|
Ok(None) => HttpResponse::NotFound().body(format!("Article with ID {} not found", id)),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Database query error: {}", err);
|
||||||
|
HttpResponse::InternalServerError().body("Database query failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetches an article by its ID from the database.
|
||||||
|
fn fetch_article_by_id(conn: &Connection, id: i64) -> Result<Option<Article>, sqlite::Error> {
|
||||||
|
let mut stmt = conn.prepare(
|
||||||
|
"SELECT id, title, auteur, edited_at, published_at, content
|
||||||
|
FROM articles WHERE id = ?1"
|
||||||
|
)?;
|
||||||
|
stmt.bind((1, id))?;
|
||||||
|
|
||||||
|
let mut article = None;
|
||||||
|
while let State::Row = stmt.next()? {
|
||||||
|
article = Some(Article {
|
||||||
|
id: stmt.read::<i64, _>(0)?,
|
||||||
|
title: stmt.read::<String, _>(1)?,
|
||||||
|
auteur: stmt.read::<String, _>(2)?,
|
||||||
|
edited_at: stmt.read::<String, _>(3)?,
|
||||||
|
published_at: stmt.read::<String, _>(4)?,
|
||||||
|
content: stmt.read::<String, _>(5)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(article)
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/api")]
|
#[get("/api")]
|
||||||
async fn api() -> impl Responder {
|
async fn api() -> impl Responder {
|
||||||
let value = json!({
|
let value = json!({
|
||||||
|
@ -72,7 +120,10 @@ async fn main() -> Result<(), std::io::Error> {
|
||||||
.service(hello)
|
.service(hello)
|
||||||
.service(get_articles)
|
.service(get_articles)
|
||||||
.service(api)
|
.service(api)
|
||||||
|
.service(get_article)
|
||||||
.service(Files::new("/", "public").index_file("index.html"))
|
.service(Files::new("/", "public").index_file("index.html"))
|
||||||
|
.service(Files::new("/game", "public").index_file("index.html"))
|
||||||
|
.service(Files::new("/chaos", "public").index_file("index.html"))
|
||||||
})
|
})
|
||||||
.bind(("0.0.0.0", 2486))?
|
.bind(("0.0.0.0", 2486))?
|
||||||
.run()
|
.run()
|
||||||
|
|
|
@ -3,10 +3,22 @@ services:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: dockerfile
|
dockerfile: dockerfile
|
||||||
container_name: web
|
network: host
|
||||||
|
container_name: nuitdelinfo
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
|
||||||
- 8080:8080
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./back/data:/app/data
|
- ./back/data:/app/data
|
||||||
|
networks:
|
||||||
|
- traefik
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.nuitdelinfo.rule=Host(`nuitdelinfo.leizour.fr`)"
|
||||||
|
- "traefik.http.routers.nuitdelinfo.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.nuitdelinfo.tls=true"
|
||||||
|
- "traefik.http.routers.nuitdelinfo.tls.certresolver=myresolver"
|
||||||
|
- "traefik.http.services.nuitdelinfo.loadbalancer.server.port=2486"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traefik:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@ RUN cargo build --release
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
FROM debian:bookworm-slim
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apt-get update & apt-get install -y extra-runtime-dependencies & rm -rf /var/lib/apt/lists/*
|
RUN apt update && apt install -y libsqlite3-0
|
||||||
COPY --from=front /app/dist /app/public
|
COPY --from=front /app/dist /app/public
|
||||||
COPY --from=back /app/target/release/back /app/back
|
COPY --from=back /app/target/release/back /app/back
|
||||||
EXPOSE 8080
|
EXPOSE 2486
|
||||||
CMD ["/app/back"]
|
CMD ["/app/back"]
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-router": "^7.0.2",
|
"react-router": "^7.0.2",
|
||||||
"react-router-dom": "^6.2.1",
|
|
||||||
"three": "^0.171.0",
|
"three": "^0.171.0",
|
||||||
"three-stdlib": "^2.34.0"
|
"three-stdlib": "^2.34.0",
|
||||||
|
"react-router-dom": "^6.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.15.0",
|
"@eslint/js": "^9.15.0",
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import React from 'react'
|
|
||||||
import { LineBasicMaterial, Line, Group } from 'three'
|
import { LineBasicMaterial, Line, Group } from 'three'
|
||||||
import { useFrame } from '@react-three/fiber'
|
|
||||||
import * as THREE from 'three'
|
import * as THREE from 'three'
|
||||||
|
|
||||||
export default function Axes() {
|
export default function Axes() {
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { Group, Mesh, MeshStandardMaterial, BufferGeometry } from 'three'
|
|
||||||
import { useGLTF } from '@react-three/drei'
|
import { useGLTF } from '@react-three/drei'
|
||||||
|
|
||||||
export default function Character() {
|
export default function Character() {
|
||||||
// import glb file
|
// import glb file
|
||||||
|
|
||||||
// load the glb file in "/models/BASEmodel.glb"
|
// load the glb file in "/models/BASEmodel.glb"
|
||||||
const { nodes, materials, scene } = useGLTF('/models/man.glb')
|
const { scene } = useGLTF('/models/man.glb')
|
||||||
|
|
||||||
// rotate the character
|
// rotate the character
|
||||||
scene.rotation.x = -Math.PI / 2
|
scene.rotation.x = -Math.PI / 2
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
import { Group } from 'three'
|
import { Group } from 'three'
|
||||||
import * as THREE from 'three'
|
import * as THREE from 'three'
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Group } from 'three'
|
|
||||||
import * as THREE from 'three'
|
import * as THREE from 'three'
|
||||||
|
|
||||||
interface MarkerProps {
|
interface MarkerProps {
|
||||||
position: [number, number, number],
|
position: number[],
|
||||||
color: string,
|
color: string,
|
||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Marker({ position, color, onClick }: MarkerProps) {
|
export default function Marker({ position, color, onClick }: MarkerProps) {
|
||||||
|
|
||||||
const [positionState, setPositionState] = React.useState(position)
|
const [positionState, setPositionState] = React.useState(new THREE.Vector3(...position))
|
||||||
|
|
||||||
// Return the marker object
|
// Return the marker object
|
||||||
// return <primitive object={marker} />
|
// return <primitive object={marker} />
|
||||||
return (
|
return (
|
||||||
<mesh position={positionState} rotation={[Math.PI,0,0]} onClick={onClick} onPointerOver={(e) => setPositionState([positionState[0], positionState[1], positionState[2] + 0.1])} onPointerOut={(e) => setPositionState(position)}>
|
<mesh position={positionState} rotation={[Math.PI,0,0]} onClick={onClick} onPointerOver={() => setPositionState(positionState.clone().setZ(positionState.z + 0.1))} onPointerOut={() => setPositionState(new THREE.Vector3(...position))}>
|
||||||
<coneGeometry args={[0.15, 0.6, 6]} />
|
<coneGeometry args={[0.15, 0.6, 6]} />
|
||||||
<meshStandardMaterial color={color} side={THREE.DoubleSide} />
|
<meshStandardMaterial color={color} side={THREE.DoubleSide} />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Water, WaterOptions } from 'three/examples/jsm/objects/Water.js';
|
import { Water, WaterOptions } from 'three/examples/jsm/objects/Water.js';
|
||||||
import { WaterMesh, WaterMeshOptions } from 'three/examples/jsm/objects/Water2Mesh.js';
|
|
||||||
|
|
||||||
const Ocean: React.FC = () => {
|
const Ocean: React.FC = () => {
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReactNode, MouseEventHandler } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
interface ButtonProps {
|
interface ButtonProps {
|
||||||
color: 'primary' | 'secondary';
|
color: 'primary' | 'secondary';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Button from "./Button";
|
|
||||||
import ButtonLink from "./ButtonLink";
|
|
||||||
import NavBar from "./NavBar";
|
import NavBar from "./NavBar";
|
||||||
|
import { Link } from "react-router";
|
||||||
|
|
||||||
export default function FstSection () {
|
export default function FstSection () {
|
||||||
return (
|
return (
|
||||||
|
@ -32,8 +32,55 @@ export default function FstSection () {
|
||||||
|
|
||||||
>Help us to save our oceans</h1><br />
|
>Help us to save our oceans</h1><br />
|
||||||
<div style={{display:"flex", justifyContent: "center", gap: "20px"}}>
|
<div style={{display:"flex", justifyContent: "center", gap: "20px"}}>
|
||||||
<Button color="primary" children={"Aller au jeu"} url="/game" />
|
{/* <Button color="primary" children={"Aller au jeu"} url="/game" />
|
||||||
<Button color="secondary" children={"Lire les articles"} url="/" />
|
<Button color="secondary" children={"Lire les articles"} url="/" /> */}
|
||||||
|
<Link to="/game" style={{
|
||||||
|
backgroundColor: 'var(--color-yellow)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
borderWidth: '0',
|
||||||
|
color: 'var(--color-black)',
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'inline-block',
|
||||||
|
fontFamily: '"Haas Grot Text R Web", "Helvetica Neue", Helvetica, Arial, sans-serif',
|
||||||
|
fontSize: '20px',
|
||||||
|
fontWeight: '500',
|
||||||
|
lineHeight: '20px',
|
||||||
|
listStyle: 'none',
|
||||||
|
margin: '0',
|
||||||
|
padding: '10px 12px',
|
||||||
|
textAlign: 'center',
|
||||||
|
transition: 'all 200ms',
|
||||||
|
verticalAlign: 'baseline',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
userSelect: 'none',
|
||||||
|
WebkitUserSelect: 'none',
|
||||||
|
touchAction: 'manipulation',
|
||||||
|
textDecoration: 'none',
|
||||||
|
}}>Aller au jeu</Link>
|
||||||
|
<Link to="/articles" style={{
|
||||||
|
backgroundColor: 'var(--color-darkblue)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
borderWidth: '0',
|
||||||
|
color: 'var(--color-white)',
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'inline-block',
|
||||||
|
fontFamily: '"Haas Grot Text R Web", "Helvetica Neue", Helvetica, Arial, sans-serif',
|
||||||
|
fontSize: '20px',
|
||||||
|
fontWeight: '500',
|
||||||
|
lineHeight: '20px',
|
||||||
|
listStyle: 'none',
|
||||||
|
margin: '0',
|
||||||
|
padding: '10px 12px',
|
||||||
|
textAlign: 'center',
|
||||||
|
transition: 'all 200ms',
|
||||||
|
verticalAlign: 'baseline',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
userSelect: 'none',
|
||||||
|
WebkitUserSelect: 'none',
|
||||||
|
touchAction: 'manipulation',
|
||||||
|
textDecoration: 'none',
|
||||||
|
}}>Lire les articles</Link>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div></div>
|
</div></div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import LogoButton from '../components/LogoButton.tsx'
|
import { Link } from 'react-router';
|
||||||
import ClickableLink from './ClickableLink.tsx';
|
|
||||||
import RoundButton from './RoundButton.tsx';
|
import RoundButton from './RoundButton.tsx';
|
||||||
|
|
||||||
export default function NavBar(){
|
export default function NavBar(){
|
||||||
|
@ -7,13 +6,15 @@ export default function NavBar(){
|
||||||
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0.5em 1em"}}>
|
<nav style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0.5em 1em"}}>
|
||||||
<div style={{ display : "flex", alignItems: "center", flexDirection: "row"}}>
|
<div style={{ display : "flex", alignItems: "center", flexDirection: "row"}}>
|
||||||
{/* <LogoButton url="/" logo = "https://archlinux.org/static/hetzner_logo.41114a37d25f.png"/> */}
|
{/* <LogoButton url="/" logo = "https://archlinux.org/static/hetzner_logo.41114a37d25f.png"/> */}
|
||||||
<span class="material-symbols-outlined"
|
<span className="material-symbols-outlined"
|
||||||
style={{fontSize: "4em", color: "white", margin: "0.5em"}}>sailing</span>
|
style={{fontSize: "4em", color: "white", margin: "0.5em"}}>sailing</span>
|
||||||
<ClickableLink url="/" text = "Accueil" />
|
<Link to="/" style={{ textDecoration: "none", color: "white", fontSize: "1.5em", margin: "0.5em", fontFamily: '"Haas Grot Text R Web", "Helvetica Neue", Helvetica, Arial, sans-serif'}}>Home</Link>
|
||||||
<ClickableLink url="/game" text = "Jeu" />
|
<Link to="/game" style={{ textDecoration: "none", color: "white", fontSize: "1.5em", margin: "0.5em", fontFamily: '"Haas Grot Text R Web", "Helvetica Neue", Helvetica, Arial, sans-serif'}}>Game</Link>
|
||||||
|
<Link to="/articles" style={{ textDecoration: "none", color: "white", fontSize: "1.5em", margin: "0.5em", fontFamily: '"Haas Grot Text R Web", "Helvetica Neue", Helvetica, Arial, sans-serif'}}>Articles</Link>
|
||||||
|
<Link to="/chaos" style={{ textDecoration: "none", color: "white", fontSize: "1.5em", margin: "0.5em", fontFamily: '"Haas Grot Text R Web", "Helvetica Neue", Helvetica, Arial, sans-serif'}}>Le Chaos</Link>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display : "flex", alignItems: "center", flexDirection: "row"}}>
|
<div style={{ display : "flex", alignItems: "center", flexDirection: "row"}}>
|
||||||
<RoundButton url="https://archlinux.org" bgcolor="var(--color-white)" text="?"/>
|
<RoundButton url="https://www.apple.com/macos/macos-sequoia/" bgcolor="var(--color-white)" text="?"/>
|
||||||
</div>
|
</div>
|
||||||
</nav>);
|
</nav>);
|
||||||
}
|
}
|
16
front/src/components/chaos/MonInput.tsx
Normal file
16
front/src/components/chaos/MonInput.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
//import { useState } from "react";
|
||||||
|
|
||||||
|
interface MonInputProps {
|
||||||
|
text: string;
|
||||||
|
new_focus: () => void;
|
||||||
|
police: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MonInput({text, new_focus, police}: MonInputProps) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<input readOnly value={text} onFocus={new_focus} style={{fontFamily: police,width:1000}}></input>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
26
front/src/components/chaos/monButton.tsx
Normal file
26
front/src/components/chaos/monButton.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
interface MonButtonProps {
|
||||||
|
letter: string;
|
||||||
|
changetext: (arg0: string) => void;
|
||||||
|
sizeFrontw: number;
|
||||||
|
sizeFronth: number;
|
||||||
|
rdmFront: () => void;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default function MonButton({letter,changetext,sizeFrontw,sizeFronth,rdmFront,color}: MonButtonProps) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function clicked() {rdmFront();
|
||||||
|
changetext(letter)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button className="key" onClick={clicked} style={{width:sizeFrontw,height:sizeFronth,background:color}}>{letter}</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
12
front/src/components/chaos/style.css
Normal file
12
front/src/components/chaos/style.css
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#keys {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto 1fr;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.key {
|
||||||
|
font-size: 10px;
|
||||||
|
border: solid black;
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ import { BrowserRouter, Route, Routes } from "react-router";
|
||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import MainPage from "./pages/MainPage.tsx";
|
import MainPage from "./pages/MainPage.tsx";
|
||||||
import GamePage from "./pages/GamePage.tsx";
|
import GamePage from "./pages/GamePage.tsx";
|
||||||
|
import ChaosPage from "./pages/ChaosPage.tsx";
|
||||||
|
|
||||||
import ArticlePage from "./pages/ArticlePage.tsx";
|
import ArticlePage from "./pages/ArticlePage.tsx";
|
||||||
import './index.css'
|
import './index.css'
|
||||||
|
|
||||||
|
@ -12,6 +14,7 @@ createRoot(document.getElementById('root')!).render(
|
||||||
<Route path="/" element={<MainPage />} />
|
<Route path="/" element={<MainPage />} />
|
||||||
// Game page
|
// Game page
|
||||||
<Route path="/game" element={<GamePage />} />
|
<Route path="/game" element={<GamePage />} />
|
||||||
|
<Route path="/chaos" element={<ChaosPage />} />
|
||||||
// Article page (dynamic route)
|
// Article page (dynamic route)
|
||||||
<Route path="/article/:id" element={<ArticlePage />} />
|
<Route path="/article/:id" element={<ArticlePage />} />
|
||||||
// Not found
|
// Not found
|
||||||
|
|
86
front/src/pages/ChaosPage.tsx
Normal file
86
front/src/pages/ChaosPage.tsx
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
import MonButton from "../components/chaos/monButton";
|
||||||
|
import MonInput from "../components/chaos/MonInput";
|
||||||
|
import "../components/chaos/style.css"
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
|
||||||
|
export default function ChaosPage(){
|
||||||
|
|
||||||
|
const [array_letter,setArray_letter]=useState(["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"," ","!"]);
|
||||||
|
|
||||||
|
const [sizeFrontw,setSizeFrontw] = useState(16)
|
||||||
|
const [sizeFronth,setSizeFronth] = useState(20)
|
||||||
|
const [color,setColor] = useState("#ffffff")
|
||||||
|
|
||||||
|
function randomFront(){setSizeFronth(Math.floor(Math.random() * (1000)));
|
||||||
|
setSizeFrontw(Math.floor(Math.random() * (1000)));
|
||||||
|
setColor(`#${Math.floor(Math.random() * 16777215).toString(16)}`)}
|
||||||
|
|
||||||
|
function shuffleArray(arr: string[]) {
|
||||||
|
for (let i = arr.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1)); // Choisir un index aléatoire
|
||||||
|
[arr[i], arr[j]] = [arr[j], arr[i]]; // Échanger les éléments
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// console.log(shuffledArray); // Affiche un tableau mélangé
|
||||||
|
|
||||||
|
|
||||||
|
const [entry1,setEntry1] = useState("")
|
||||||
|
function E1(ent:string) {
|
||||||
|
setEntry1(entry1+ent);
|
||||||
|
}
|
||||||
|
const [connarddefocus,setFocus] = useState(()=>E1)
|
||||||
|
|
||||||
|
const [entry2,setEntry2] = useState("")
|
||||||
|
function E2(ent:string) {
|
||||||
|
setEntry2(entry2+ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeFocus(E: (ent:string)=>void) {
|
||||||
|
setArray_letter(shuffleArray(array_letter));
|
||||||
|
setFocus(()=>E);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [entry3,setEntry3] = useState("")
|
||||||
|
function E3(ent:string) {
|
||||||
|
setEntry3(entry3+ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [tel,setTel] = useState(0)
|
||||||
|
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<h1>Chaos Page</h1>
|
||||||
|
<p>Quel est votre nom ?</p>
|
||||||
|
<MonInput text={entry1} new_focus={()=>changeFocus(E1)} police={""}/>
|
||||||
|
<p>Quel adjectif désigne le mieux Xi Junpin ?</p>
|
||||||
|
<MonInput text={entry2} new_focus={()=>changeFocus(E2)} police={""}/>
|
||||||
|
<p>Combien font 1+1 ?</p>
|
||||||
|
<MonInput text={entry3} new_focus={()=>changeFocus(E3)} police={"Wingdings"}/>
|
||||||
|
<div id = "keys">
|
||||||
|
{array_letter.map((letter) => {return <MonButton
|
||||||
|
letter={letter}
|
||||||
|
changetext={connarddefocus}
|
||||||
|
sizeFrontw={sizeFrontw}
|
||||||
|
sizeFronth={sizeFronth}
|
||||||
|
rdmFront={randomFront}
|
||||||
|
color={color}/> })}
|
||||||
|
</div>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Formulaire super mega bien</legend>
|
||||||
|
<input type="text" placeholder="nom"/>
|
||||||
|
<input type="text" placeholder="prenom"/>
|
||||||
|
<input type="text" placeholder="email"/>
|
||||||
|
<input type="text" placeholder="mdp"/>
|
||||||
|
<input type="text" placeholder="mdp2"/>
|
||||||
|
<label htmlFor="phone">phone : {tel}</label>
|
||||||
|
<input type="range" min="0" max="9999999999" step="1" name="phone" id="phone" value={tel} onChange={(e)=>setTel(parseInt(e.target.value))}/>
|
||||||
|
<input type="submit" value="envoyer"/>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
import { Canvas } from "@react-three/fiber";
|
import { Canvas } from "@react-three/fiber";
|
||||||
import { OrbitControls, PerspectiveCamera, Sky } from "@react-three/drei";
|
import { OrbitControls, PerspectiveCamera, Sky } from "@react-three/drei";
|
||||||
import * as THREE from "three";
|
import { useEffect, useState } from "react";
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
|
||||||
import Ocean from "../components/3d/Ocean";
|
import Ocean from "../components/3d/Ocean";
|
||||||
import Axes from "../components/3d/Axes";
|
|
||||||
import Character from "../components/3d/Character";
|
import Character from "../components/3d/Character";
|
||||||
import Floor from "../components/3d/Floor";
|
import Floor from "../components/3d/Floor";
|
||||||
import Marker from "../components/3d/Marker";
|
import Marker from "../components/3d/Marker";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue