Skip to content

Commit 9ecde50

Browse files
committed
add demobase
1 parent 8ba5c94 commit 9ecde50

18 files changed

+4934
-0
lines changed

000_DemoBase/.eslintrc.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
es2021: true,
5+
node: true,
6+
},
7+
extends: [
8+
"eslint:recommended",
9+
"plugin:react/recommended",
10+
"plugin:@typescript-eslint/recommended",
11+
],
12+
parser: "@typescript-eslint/parser",
13+
parserOptions: {
14+
ecmaFeatures: {
15+
jsx: true,
16+
},
17+
ecmaVersion: 13,
18+
sourceType: "module",
19+
},
20+
plugins: ["react", "@typescript-eslint"],
21+
rules: {},
22+
};

000_DemoBase/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/node_modules
2+
/dist
3+
4+
*#
5+
*~

000_DemoBase/.prettierrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"tabWidth": 4,
3+
"useTabs": false,
4+
"semi": true,
5+
"printWidth": 360
6+
}

000_DemoBase/package-lock.json

Lines changed: 4225 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

000_DemoBase/package.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"name": "000_DemoBase",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "dist/index.js",
6+
"scripts": {
7+
"tsc": "tsc",
8+
"clean": "rimraf dist/*",
9+
"webpack:build": "webpack --config webpack.config.js",
10+
"build": "run-s clean tsc webpack:build ",
11+
"test": "echo \"Error: no test specified\" && exit 1"
12+
},
13+
"keywords": [],
14+
"author": "",
15+
"license": "ISC",
16+
"devDependencies": {
17+
"@babel/core": "^7.15.8",
18+
"@babel/plugin-transform-runtime": "^7.15.8",
19+
"@babel/preset-env": "^7.15.8",
20+
"@babel/preset-react": "^7.14.5",
21+
"@babel/preset-typescript": "^7.15.0",
22+
"@babel/runtime": "^7.15.4",
23+
"@types/node": "^17.0.23",
24+
"@types/react": "^17.0.39",
25+
"@types/react-dom": "^17.0.13",
26+
"autoprefixer": "^10.4.4",
27+
"babel-loader": "^8.2.3",
28+
"before-build-webpack": "^0.2.12",
29+
"css-loader": "^6.7.1",
30+
"daisyui": "^2.6.3",
31+
"npm-run-all": "^4.1.5",
32+
"postcss-loader": "^6.2.1",
33+
"rimraf": "^3.0.2",
34+
"style-loader": "^3.3.1",
35+
"ts-loader": "^9.2.8",
36+
"tsconfig-paths": "^3.14.1",
37+
"typescript": "^4.6.3",
38+
"webpack": "^5.71.0",
39+
"webpack-cli": "^4.9.2",
40+
"react": "^17.0.2",
41+
"react-dom": "^17.0.2"
42+
},
43+
"dependencies": {}
44+
}

000_DemoBase/postcss.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
plugins: [require("tailwindcss"), require("autoprefixer")],
3+
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from "react";
2+
import { useMemo } from "react";
3+
4+
export type CommonSelectorProps<T extends string> = {
5+
id: string;
6+
title: string;
7+
currentValue: string;
8+
options: { [label: string]: T };
9+
onChange: (value: T) => void;
10+
};
11+
export const CommonSelector = <T extends string>(props: CommonSelectorProps<T>) => {
12+
const onChange = (value: T) => {
13+
props.onChange(value);
14+
};
15+
const select = useMemo(() => {
16+
const options = Object.keys(props.options).map((x) => {
17+
const value = props.options[x];
18+
return (
19+
<option key={value} value={value}>
20+
{x}
21+
</option>
22+
);
23+
});
24+
return (
25+
<div>
26+
<p className="text-slate-600" style={{ fontSize: "0.75rem" }}>
27+
{props.title}
28+
</p>
29+
<select
30+
className="select select-bordered select-sm w-full max-w-xs"
31+
onChange={(val: React.ChangeEvent<HTMLSelectElement>) => {
32+
onChange(val.currentTarget.value as T);
33+
}}
34+
value={props.currentValue}
35+
>
36+
{options}
37+
</select>
38+
</div>
39+
);
40+
}, [props]);
41+
return select;
42+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from "react";
2+
import { useMemo } from "react";
3+
4+
export type CommonSliderProps = {
5+
id: string;
6+
title: string;
7+
currentValue: number;
8+
max: number;
9+
min: number;
10+
step: number;
11+
integer: boolean;
12+
width?: string;
13+
onChange: (value: number) => void;
14+
};
15+
export const CommonSlider = (props: CommonSliderProps) => {
16+
const onChange = (val: number) => {
17+
props.onChange(val);
18+
};
19+
const select = useMemo(() => {
20+
return (
21+
<div>
22+
<p className="text-slate-600" style={{ fontSize: "0.75rem" }}>
23+
{props.title} [{props.currentValue}]
24+
</p>
25+
<input
26+
type="range"
27+
className="range range-sm"
28+
min={props.min}
29+
max={props.max}
30+
value={props.currentValue}
31+
step={props.step}
32+
onChange={(val: React.ChangeEvent<HTMLInputElement>) => {
33+
if (props.integer) {
34+
onChange(parseInt(val.target.value));
35+
} else {
36+
onChange(parseFloat(val.target.value));
37+
}
38+
}}
39+
style={{ width: props.width ? props.width : "100%" }}
40+
></input>
41+
</div>
42+
);
43+
}, [props]);
44+
return select;
45+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from "react";
2+
import { useMemo } from "react";
3+
4+
export type CommonSwitchProps = {
5+
id: string;
6+
title: string;
7+
currentValue: boolean;
8+
onChange: (value: boolean) => void;
9+
};
10+
export const CommonSwitch = (props: CommonSwitchProps) => {
11+
const onChange = () => {
12+
props.onChange(!props.currentValue);
13+
};
14+
const select = useMemo(() => {
15+
return (
16+
<div>
17+
<p className="text-slate-600" style={{ fontSize: "0.75rem" }}>
18+
{props.title}
19+
</p>
20+
<input
21+
type="checkbox"
22+
className="toggle toggle-sm"
23+
checked={props.currentValue}
24+
onChange={() => {
25+
onChange();
26+
}}
27+
></input>
28+
</div>
29+
);
30+
}, [props]);
31+
return select;
32+
};
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import React, { useEffect, useMemo, useState } from "react";
2+
import { useDeviceManager } from "../hooks/useDeviceManager";
3+
import { CommonSelector, CommonSelectorProps } from "./CommonSelector";
4+
import "../css/CSS.css";
5+
6+
export type VideoInputSelectorProps = {
7+
id: string;
8+
currentValue: string;
9+
onInputSourceTypeChanged: (value: string) => void;
10+
onInputSourceChanged: (value: MediaStream | string) => void;
11+
};
12+
13+
export const VideoInputSelector = (props: VideoInputSelectorProps) => {
14+
const { getVideoInputDevices } = useDeviceManager();
15+
const [videoDevices, setVideoDevices] = useState<MediaDeviceInfo[]>([]);
16+
17+
useEffect(() => {
18+
const loadDevices = async () => {
19+
const videoDevices = await getVideoInputDevices();
20+
setVideoDevices(videoDevices);
21+
};
22+
loadDevices();
23+
}, []);
24+
25+
/// Load Camera
26+
useEffect(() => {
27+
if (props.currentValue === "File" || props.currentValue === "Window") {
28+
return;
29+
}
30+
navigator.mediaDevices
31+
.getUserMedia({
32+
audio: false,
33+
video: {
34+
deviceId: props.currentValue,
35+
},
36+
})
37+
.then((media) => {
38+
props.onInputSourceChanged(media);
39+
});
40+
}, [props.currentValue]);
41+
42+
/// create params
43+
const commonSelectorProps: CommonSelectorProps<string> = useMemo(() => {
44+
const p: CommonSelectorProps<string> = {
45+
id: props.id,
46+
title: "Video Input",
47+
currentValue: props.currentValue,
48+
options: {
49+
File: "File",
50+
Window: "Window",
51+
},
52+
onChange: props.onInputSourceTypeChanged,
53+
};
54+
videoDevices.forEach((x) => {
55+
p.options[x.label] = x.deviceId;
56+
});
57+
return p;
58+
}, [videoDevices, props.currentValue]);
59+
60+
const loadFileClicked = () => {
61+
console.log("clicked");
62+
const fileInput = document.getElementById(`${props.id}-file-input`) as HTMLInputElement;
63+
console.log("clicked", fileInput);
64+
fileInput.onchange = (event: Event) => {
65+
if (!event || !event.target) {
66+
return;
67+
}
68+
if (!(event.target instanceof HTMLInputElement)) {
69+
return;
70+
}
71+
if (!event.target.files) {
72+
return;
73+
}
74+
if (!event.target.files[0].type.match("image.*") && !event.target.files[0].type.match("movie.*")) {
75+
console.log("not image file", event.target.files[0].type);
76+
return;
77+
}
78+
console.log(event.target.files[0]);
79+
const reader = new FileReader();
80+
reader.onload = () => {
81+
console.log("read image", reader.result);
82+
props.onInputSourceChanged(reader.result as string);
83+
};
84+
reader.readAsDataURL(event.target.files[0]);
85+
};
86+
fileInput.click();
87+
};
88+
89+
const chooseWindowClicked = () => {
90+
navigator.mediaDevices.getDisplayMedia().then((media) => {
91+
props.onInputSourceChanged(media);
92+
});
93+
};
94+
95+
return (
96+
<div>
97+
<CommonSelector {...commonSelectorProps}></CommonSelector>
98+
{props.currentValue === "File" ? (
99+
<div style={{ display: "flex" }}>
100+
<button
101+
className="btn btn-sm btn-outline"
102+
onClick={() => {
103+
loadFileClicked();
104+
}}
105+
>
106+
Load File
107+
</button>
108+
</div>
109+
) : (
110+
<></>
111+
)}
112+
{props.currentValue === "Window" ? (
113+
<div style={{ display: "flex" }}>
114+
<button
115+
className="btn btn-sm btn-outline"
116+
onClick={() => {
117+
chooseWindowClicked();
118+
}}
119+
>
120+
Choose Window
121+
</button>
122+
</div>
123+
) : (
124+
<></>
125+
)}
126+
127+
<></>
128+
129+
<input type="file" id={`${props.id}-file-input`} hidden></input>
130+
</div>
131+
);
132+
};

0 commit comments

Comments
 (0)