mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
Initial commit
This commit is contained in:
55
app/components/audioVisualizer.js
Normal file
55
app/components/audioVisualizer.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
function AudioVisualizer() {
|
||||
const canvasRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
let animationFrameId;
|
||||
|
||||
const canvas = canvasRef.current;
|
||||
const context = canvas.getContext('2d');
|
||||
const analyser = new AnalyserNode(new AudioContext());
|
||||
|
||||
navigator.mediaDevices.getUserMedia({ audio: true })
|
||||
.then(stream => {
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
const source = audioContext.createMediaStreamSource(stream);
|
||||
const analyser = audioContext.createAnalyser();
|
||||
analyser.fftSize = 2048;
|
||||
source.connect(analyser);
|
||||
|
||||
const bufferLength = analyser.frequencyBinCount;
|
||||
const dataArray = new Uint8Array(bufferLength);
|
||||
const barWidth = (canvas.width / bufferLength) * 2.5;
|
||||
let barHeight;
|
||||
let x = 0;
|
||||
|
||||
function renderFrame() {
|
||||
x = 0;
|
||||
analyser.getByteFrequencyData(dataArray);
|
||||
context.fillStyle = '#000';
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
for (let i = 0; i < bufferLength; i++) {
|
||||
barHeight = dataArray[i];
|
||||
|
||||
const red = 255;
|
||||
const green = 250 * (i / bufferLength);
|
||||
const blue = barHeight + (25 * (i / bufferLength));
|
||||
|
||||
context.fillStyle = `rgb(${red},${green},${blue})`;
|
||||
context.fillRect(x, canvas.height - barHeight / 2, barWidth, barHeight / 2);
|
||||
|
||||
x += barWidth + 1;
|
||||
}
|
||||
animationFrameId = requestAnimationFrame(renderFrame);
|
||||
}
|
||||
renderFrame();
|
||||
});
|
||||
|
||||
return () => cancelAnimationFrame(animationFrameId);
|
||||
}, []);
|
||||
|
||||
return <canvas className='w-full h-16' ref={canvasRef} />;
|
||||
}
|
||||
|
||||
export default AudioVisualizer;
|
||||
114
app/components/dashboard.js
Normal file
114
app/components/dashboard.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import { Mulberry32 } from '../utils.js'
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import AudioVisualizer from './audioVisualizer.js';
|
||||
|
||||
export function Dashboard()
|
||||
{
|
||||
const [openIndex, setOpenIndex] = useState(null);
|
||||
const [liveTranscript, setLiveTranscript] = useState("");
|
||||
|
||||
const [fakeTranscriptIndex, setFakeTranscriptIndex] = useState(0);
|
||||
|
||||
const fakeTranscripts = [
|
||||
"This is the first transcript. We are discussing the current situation of our company. We are currently leading the market with a significant margin, and our future outlook is also very promising...",
|
||||
"Here is the second transcript. We are now moving to our next topic, which is the progress in our ongoing projects. Most of them are on schedule and the quality of work is up to our standard...",
|
||||
"This is the third transcript. It's about the financial status of our company. We are doing quite well financially. The revenue for this quarter is higher than expected...",
|
||||
// add more fake transcripts as needed
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
// Randomly select a fake transcript
|
||||
const selectedTranscript = fakeTranscripts[Math.floor(Math.random() * fakeTranscripts.length)];
|
||||
// Split the selected transcript into characters
|
||||
const characters = Array.from(selectedTranscript);
|
||||
|
||||
let counter = 0;
|
||||
let liveTranscriptCopy = '';
|
||||
let intervalId = setInterval(() => {
|
||||
if (counter < characters.length) {
|
||||
liveTranscriptCopy += characters[counter];
|
||||
setLiveTranscript(liveTranscriptCopy);
|
||||
counter++;
|
||||
} else {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
}, 50); // delay of 100ms
|
||||
|
||||
// Cleanup function to clear the interval when the component unmounts
|
||||
return () => clearInterval(intervalId);
|
||||
}, []);
|
||||
|
||||
const generateDecibelData = (x) => {
|
||||
let data = [];
|
||||
let random = Mulberry32(123456789 + x);
|
||||
for (let i = 0; i < 50; i++) {
|
||||
data.push(Math.floor(random() * 30) + 10); // generate random values between 10 and 40
|
||||
}
|
||||
return data;
|
||||
};
|
||||
const generateDecibelGraph = (decibelData) => {
|
||||
return decibelData.map((decibel, i) => (
|
||||
<div key={i} className="w-1 bg-blue-500 mr-0.5" style={{ height: `${decibel}px` }}> </div>
|
||||
));
|
||||
};
|
||||
|
||||
|
||||
// This is hardcoded data for proof of concept
|
||||
const data = [
|
||||
{ timestamp: '00:00', topic: 'Meeting Introduction', decibel: generateDecibelData(1), transcript: "This is the meeting introduction, we will be discussing several important topics today." },
|
||||
{ timestamp: '00:48', topic: 'Discussing Quarterly Revenue', decibel: generateDecibelData(2), transcript: "We are discussing the quarterly revenue here, it appears our revenue has grown by 15% compared to the previous quarter." },
|
||||
{ timestamp: '01:35', topic: 'Annual Sales Review', decibel: generateDecibelData(3), transcript: "Now we're reviewing the annual sales, there was a significant boost during the holiday season." },
|
||||
{ timestamp: '02:20', topic: 'Operational Costs Analysis', decibel: generateDecibelData(4), transcript: "Moving on to the operational costs analysis, we have managed to reduce unnecessary expenses." },
|
||||
{ timestamp: '03:10', topic: 'Employee Performance', decibel: generateDecibelData(5), transcript: "Let's talk about the employee performance, overall the team has done a great job." },
|
||||
/* { timestamp: '03:45', topic: 'New Marketing Strategies', decibel: generateDecibelData(6), transcript: "Our marketing team has proposed some new strategies that we'll discuss now." },
|
||||
{ timestamp: '04:30', topic: 'Customer Feedback', decibel: generateDecibelData(7), transcript: "Let's go through some customer feedback that we've received." },
|
||||
{ timestamp: '05:15', topic: 'Product Development', decibel: generateDecibelData(8), transcript: "Product development is going well and the new product line will be ready to launch next quarter." },
|
||||
{ timestamp: '06:00', topic: 'Discussing Future Projects', decibel: generateDecibelData(9), transcript: "Now we are talking about the future projects, we have some exciting projects lined up." },
|
||||
{ timestamp: '06:45', topic: 'Meeting Conclusion', decibel: generateDecibelData(10), transcript: "As we conclude the meeting, I want to thank everyone for their hard work and dedication." }, */
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-3/4 py-4">
|
||||
<div className="text-center py-6">
|
||||
<h1 className="text-4xl font-bold text-blue-500">Reflector</h1>
|
||||
<p className="text-gray-500">Capture The Signal, Not The Noise</p>
|
||||
</div>
|
||||
<div className="flex justify-between border-b-2">
|
||||
<div className="w-1/4">Timestamp</div>
|
||||
<div className="w-1/4">Topic</div>
|
||||
<div className="w-1/4"></div>
|
||||
</div>
|
||||
{data.map((item, index) => (
|
||||
<div key={index} className="border-b-2 py-2">
|
||||
<div className="flex justify-between cursor-pointer" onClick={() => setOpenIndex(openIndex === index ? null : index)}>
|
||||
<div className="w-1/4">{item.timestamp}</div>
|
||||
<div className="w-1/4">{item.topic} <span className={`inline-block transform transition-transform duration-200 ${openIndex === index ? 'rotate-90' : ''}`}>{'>'}</span></div>
|
||||
<div className="w-1/4 flex flex-row space-x-0.5">
|
||||
{generateDecibelGraph(item.decibel)}
|
||||
</div>
|
||||
</div>
|
||||
{openIndex === index && (
|
||||
<div className="mt-2 p-2 bg-white">
|
||||
{item.transcript}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className="border-b-2 py-2">
|
||||
<div className="flex justify-between">
|
||||
<div className="w-1/4">Live</div>
|
||||
<div className="w-1/4">Transcript</div>
|
||||
<div className="w-1/4 flex flex-row space-x-0.5">
|
||||
{generateDecibelGraph(generateDecibelData())}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 p-2 bg-white">
|
||||
{liveTranscript}
|
||||
</div>
|
||||
</div>
|
||||
<AudioVisualizer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
46
app/components/record.js
Normal file
46
app/components/record.js
Normal file
@@ -0,0 +1,46 @@
|
||||
export default function Record(props) {
|
||||
let mediaRecorder = null; // mediaRecorder instance
|
||||
|
||||
const startRecording = () => {
|
||||
navigator.mediaDevices.getUserMedia({ audio: true })
|
||||
.then(stream => {
|
||||
mediaRecorder = new MediaRecorder(stream);
|
||||
mediaRecorder.start();
|
||||
props.onRecord(true);
|
||||
});
|
||||
};
|
||||
|
||||
const stopRecording = () => {
|
||||
if (mediaRecorder) {
|
||||
mediaRecorder.stop();
|
||||
props.onRecord(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center h-screen">
|
||||
<div className="text-center py-6 mt-10">
|
||||
<h1 className="text-5xl font-bold text-blue-500">Reflector</h1>
|
||||
<p className="text-gray-500">Capture The Signal, Not The Noise</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center justify-center flex-grow -mt-10">
|
||||
{!props.isRecording ? (
|
||||
<button
|
||||
onClick={startRecording}
|
||||
className="px-4 py-2 mb-4 text-2xl font-bold text-white bg-blue-500 rounded"
|
||||
>
|
||||
Record
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={stopRecording}
|
||||
className="px-4 py-2 mb-4 text-2xl font-bold text-red-500 rounded"
|
||||
>
|
||||
Stop
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
36
app/components/webrtc.js
Normal file
36
app/components/webrtc.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Peer from 'simple-peer';
|
||||
|
||||
const useWebRTC = (stream) => {
|
||||
const [data, setData] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
let peer = new Peer({ initiator: true, stream: stream });
|
||||
|
||||
peer.on('signal', data => {
|
||||
// This is where you'd send the signal data to the server.
|
||||
// The server would then send it back to other peers who would then
|
||||
// use `peer.signal()` method to continue the connection negotiation.
|
||||
console.log('signal', data);
|
||||
});
|
||||
|
||||
peer.on('connect', () => {
|
||||
console.log('WebRTC connected');
|
||||
});
|
||||
|
||||
peer.on('data', data => {
|
||||
// Received data from the server.
|
||||
const serverData = JSON.parse(data.toString());
|
||||
setData(serverData);
|
||||
});
|
||||
|
||||
// Clean up
|
||||
return () => {
|
||||
peer.destroy();
|
||||
}
|
||||
}, [stream]);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export default useWebRTC;
|
||||
@@ -24,4 +24,6 @@ body {
|
||||
rgb(var(--background-end-rgb))
|
||||
)
|
||||
rgb(var(--background-start-rgb));
|
||||
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
import './globals.css'
|
||||
import { Inter } from 'next/font/google'
|
||||
import { Roboto } from 'next/font/google'
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] })
|
||||
import Head from 'next/head'
|
||||
|
||||
const roboto = Roboto({ subsets: ['latin'], weight: '400' })
|
||||
|
||||
export const metadata = {
|
||||
title: 'Create Next App',
|
||||
description: 'Generated by create next app',
|
||||
title: 'Reflector – Monadical',
|
||||
description: 'Capture The Signal, Not The Noise',
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
<Head>
|
||||
<title>Test</title>
|
||||
</Head>
|
||||
<body className={roboto.className}>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
143
app/page.js
143
app/page.js
@@ -1,113 +1,38 @@
|
||||
import Image from 'next/image'
|
||||
"use client"
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Record from './components/record.js';
|
||||
import { Dashboard } from './components/dashboard.js';
|
||||
import useWebRTC from './components/webrtc.js';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
|
||||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
||||
Get started by editing
|
||||
<code className="font-mono font-bold">app/page.js</code>
|
||||
</p>
|
||||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
|
||||
<a
|
||||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
By{' '}
|
||||
<Image
|
||||
src="/vercel.svg"
|
||||
alt="Vercel Logo"
|
||||
className="dark:invert"
|
||||
width={100}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
const App = () => {
|
||||
const [isRecording, setIsRecording] = useState(false);
|
||||
const [splashScreen, setSplashScreen] = useState(true);
|
||||
|
||||
|
||||
|
||||
const handleRecord = (recording) => {
|
||||
setIsRecording(recording);
|
||||
setSplashScreen(false);
|
||||
};
|
||||
|
||||
const [stream, setStream] = useState(null);
|
||||
const serverData = useWebRTC(stream);
|
||||
console.log(serverData);
|
||||
|
||||
useEffect(() => {
|
||||
navigator.mediaDevices.getUserMedia({ audio: true })
|
||||
.then(setStream)
|
||||
.catch(err => console.error(err));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100">
|
||||
{splashScreen && <Record isRecording={isRecording} onRecord={(recording) => handleRecord(recording)} /> }
|
||||
{!splashScreen && <Dashboard />}
|
||||
</div>
|
||||
);
|
||||
|
||||
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px]">
|
||||
<Image
|
||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js Logo"
|
||||
width={180}
|
||||
height={37}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-32 grid text-center lg:mb-0 lg:grid-cols-4 lg:text-left">
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Docs{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Find in-depth information about Next.js features and API.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800 hover:dark:bg-opacity-30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Learn{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Learn about Next.js in an interactive course with quizzes!
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Templates{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Explore the Next.js 13 playground.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Deploy{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default App;
|
||||
21
app/utils.js
Normal file
21
app/utils.js
Normal file
@@ -0,0 +1,21 @@
|
||||
export function getRandomNumber(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
export function SeededRand(seed) {
|
||||
seed ^= seed << 13
|
||||
seed ^= seed >> 17
|
||||
seed ^= seed << 5
|
||||
return seed / (2 ** 32)
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function Mulberry32(seed) {
|
||||
return function () {
|
||||
var t = seed += 0x6D2B79F5;
|
||||
t = Math.imul(t ^ t >>> 15, t | 1);
|
||||
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
||||
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
||||
}
|
||||
}
|
||||
189
package-lock.json
generated
189
package-lock.json
generated
@@ -9,11 +9,13 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"autoprefixer": "10.4.14",
|
||||
"next": "13.4.9",
|
||||
"next": "^13.4.9",
|
||||
"postcss": "8.4.25",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"tailwindcss": "3.3.2"
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"simple-peer": "^9.11.1",
|
||||
"supports-color": "^9.4.0",
|
||||
"tailwindcss": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
@@ -314,6 +316,25 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
@@ -373,6 +394,29 @@
|
||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
@@ -477,6 +521,22 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/didyoumean": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
@@ -492,6 +552,11 @@
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.455.tgz",
|
||||
"integrity": "sha512-8tgdX0Odl24LtmLwxotpJCVjIndN559AvaOtd67u+2mo+IDsgsTF580NB+uuDCqsHw8yFg53l5+imFV9Fw3cbA=="
|
||||
},
|
||||
"node_modules/err-code": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz",
|
||||
"integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA=="
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
@@ -580,6 +645,11 @@
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"node_modules/get-browser-rtc": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz",
|
||||
"integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ=="
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
@@ -631,6 +701,25 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
@@ -762,6 +851,11 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
@@ -1095,6 +1189,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||
@@ -1126,6 +1228,19 @@
|
||||
"pify": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
@@ -1184,6 +1299,25 @@
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||
@@ -1192,6 +1326,34 @@
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-peer": {
|
||||
"version": "9.11.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-peer/-/simple-peer-9.11.1.tgz",
|
||||
"integrity": "sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"debug": "^4.3.2",
|
||||
"err-code": "^3.0.1",
|
||||
"get-browser-rtc": "^1.1.0",
|
||||
"queue-microtask": "^1.2.3",
|
||||
"randombytes": "^2.1.0",
|
||||
"readable-stream": "^3.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
@@ -1208,6 +1370,14 @@
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-jsx": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
|
||||
@@ -1251,6 +1421,17 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "9.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
|
||||
"integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
|
||||
10
package.json
10
package.json
@@ -10,10 +10,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"autoprefixer": "10.4.14",
|
||||
"next": "13.4.9",
|
||||
"next": "^13.4.9",
|
||||
"postcss": "8.4.25",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"tailwindcss": "3.3.2"
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"simple-peer": "^9.11.1",
|
||||
"supports-color": "^9.4.0",
|
||||
"tailwindcss": "^3.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user