piezo buzzer

This commit is contained in:
Nomi Nonsense (Nonszy) 2024-03-09 16:05:08 +07:00
parent ae271aeecf
commit c75bf1c319
11 changed files with 245 additions and 50 deletions

View File

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

View File

@ -1,18 +1,33 @@
import { CSSProperties, MouseEventHandler, ReactNode } from "react"; import { CSSProperties, MouseEventHandler, ReactNode } from "react";
interface InButton { interface ButtonProps {
className?: string; className?: string;
style?: CSSProperties, style?: CSSProperties,
onClick?: MouseEventHandler onClick?: MouseEventHandler
children?: ReactNode children?: ReactNode
} }
export default function Button ({ function Primary ({
className, className,
style, style,
onClick, onClick,
children children
}: InButton) { }: ButtonProps) {
return (
<button
className={`px-5 py-4 transition font-roboto-mono bg-primary bg-opacity-100 hover:bg-opacity-80 rounded-lg ${className}`}
style={style}
onClick={onClick}
>{children}</button>
)
}
function Secondary ({
className,
style,
onClick,
children
}: ButtonProps) {
return ( return (
<button <button
className={`px-5 py-4 transition font-roboto-mono bg-finn border hover:bg-secondary border-border rounded-lg ${className}`} className={`px-5 py-4 transition font-roboto-mono bg-finn border hover:bg-secondary border-border rounded-lg ${className}`}
@ -21,3 +36,23 @@ export default function Button ({
>{children}</button> >{children}</button>
) )
} }
function Button ({
className,
style,
onClick,
children
}: ButtonProps) {
return (
<button
className={`px-5 py-4 transition font-roboto-mono bg-finn border hover:bg-secondary border-border rounded-lg ${className}`}
style={style}
onClick={onClick}
>{children}</button>
)
}
Button.Primary = Primary;
Button.Secondary = Secondary;
export default Button;

View File

@ -22,10 +22,10 @@ export default function EvoInput ({
} }
return ( return (
<label className={`flex cursor-pointer bg-finn border border-border rounded-lg ${className}`} onClick={handleClick}> <label className={`flex items-center justify-between cursor-pointer bg-finn border border-border rounded-lg ${className}`} onClick={handleClick}>
<div className="flex-1 w-1/2 p-2">{name}</div> <div className="w-fit p-2 text-sm ps-4">{name}</div>
<input <input
className="flex-1 w-1/2 h-full p-2 text-center bg-transparent" className="w-1/2 h-full p-2 text-center text-sm font-roboto-mono bg-transparent"
type={type} type={type}
name="" name=""
id="" id=""

View File

@ -4,38 +4,25 @@ import Switch from "./Switch";
interface PinBoxProps { interface PinBoxProps {
className?: string; className?: string;
value: number | string; value: number | string;
state: boolean;
onValueChange?: ChangeEventHandler<HTMLInputElement | null>; onValueChange?: ChangeEventHandler<HTMLInputElement | null>;
onStateChange?: FormEventHandler<HTMLButtonElement | null>;
onDelete?: FormEventHandler<HTMLButtonElement | null>; onDelete?: FormEventHandler<HTMLButtonElement | null>;
minusBtn?: boolean; minusBtn?: boolean;
} }
function Add ({ interface ToggleProps extends PinBoxProps {
className, state: boolean;
onClick onStateChange?: FormEventHandler<HTMLButtonElement | null>;
}: {
className?: string,
onClick?: MouseEventHandler<HTMLButtonElement>
}) {
return (
<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>
</button>
)
} }
function PinBox ({ function PinBox ({
className, className,
value, value,
state,
onValueChange, onValueChange,
onStateChange,
onDelete, onDelete,
minusBtn minusBtn
}: PinBoxProps) { }: PinBoxProps) {
return ( return (
<div className={`flex flex-col gap-3 animate-fade-in ${className}`}> <div className={`flex flex-col gap-3 ${className}`}>
{minusBtn && <button {minusBtn && <button
className="border bg-transparent ms-auto hover:bg-secondary border-border rounded px-2" className="border bg-transparent ms-auto hover:bg-secondary border-border rounded px-2"
onClick={onDelete} onClick={onDelete}
@ -56,6 +43,27 @@ function PinBox ({
onChange={onValueChange} onChange={onValueChange}
/> />
</div> </div>
</div>
)
}
function Toggle ({
className,
value,
minusBtn,
onDelete,
state,
onStateChange,
onValueChange
}: ToggleProps) {
return (
<div className={`flex flex-col gap-6 ${className}`}>
<PinBox
value={value}
minusBtn={minusBtn}
onDelete={onDelete}
onValueChange={onValueChange}
/>
<Switch <Switch
state={state} state={state}
onChange={onStateChange} onChange={onStateChange}
@ -64,6 +72,21 @@ function PinBox ({
) )
} }
function Add ({
className,
onClick
}: {
className?: string,
onClick?: MouseEventHandler<HTMLButtonElement>
}) {
return (
<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>
</button>
)
}
PinBox.Add = Add; PinBox.Add = Add;
PinBox.Toggle = Toggle;
export default PinBox; export default PinBox;

View File

@ -1,9 +1,10 @@
import PinBox from "../forms/PinBox"; import PinBox from "../forms/PinBox";
import { useLed } from "../../hooks"; import { useLed } from "../../hooks";
import ControlSection from "../ControlSection"; import ControlSection from "../ControlSection";
import { Ref } from "react";
function ControlLED () { function ControlLED ({ refto }: { refto?: Ref<HTMLDivElement> }) {
const { addLed, leds, removeLed, setLed, setLedPin } = useLed(); const { addLed, leds, removeLed, setLed, setLedPin } = useLed();
const handleAdd = (): void => { const handleAdd = (): void => {
@ -21,10 +22,11 @@ function ControlLED () {
<ControlSection <ControlSection
title="LED" title="LED"
id="led" id="led"
refto={refto}
stack={(<> stack={(<>
{leds.map((led, i) => ( {leds.map((led, i) => (
<PinBox <PinBox.Toggle
className="w-36" className="w-36 animate-fade-in"
key={i} key={i}
minusBtn={true} minusBtn={true}
value={led.pin} value={led.pin}

View File

@ -0,0 +1,77 @@
import PinBox from "../forms/PinBox";
import ControlSection from "../ControlSection";
import { Ref } from "react";
import { usePiezo } from "../../hooks";
import { DynamicPinState } from "../../types/board";
import EvoInput from "../forms/EvoInput";
import Button from "../forms/Button";
function PiezoItem ({ piezo, index }: { piezo: DynamicPinState, index: number }) {
const { setFrequency, setPiezoPin, removePiezo } = usePiezo();
return (
<div className="flex flex-col gap-3">
<PinBox
className="w-36 animate-fade-in"
minusBtn={true}
value={piezo.pin}
onValueChange={(e) => {
const pin = e.target.value;
setPiezoPin(index, pin);
}}
onDelete={() => {
removePiezo(index);
}}
/>
<EvoInput
className="w-36 h-11"
name="Frequency"
type="number"
value={piezo.state.toString()}
onChange={(e) => {
const freq: number = Number.parseInt(e.target.value);
if (!Number.isNaN(freq)) setFrequency(piezo.pin, freq);
}}
/>
<Button.Primary className="text-sm py-0 h-11">Play</Button.Primary>
</div>
)
}
function ControlPiezo ({ refto }: { refto?: Ref<HTMLDivElement> }) {
const { piezo: piezos, addPiezo } = usePiezo();
const handleAdd = (): void => {
let anopin = 13;
for (let i = 0; i < piezos.length; i++) {
if (piezos.filter(piezo => piezo.pin == anopin).length > 0) {
anopin--;
}
else break;
}
addPiezo(anopin, 247);
}
return (
<ControlSection
title="Piezo Buzzer"
id="piezo"
refto={refto}
stack={(<>
{piezos.map((piezo, i) => (
<PiezoItem
index={i}
piezo={piezo}
key={i}
/>
))}
{piezos.length < 14 && <PinBox.Add
className="w-36 mt-10"
onClick={handleAdd}
/>}
</>)}
/>
)
}
export default ControlPiezo;

View File

@ -2,7 +2,7 @@ import { useRgbLed } from "../../hooks";
import { ChannelPinState, PinState } from "../../types/board"; import { ChannelPinState, PinState } from "../../types/board";
import EvoInput from "../forms/EvoInput"; import EvoInput from "../forms/EvoInput";
import Switch from "../forms/Switch"; import Switch from "../forms/Switch";
import { MouseEventHandler, useEffect, useState } from "react"; import { MouseEventHandler, Ref, useEffect, useState } from "react";
interface HorizontalBarProps { interface HorizontalBarProps {
pinState: ChannelPinState; pinState: ChannelPinState;
@ -31,15 +31,15 @@ function HorizontalBar ({ pinState, onUpdate, onDelete }: HorizontalBarProps) {
}, [red, green, blue]) }, [red, green, blue])
return ( return (
<div className="flex flex-col col-span-3 gap-2 animate-fade-in"> <div className="flex flex-col col-span-3 gap-2 animate-fade-in font-roboto-mono">
<button className="ms-auto bg-finn border border-border rounded-lg px-5" onClick={onDelete}> <button className="ms-auto bg-finn hover:bg-secondary transition border border-border rounded-lg px-5" onClick={onDelete}>
<i className="bi bi-dash text-xl"></i> <i className="bi bi-dash text-xl"></i>
</button> </button>
<div className="bg-secondary animate-size-in rounded-lg border border-border p-4 flex gap-3"> <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="flex-1 text-center flex flex-col gap-3">
<div className="text-[#FF4444]">Red</div> <div className="text-[#FF4444]">Red</div>
<EvoInput <EvoInput
name="pin" name="Pin"
value={red.pin.toString()} value={red.pin.toString()}
type="number" type="number"
onChange={(e) => { onChange={(e) => {
@ -62,7 +62,7 @@ function HorizontalBar ({ pinState, onUpdate, onDelete }: HorizontalBarProps) {
<div className="flex-1 text-center flex flex-col gap-3"> <div className="flex-1 text-center flex flex-col gap-3">
<div className="text-[#48FF44]">Green</div> <div className="text-[#48FF44]">Green</div>
<EvoInput <EvoInput
name="pin" name="Pin"
value={green.pin.toString()} value={green.pin.toString()}
type="number" type="number"
onChange={(e) => { onChange={(e) => {
@ -85,7 +85,7 @@ function HorizontalBar ({ pinState, onUpdate, onDelete }: HorizontalBarProps) {
<div className="flex-1 text-center flex flex-col gap-3"> <div className="flex-1 text-center flex flex-col gap-3">
<div className="text-[#4844FF]">Blue</div> <div className="text-[#4844FF]">Blue</div>
<EvoInput <EvoInput
name="pin" name="Pin"
value={blue.pin.toString()} value={blue.pin.toString()}
type="number" type="number"
onChange={(e) => { onChange={(e) => {
@ -113,7 +113,7 @@ function HorizontalBar ({ pinState, onUpdate, onDelete }: HorizontalBarProps) {
function HorizontalBarPlus ({ onClick }: { onClick?: MouseEventHandler<HTMLButtonElement> }) { function HorizontalBarPlus ({ onClick }: { onClick?: MouseEventHandler<HTMLButtonElement> }) {
return ( return (
<button <button
className="bg-finn hover:bg-secondary transition col-span-3 rounded-lg border border-border flex items-center justify-center mt-10" className="bg-finn h-40 hover:bg-secondary transition col-span-3 rounded-lg border border-border flex items-center justify-center mt-10"
onClick={onClick} onClick={onClick}
> >
<i className="bi bi-plus text-6xl text-border"></i> <i className="bi bi-plus text-6xl text-border"></i>
@ -121,7 +121,7 @@ function HorizontalBarPlus ({ onClick }: { onClick?: MouseEventHandler<HTMLButto
) )
} }
function ControlRgbLed () { function ControlRgbLed ({ refto }: { refto?: Ref<HTMLDivElement> }) {
const { addLed, rgbLed, removeLed, setLed } = useRgbLed(); const { addLed, rgbLed, removeLed, setLed } = useRgbLed();
const handleAdd = (): void => { const handleAdd = (): void => {
@ -142,7 +142,7 @@ function ControlRgbLed () {
} }
return ( return (
<div className="container py-16" id="rgb-led"> <div className="container py-16" id="rgb-led" ref={refto}>
<div className="container-grid items-center relative"> <div className="container-grid items-center relative">
<div className={`col-span-8`}> <div className={`col-span-8`}>
<h2 className="text-4xl font-poppins font-bold leading-normal mb-4"> <h2 className="text-4xl font-poppins font-bold leading-normal mb-4">

View File

@ -1,5 +1,6 @@
import Button from "../forms/Button"; import Button from "../forms/Button";
import NolaImg from "../../assets/img/ocs/nola_3.png"; import NolaImg from "../../assets/img/ocs/nola_3.png";
import { RefObject } from "react";
type ShortNav = { type ShortNav = {
name: string, name: string,
@ -8,10 +9,11 @@ type ShortNav = {
interface InHero { interface InHero {
img: string; img: string;
shortNav: ShortNav[] shortNav: ShortNav[];
refs?: RefObject<HTMLElement>[]
} }
function Hero ({ img, shortNav }: InHero) { function Hero ({ img, shortNav, refs }: InHero) {
return ( return (
<div className="h-screen container flex items-center"> <div className="h-screen container flex items-center">
<div className="container-grid items-center relative"> <div className="container-grid items-center relative">
@ -24,10 +26,14 @@ 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, target }, i) => ( {shortNav.map(({ name }, i) => (
<a href={target} key={i}> <Button
<Button>{name}</Button> key={i}
</a> onClick={() => {
if (refs && refs.length >= i)
refs[i].current?.scrollIntoView({ behavior: "smooth" });
}}
>{name}</Button>
))} ))}
</div> </div>
<div className="absolute left-0 -bottom-24"> <div className="absolute left-0 -bottom-24">

View File

@ -40,7 +40,12 @@ const INIT_VALUES: ControllerContextProps = {
} }
} }
], ],
piezo: [], piezo: [
{
pin: 6,
state: 127
}
],
motoServo: [], motoServo: [],
photoresistor: [], photoresistor: [],
} }

View File

@ -10,8 +10,7 @@ export function useLed () {
const { leds, setLeds } = useContext(BoardControllerContext); const { leds, setLeds } = useContext(BoardControllerContext);
const getLed = (pin: number | string) => { const getLed = (pin: number | string) => {
const led = leds.find(val => val.pin == pin); return leds.find(val => val.pin == pin);
return led;
} }
const addLed = (pin: number | string, state?: boolean) => { const addLed = (pin: number | string, state?: boolean) => {
@ -80,3 +79,41 @@ export function useRgbLed () {
return { rgbLed, getLed, setLed, addLed, removeLed }; return { rgbLed, getLed, setLed, addLed, removeLed };
} }
export function usePiezo () {
const { piezo, setPiezo } = useContext(BoardControllerContext);
const getPiezo = (pin: number | string) => {
return piezo.find(val => val.pin == pin);
}
const addPiezo = (pin: number | string, state: number) => {
const newPiezo = [...piezo, { pin, state }];
setPiezo!(newPiezo);
}
const removePiezo = (index: number) => {
const newPiezo = piezo.filter((_piezo, i) => i != index);
setPiezo!(newPiezo);
}
const setFrequency = (pin: number | string, state: number) => {
const newPiezo = piezo.map(piezo => {
if (piezo.pin == pin) return { pin, state };
return piezo;
})
setPiezo!(newPiezo);
}
const setPiezoPin = (index: number | string, newPin: number | string) => {
const newPiezo = piezo.map((piezo, i) => {
if (i == index) return { pin: newPin, state: piezo.state };
return piezo;
})
setPiezo!(newPiezo);
}
return { piezo, getPiezo, addPiezo, removePiezo, setFrequency, setPiezoPin };
}

View File

@ -1,3 +1,4 @@
import { useRef } from "react";
import MainBody from "../components/MainBody"; import MainBody from "../components/MainBody";
// Section components // Section components
@ -8,16 +9,23 @@ 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"; import ControlRgbLed from "../components/landing/ControlRgbLed";
import ControlPiezo from "../components/landing/ControlPiezo";
function MainPage () { function MainPage () {
const led = useRef<HTMLDivElement | null>(null);
const rgbLed = useRef<HTMLDivElement | null>(null);
const piezo = useRef<HTMLDivElement | null>(null);
return (<> return (<>
<MainBody> <MainBody>
<Hero <Hero
img={LunarImg} img={LunarImg}
refs={[led, rgbLed, piezo]}
shortNav={ControlNav} shortNav={ControlNav}
/> />
<ControlLED /> <ControlLED refto={led} />
<ControlRgbLed /> <ControlRgbLed refto={rgbLed} />
<ControlPiezo refto={piezo} />
</MainBody> </MainBody>
</>) </>)
} }