fixed dup led pin and add rgb led

This commit is contained in:
Nomi Nonsense (Nonszy) 2024-03-07 19:30:43 +07:00
parent b46c8e40f0
commit ae271aeecf
12 changed files with 402 additions and 62 deletions

View File

@ -0,0 +1,33 @@
import { ReactNode } from "react";
interface ControlSectionProps {
title: string;
description?: string;
id?: string;
stack: ReactNode;
colSpan?: number;
stackType?: 'grid' | 'flex'
}
export default function ControlSection ({
title,
description,
id,
stack
}: ControlSectionProps) {
return (
<div className="container py-16" id={id}>
<div className="container-grid items-center relative">
<div className={`col-span-6`}>
<h2 className="text-4xl font-poppins font-bold leading-normal mb-4">
{title}
</h2>
<p>{description}</p>
<div className={`flex flex-wrap gap-6`}>
{stack}
</div>
</div>
</div>
</div>
)
}

View File

@ -1,4 +1,4 @@
import React, { ReactNode } from "react"; import { ReactNode } from "react";
import BackroundImg from "../assets/img/background.png"; import BackroundImg from "../assets/img/background.png";
export default function MainBody({ children }: { children?: ReactNode }) { export default function MainBody({ children }: { children?: ReactNode }) {

View File

@ -0,0 +1,38 @@
import { ChangeEventHandler, HTMLInputTypeAttribute, useRef } from "react";
interface EvoInputProps {
className?: string;
name: string;
value: string;
type?: HTMLInputTypeAttribute
onChange?: ChangeEventHandler<HTMLInputElement>
}
export default function EvoInput ({
className,
name,
value,
type,
onChange
}: EvoInputProps) {
const labelRef = useRef<HTMLInputElement | null>(null);
const handleClick = () => {
labelRef.current?.focus();
}
return (
<label className={`flex cursor-pointer bg-finn border border-border rounded-lg ${className}`} onClick={handleClick}>
<div className="flex-1 w-1/2 p-2">{name}</div>
<input
className="flex-1 w-1/2 h-full p-2 text-center bg-transparent"
type={type}
name=""
id=""
value={value}
ref={labelRef}
onChange={onChange}
/>
</label>
)
}

View File

@ -2,27 +2,53 @@ import { ChangeEventHandler, FormEventHandler, MouseEventHandler } from "react";
import Switch from "./Switch"; import Switch from "./Switch";
interface PinBoxProps { interface PinBoxProps {
className?: string;
value: number | string; value: number | string;
state: boolean; state: boolean;
onValueChange?: ChangeEventHandler<HTMLInputElement | null> onValueChange?: ChangeEventHandler<HTMLInputElement | null>;
onStateChange?: FormEventHandler<HTMLButtonElement | null> onStateChange?: FormEventHandler<HTMLButtonElement | null>;
onDelete?: FormEventHandler<HTMLButtonElement | null>;
minusBtn?: boolean;
} }
function Add ({ onClick }: { onClick?: MouseEventHandler<HTMLButtonElement> }) { function Add ({
className,
onClick
}: {
className?: string,
onClick?: MouseEventHandler<HTMLButtonElement>
}) {
return ( return (
<button className="bg-finn hover:bg-secondary transition border border-border rounded-lg flex items-center justify-center h-36" onClick={onClick}> <button className={`bg-finn hover:bg-secondary transition border border-border rounded-lg flex items-center justify-center h-36 ${className}`} onClick={onClick}>
<i className="bi bi-plus text-border text-7xl"></i> <i className="bi bi-plus text-border text-7xl"></i>
</button> </button>
) )
} }
function PinBox ({ value, state, onValueChange, onStateChange }: PinBoxProps) { function PinBox ({
className,
value,
state,
onValueChange,
onStateChange,
onDelete,
minusBtn
}: PinBoxProps) {
return ( return (
<div className="flex flex-col gap-3 animate-fade-in"> <div className={`flex flex-col gap-3 animate-fade-in ${className}`}>
<div className="bg-secondary border border-border rounded-lg flex flex-col h-36 animate-size-in"> {minusBtn && <button
<div className="font-roboto-mono py-4 text-center">Pin</div> className="border bg-transparent ms-auto hover:bg-secondary border-border rounded px-2"
onClick={onDelete}
>
<i className="bi bi-dash"></i>
</button>}
<div className="bg-secondary border border-border rounded-lg flex flex-col h-36 animate-size-in relative">
<div className="font-roboto-mono py-4 text-center">
Pin
</div>
<input <input
className="flex-grow bg-transparent border-none text-center text-3xl font-roboto-mono" className="flex-grow bg-transparent pb-6 border-none text-center text-3xl font-roboto-mono"
type="number" type="number"
name="pinbox" name="pinbox"
id="" id=""

View File

@ -1,56 +1,53 @@
import { useState } from "react";
import PinBox from "../forms/PinBox"; import PinBox from "../forms/PinBox";
import { PinState } from "../../types/board";
import { useLed } from "../../hooks"; import { useLed } from "../../hooks";
import ControlSection from "../ControlSection";
function ControlLED () { function ControlLED () {
const { addLed, getLed, leds, removeLed, setLed, setLedPin } = useLed(); const { addLed, leds, removeLed, setLed, setLedPin } = useLed();
const handleAdd = (): void => { const handleAdd = (): void => {
let anopin = 13; let anopin = 13;
for (let i = 0; i < leds.length; i++) { for (let i = 0; i < leds.length; i++) {
// console.log(leds[i].pin != anopin, leds[i].pin, anopin); if (leds.filter(led => led.pin == anopin).length > 0) {
if (leds[i].pin != anopin) break; anopin--;
anopin--; }
else break;
} }
addLed(anopin, false); addLed(anopin, false);
} }
return ( return (
<div className="container py-16"> <ControlSection
<div className="container-grid items-center relative"> title="LED"
<div className="col-span-6"> id="led"
<h2 className="text-4xl font-poppins font-bold leading-normal mb-4"> stack={(<>
LED {leds.map((led, i) => (
</h2> <PinBox
<div className="grid grid-cols-6 gap-6"> className="w-36"
{leds.map((led, i) => ( key={i}
<PinBox minusBtn={true}
key={i} value={led.pin}
value={led.pin} state={led.state}
state={led.state} onValueChange={(e) => {
onValueChange={(e) => { const pin = e.target.value;
const pin = e.target.value; setLedPin(i, pin);
if (leds.filter(led => led.pin == pin).length > 0) { }}
alert(`Pin ${pin} is already use`); onStateChange={() => {
return; const state = !led.state;
} setLed(led.pin, state);
setLedPin(led.pin, pin); }}
}} onDelete={() => {
onStateChange={() => { removeLed(i);
const state = !led.state; }}
setLed(led.pin, state); />
}} ))}
/> {leds.length < 14 && <PinBox.Add
))} className="w-36 mt-10"
{leds.length < 14 && <PinBox.Add onClick={handleAdd}
onClick={handleAdd} />}
/>} </>)}
</div> />
</div>
</div>
</div>
) )
} }

View File

@ -0,0 +1,174 @@
import { useRgbLed } from "../../hooks";
import { ChannelPinState, PinState } from "../../types/board";
import EvoInput from "../forms/EvoInput";
import Switch from "../forms/Switch";
import { MouseEventHandler, useEffect, useState } from "react";
interface HorizontalBarProps {
pinState: ChannelPinState;
onUpdate?: (pin: ChannelPinState) => void;
onDelete?: () => void
}
function HorizontalBar ({ pinState, onUpdate, onDelete }: HorizontalBarProps) {
const [red, setRed] = useState<PinState>({
pin: pinState.red.pin.toString(),
state: pinState.red.state
});
const [green, setGreen] = useState<PinState>({
pin: pinState.green.pin.toString(),
state: pinState.green.state
});
const [blue, setBlue] = useState<PinState>({
pin: pinState.blue.pin.toString(),
state: pinState.blue.state
});
useEffect(() => {
if (onUpdate) onUpdate({red, green, blue});
}, [red, green, blue])
return (
<div className="flex flex-col col-span-3 gap-2 animate-fade-in">
<button className="ms-auto bg-finn border border-border rounded-lg px-5" onClick={onDelete}>
<i className="bi bi-dash text-xl"></i>
</button>
<div className="bg-secondary animate-size-in rounded-lg border border-border p-4 flex gap-3">
<div className="flex-1 text-center flex flex-col gap-3">
<div className="text-[#FF4444]">Red</div>
<EvoInput
name="pin"
value={red.pin.toString()}
type="number"
onChange={(e) => {
setRed({
pin: e.target.value,
state: red.state
});
}}
/>
<Switch
state={red.state}
onChange={() => {
setRed({
pin: red.pin,
state: !red.state
})
}}
/>
</div>
<div className="flex-1 text-center flex flex-col gap-3">
<div className="text-[#48FF44]">Green</div>
<EvoInput
name="pin"
value={green.pin.toString()}
type="number"
onChange={(e) => {
setGreen({
pin: e.target.value,
state: green.state
});
}}
/>
<Switch
state={green.state}
onChange={() => {
setGreen({
pin: green.pin,
state: !green.state
})
}}
/>
</div>
<div className="flex-1 text-center flex flex-col gap-3">
<div className="text-[#4844FF]">Blue</div>
<EvoInput
name="pin"
value={blue.pin.toString()}
type="number"
onChange={(e) => {
setBlue({
pin: e.target.value,
state: blue.state
});
}}
/>
<Switch
state={blue.state}
onChange={() => {
setBlue({
pin: blue.pin,
state: !blue.state
})
}}
/>
</div>
</div>
</div>
)
}
function HorizontalBarPlus ({ onClick }: { onClick?: MouseEventHandler<HTMLButtonElement> }) {
return (
<button
className="bg-finn hover:bg-secondary transition col-span-3 rounded-lg border border-border flex items-center justify-center mt-10"
onClick={onClick}
>
<i className="bi bi-plus text-6xl text-border"></i>
</button>
)
}
function ControlRgbLed () {
const { addLed, rgbLed, removeLed, setLed } = useRgbLed();
const handleAdd = (): void => {
addLed({
red: {
pin: 13,
state: false
},
green: {
pin: 12,
state: false
},
blue: {
pin: 11,
state: false
}
})
}
return (
<div className="container py-16" id="rgb-led">
<div className="container-grid items-center relative">
<div className={`col-span-8`}>
<h2 className="text-4xl font-poppins font-bold leading-normal mb-4">
RGB LED
</h2>
<div className={`grid grid-cols-9 gap-6`}>
{rgbLed.map((led, i) => (
<HorizontalBar
key={i}
pinState={led}
onUpdate={(newLed) => {
setLed(i, newLed);
}}
onDelete={() => {
removeLed(i);
}}
/>
))}
{rgbLed.length < 5 && <HorizontalBarPlus
onClick={handleAdd}
/>}
</div>
</div>
</div>
</div>
)
}
export default ControlRgbLed;

View File

@ -24,13 +24,17 @@ function Hero ({ img, shortNav }: InHero) {
<small className="text-xs"> i don't even know anything about electronics and some IoT stuff lol</small> <small className="text-xs"> i don't even know anything about electronics and some IoT stuff lol</small>
</p> </p>
<div className="flex flex-wrap gap-3 mt-5"> <div className="flex flex-wrap gap-3 mt-5">
{shortNav.map(({ name }, i) => ( {shortNav.map(({ name, target }, i) => (
<Button key={i} className="text-sm">{name}</Button> <a href={target} key={i}>
<Button>{name}</Button>
</a>
))} ))}
</div> </div>
<div className="absolute left-0 -bottom-24"> <div className="absolute left-0 -bottom-24">
Made By Made By
<img className="inline" src={NolaImg} /> <a href="https://github.com/norman-andrians" target="_blank">
<img className="inline hover:animate-wewew" src={NolaImg} />
</a>
Norman Andrians Norman Andrians
</div> </div>
</div> </div>

View File

@ -24,7 +24,22 @@ const INIT_VALUES: ControllerContextProps = {
state: false state: false
} }
], ],
rgbLed: [], rgbLed: [
{
red: {
pin: 13,
state: false
},
green: {
pin: 12,
state: false
},
blue: {
pin: 11,
state: false
}
}
],
piezo: [], piezo: [],
motoServo: [], motoServo: [],
photoresistor: [], photoresistor: [],

View File

@ -5,6 +5,9 @@
@tailwind utilities; @tailwind utilities;
@layer base { @layer base {
html {
scroll-behavior: smooth;
}
input::-webkit-outer-spin-button, input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button { input::-webkit-inner-spin-button {
-webkit-appearance: none; -webkit-appearance: none;
@ -27,6 +30,14 @@
to { opacity: 1; } to { opacity: 1; }
} }
@keyframes wewew {
0% { transform: scale(1, 1); }
25% { transform: scale(1.1, .9); }
50% { transform: scale(.9, 1.1); }
75% { transform: scale(1.1, .9); }
100% { transform: scale(1, 1); }
}
.container { .container {
@apply w-[1280px] mx-auto; @apply w-[1280px] mx-auto;
} }
@ -36,10 +47,10 @@
} }
.switch { .switch {
@apply rounded-lg; @apply rounded-lg transition;
} }
.switch > .handler { .switch > .handler {
@apply rounded-md p-[6px] transition-all; @apply rounded-md p-[6px] transition-[margin];
} }
@ -51,7 +62,7 @@
} }
.switch-off { .switch-off {
@apply border-disabled; @apply border-disabled bg-transparent;
} }
.switch-off > .handler { .switch-off > .handler {
@apply bg-disabled ms-0; @apply bg-disabled ms-0;

View File

@ -1,5 +1,6 @@
import { useContext } from "react"; import { useContext } from "react";
import { BoardControllerContext } from "../contexts/BoardController"; import { BoardControllerContext } from "../contexts/BoardController";
import { ChannelPinState } from "../types/board";
export function usePin () { export function usePin () {
return useContext(BoardControllerContext); return useContext(BoardControllerContext);
@ -18,8 +19,8 @@ export function useLed () {
setLeds!(newLed); setLeds!(newLed);
} }
const removeLed = (pin: number | string) => { const removeLed = (index: number) => {
const newLed = leds.filter(led => led.pin != pin); const newLed = leds.filter((_led, i) => i != index);
setLeds!(newLed); setLeds!(newLed);
} }
@ -31,13 +32,51 @@ export function useLed () {
setLeds!(newLed); setLeds!(newLed);
} }
const setLedPin = (pin: number | string, newPin: number | string) => { const setLedPin = (index: number | string, newPin: number | string) => {
const newLed = leds.map(led => { const newLed = leds.map((led, i) => {
if (led.pin == pin) return { pin: newPin, state: led.state }; if (i == index) return { pin: newPin, state: led.state };
return led; return led;
}) })
setLeds!(newLed); setLeds!(newLed);
} }
return { leds, getLed, setLed, setLedPin, addLed, removeLed }; return { leds, getLed, setLed, setLedPin, addLed, removeLed };
}
export function useRgbLed () {
const { rgbLed, setRgbLed } = useContext(BoardControllerContext);
const getLed = (index: number) => {
const led = rgbLed.find((_val, i) => i == index);
return led;
}
const addLed = (channelPin: ChannelPinState) => {
const newLed: ChannelPinState[] = [
...rgbLed,
{
red: channelPin.red,
green: channelPin.green,
blue: channelPin.blue
}
];
setRgbLed!(newLed);
}
const removeLed = (index: number) => {
const newLed: ChannelPinState[] = rgbLed.filter((_led, i) => i != index);
setRgbLed!(newLed);
}
const setLed = (index: number, channelPin: ChannelPinState) => {
const newLed: ChannelPinState[] = rgbLed.map((led, i) => {
if (i == index) return channelPin;
return led;
})
setRgbLed!(newLed);
}
return { rgbLed, getLed, setLed, addLed, removeLed };
} }

View File

@ -7,6 +7,7 @@ import ControlLED from "../components/landing/ControlLED";
import LunarImg from "../assets/img/ocs/lunar-oc.png"; import LunarImg from "../assets/img/ocs/lunar-oc.png";
import ControlNav from "../data/control-navigation.json"; import ControlNav from "../data/control-navigation.json";
import ControlRgbLed from "../components/landing/ControlRgbLed";
function MainPage () { function MainPage () {
return (<> return (<>
@ -16,6 +17,7 @@ function MainPage () {
shortNav={ControlNav} shortNav={ControlNav}
/> />
<ControlLED /> <ControlLED />
<ControlRgbLed />
</MainBody> </MainBody>
</>) </>)
} }

View File

@ -23,7 +23,8 @@ export default {
}, },
animation: { animation: {
'size-in': 'size-in .3s ease-in-out', 'size-in': 'size-in .3s ease-in-out',
'fade-in': 'fade-in .3s ease-in-out' 'fade-in': 'fade-in .3s ease-in-out',
'wewew': 'wewew .45s ease-in-out',
} }
}, },
}, },