|
@@ -8,9 +8,9 @@ import ABCJS, {
|
|
} from "abcjs";
|
|
} from "abcjs";
|
|
import "ABCJS/ABCJS-audio.css";
|
|
import "ABCJS/ABCJS-audio.css";
|
|
import styles from "./index.module.less";
|
|
import styles from "./index.module.less";
|
|
-import { showConfirmDialog } from "vant";
|
|
|
|
|
|
+import { showConfirmDialog, showToast } from "vant";
|
|
import Keys from "../component/keys";
|
|
import Keys from "../component/keys";
|
|
-import { Collapse, CollapseItem, Snackbar } from "@varlet/ui";
|
|
|
|
|
|
+import { Collapse, CollapseItem } from "@varlet/ui";
|
|
import { IAbc, IMeasure, INote, INoteActive } from "../types";
|
|
import { IAbc, IMeasure, INote, INoteActive } from "../types";
|
|
import { ABC_DATA, createMeasure, createNote, renderMeasures } from "./runtime";
|
|
import { ABC_DATA, createMeasure, createNote, renderMeasures } from "./runtime";
|
|
import TheIcon from "/src/components/The-icon";
|
|
import TheIcon from "/src/components/The-icon";
|
|
@@ -34,7 +34,7 @@ import {
|
|
NSpin,
|
|
NSpin,
|
|
useMessage,
|
|
useMessage,
|
|
} from "naive-ui";
|
|
} from "naive-ui";
|
|
-import { LongArrowAltDown, LongArrowAltUp } from "@vicons/fa";
|
|
|
|
|
|
+import { LongArrowAltDown, LongArrowAltUp, GripLinesVertical } from "@vicons/fa";
|
|
import { svg2canvas } from "/src/utils/svg2canvas";
|
|
import { svg2canvas } from "/src/utils/svg2canvas";
|
|
import { downloadFile } from "/src/utils";
|
|
import { downloadFile } from "/src/utils";
|
|
import FileBtn, { IFileBtnType } from "./component/file-btn";
|
|
import FileBtn, { IFileBtnType } from "./component/file-btn";
|
|
@@ -206,6 +206,8 @@ export default defineComponent({
|
|
|
|
|
|
deleteMearseType: "ing" as "ing" | "finish", // 删除小节类型
|
|
deleteMearseType: "ing" as "ing" | "finish", // 删除小节类型
|
|
loadingAudioSrouce: false, // 加载音频资源
|
|
loadingAudioSrouce: false, // 加载音频资源
|
|
|
|
+ /** 移调类型 */
|
|
|
|
+ moveKeyType: "inset" as "inset" | "up" | "down", // 移调类型
|
|
});
|
|
});
|
|
const noteTypes = ABC_DATA.types.map((item) => item.value).filter(Boolean);
|
|
const noteTypes = ABC_DATA.types.map((item) => item.value).filter(Boolean);
|
|
const accidentals = ABC_DATA.accidentals.map((item) => item.value).filter(Boolean);
|
|
const accidentals = ABC_DATA.accidentals.map((item) => item.value).filter(Boolean);
|
|
@@ -240,7 +242,7 @@ export default defineComponent({
|
|
if (data.select.state) {
|
|
if (data.select.state) {
|
|
data.select.list.push(active);
|
|
data.select.list.push(active);
|
|
if (data.select.list.length === 1) {
|
|
if (data.select.list.length === 1) {
|
|
- Snackbar("请先选择结束音符");
|
|
|
|
|
|
+ showToast("请先选择结束音符");
|
|
}
|
|
}
|
|
if (data.select.list.length === 2) {
|
|
if (data.select.list.length === 2) {
|
|
data.select.list = data.select.list.sort((a, b) => a.startChar - b.startChar);
|
|
data.select.list = data.select.list.sort((a, b) => a.startChar - b.startChar);
|
|
@@ -294,6 +296,8 @@ export default defineComponent({
|
|
meter: "M:4/4",
|
|
meter: "M:4/4",
|
|
speed: "Q:1/4=60",
|
|
speed: "Q:1/4=60",
|
|
key: "K:C",
|
|
key: "K:C",
|
|
|
|
+ visualTranspose: 0,
|
|
|
|
+ transposeKey: "K:C",
|
|
measures: initMusic(30),
|
|
measures: initMusic(30),
|
|
} as IAbc,
|
|
} as IAbc,
|
|
});
|
|
});
|
|
@@ -399,14 +403,14 @@ export default defineComponent({
|
|
});
|
|
});
|
|
|
|
|
|
const midiBuffer = new ABCJS.synth.CreateSynth();
|
|
const midiBuffer = new ABCJS.synth.CreateSynth();
|
|
- console.log(midiBuffer);
|
|
|
|
|
|
+ // console.log(midiBuffer);
|
|
midiBuffer.init({
|
|
midiBuffer.init({
|
|
visualObj: abcData.visualObj,
|
|
visualObj: abcData.visualObj,
|
|
- options: abcData.synthOptions,
|
|
|
|
|
|
+ options: { ...abcData.synthOptions, midiTranspose: abcData.abc.visualTranspose },
|
|
});
|
|
});
|
|
abcData.synthControl
|
|
abcData.synthControl
|
|
.setTune(abcData.visualObj, false, {
|
|
.setTune(abcData.visualObj, false, {
|
|
- midiTranspose: abcData.abcOptions.visualTranspose,
|
|
|
|
|
|
+ midiTranspose: abcData.abc.visualTranspose,
|
|
...abcData.synthOptions,
|
|
...abcData.synthOptions,
|
|
})
|
|
})
|
|
.then(function (response) {
|
|
.then(function (response) {
|
|
@@ -444,7 +448,10 @@ export default defineComponent({
|
|
};
|
|
};
|
|
|
|
|
|
const renderSvg = () => {
|
|
const renderSvg = () => {
|
|
- abcData.visualObj = ABCJS.renderAbc("paper", data.music, abcData.abcOptions)[0];
|
|
|
|
|
|
+ abcData.visualObj = ABCJS.renderAbc("paper", data.music, {
|
|
|
|
+ ...abcData.abcOptions,
|
|
|
|
+ visualTranspose: abcData.abc.visualTranspose,
|
|
|
|
+ })[0];
|
|
console.log("🚀 ~ visualObj:", abcData.visualObj);
|
|
console.log("🚀 ~ visualObj:", abcData.visualObj);
|
|
};
|
|
};
|
|
|
|
|
|
@@ -490,11 +497,12 @@ export default defineComponent({
|
|
const handleResetRender = (isProduct = true) => {
|
|
const handleResetRender = (isProduct = true) => {
|
|
return new Promise((resolve) => {
|
|
return new Promise((resolve) => {
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
- textAreaRef.value.value = data.music = isProduct ? renderMeasures(abcData.abc) : data.music;
|
|
|
|
|
|
+ data.music = isProduct ? renderMeasures(abcData.abc) : data.music;
|
|
renderSvg();
|
|
renderSvg();
|
|
resetMidi();
|
|
resetMidi();
|
|
renderBoxRect();
|
|
renderBoxRect();
|
|
resolve(1);
|
|
resolve(1);
|
|
|
|
+ textAreaRef.value && (textAreaRef.value.value = data.music);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
};
|
|
};
|
|
@@ -549,7 +557,7 @@ export default defineComponent({
|
|
abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
|
|
abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
|
|
// console.log(activeNote, data.active.isFirstChecked);
|
|
// console.log(activeNote, data.active.isFirstChecked);
|
|
const _values = value.split("-");
|
|
const _values = value.split("-");
|
|
- console.log("🚀 ~ _value:", _values);
|
|
|
|
|
|
+ // console.log("🚀 ~ _value:", _values);
|
|
if (data.active.isFirstChecked) {
|
|
if (data.active.isFirstChecked) {
|
|
activeNote.content = _values[0];
|
|
activeNote.content = _values[0];
|
|
activeNote.noteType = data.noteType;
|
|
activeNote.noteType = data.noteType;
|
|
@@ -607,18 +615,13 @@ export default defineComponent({
|
|
// 临时升降记号
|
|
// 临时升降记号
|
|
if (type === "accidentals") {
|
|
if (type === "accidentals") {
|
|
if (!data.active) {
|
|
if (!data.active) {
|
|
- Snackbar({
|
|
|
|
- content: "请先选择音符",
|
|
|
|
- position: "top",
|
|
|
|
- });
|
|
|
|
|
|
+ showToast("请先选择音符");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
const activeNote =
|
|
const activeNote =
|
|
abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
|
|
abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
|
|
if (activeNote.content === "z") {
|
|
if (activeNote.content === "z") {
|
|
- Snackbar({
|
|
|
|
- content: "休止符无法添加临时升降记号",
|
|
|
|
- });
|
|
|
|
|
|
+ showToast("休止符无法添加临时升降记号");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
activeNote.accidental = activeNote.accidental == value ? "" : value;
|
|
activeNote.accidental = activeNote.accidental == value ? "" : value;
|
|
@@ -680,9 +683,7 @@ export default defineComponent({
|
|
// 演奏技法
|
|
// 演奏技法
|
|
if (type === "play") {
|
|
if (type === "play") {
|
|
if (!data.active) {
|
|
if (!data.active) {
|
|
- Snackbar({
|
|
|
|
- content: "请先选择音符",
|
|
|
|
- });
|
|
|
|
|
|
+ showToast("请先选择音符");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
const activeNote =
|
|
const activeNote =
|
|
@@ -704,16 +705,11 @@ export default defineComponent({
|
|
data.select.list = [];
|
|
data.select.list = [];
|
|
data.select.state = true;
|
|
data.select.state = true;
|
|
data.select.parmas = params;
|
|
data.select.parmas = params;
|
|
- Snackbar({
|
|
|
|
- content: "请先选择开始音符",
|
|
|
|
- position: "top",
|
|
|
|
- });
|
|
|
|
|
|
+ showToast("请先选择开始音符");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
if (!data.active) {
|
|
if (!data.active) {
|
|
- Snackbar({
|
|
|
|
- content: "请先选择音符",
|
|
|
|
- });
|
|
|
|
|
|
+ showToast("请先选择音符");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -737,15 +733,11 @@ export default defineComponent({
|
|
data.select.list = [];
|
|
data.select.list = [];
|
|
data.select.state = true;
|
|
data.select.state = true;
|
|
data.select.parmas = params;
|
|
data.select.parmas = params;
|
|
- Snackbar({
|
|
|
|
- content: "请先选择开始音符",
|
|
|
|
- });
|
|
|
|
|
|
+ showToast("请先选择开始音符");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
if (!data.active) {
|
|
if (!data.active) {
|
|
- Snackbar({
|
|
|
|
- content: "请先选择音符",
|
|
|
|
- });
|
|
|
|
|
|
+ showToast("请先选择音符");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -819,9 +811,7 @@ export default defineComponent({
|
|
// 附点
|
|
// 附点
|
|
if (type === "dot") {
|
|
if (type === "dot") {
|
|
if (!data.active) {
|
|
if (!data.active) {
|
|
- Snackbar({
|
|
|
|
- content: "请先选择音符",
|
|
|
|
- });
|
|
|
|
|
|
+ showToast("请先选择音符");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
const activeNote =
|
|
const activeNote =
|
|
@@ -904,10 +894,16 @@ export default defineComponent({
|
|
};
|
|
};
|
|
|
|
|
|
/** 移调 */
|
|
/** 移调 */
|
|
- const handleMoveKey = (step: number) => {
|
|
|
|
- console.log("移调", step);
|
|
|
|
- const oldStep = abcData.abcOptions.visualTranspose || 0;
|
|
|
|
- abcData.abcOptions.visualTranspose = oldStep + step;
|
|
|
|
|
|
+ const handleMoveKey = (item: (typeof ABC_DATA.key)[0]) => {
|
|
|
|
+ if (data.moveKeyType === "down") {
|
|
|
|
+ abcData.abc.visualTranspose = item.step < 0 ? item.step : item.step - 12;
|
|
|
|
+ } else if (data.moveKeyType === "up") {
|
|
|
|
+ abcData.abc.visualTranspose = item.step >= 0 ? item.step : item.step + 12;
|
|
|
|
+ } else {
|
|
|
|
+ abcData.abc.visualTranspose = item.step;
|
|
|
|
+ }
|
|
|
|
+ // console.log(abcData.abc.visualTranspose, item.step, item.value)
|
|
|
|
+ abcData.abc.transposeKey = item.value;
|
|
popup.moveKeyShow = false;
|
|
popup.moveKeyShow = false;
|
|
handleResetRender();
|
|
handleResetRender();
|
|
};
|
|
};
|
|
@@ -934,14 +930,13 @@ export default defineComponent({
|
|
};
|
|
};
|
|
|
|
|
|
const handleKeyUp = (e: KeyboardEvent) => {
|
|
const handleKeyUp = (e: KeyboardEvent) => {
|
|
- if (e.key === "Backspace") handleDeleteNote();
|
|
|
|
-
|
|
|
|
if (!data.active) return false;
|
|
if (!data.active) return false;
|
|
|
|
+ console.log(e.key);
|
|
|
|
+ if (e.key === "Backspace") handleDeleteNote();
|
|
if (/^[A-Ga-g]$/.test(e.key)) {
|
|
if (/^[A-Ga-g]$/.test(e.key)) {
|
|
handleChange({ type: "note", value: e.key.toLocaleUpperCase() });
|
|
handleChange({ type: "note", value: e.key.toLocaleUpperCase() });
|
|
}
|
|
}
|
|
if (["ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
if (["ArrowUp", "ArrowDown"].includes(e.key)) {
|
|
- console.log(e.key);
|
|
|
|
e.preventDefault();
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
e.stopPropagation();
|
|
handleMoveNote(e.key === "ArrowUp" ? "up" : "donw");
|
|
handleMoveNote(e.key === "ArrowUp" ? "up" : "donw");
|
|
@@ -971,18 +966,13 @@ export default defineComponent({
|
|
}
|
|
}
|
|
if (abc) {
|
|
if (abc) {
|
|
console.log("🚀 ~ abc:", abc);
|
|
console.log("🚀 ~ abc:", abc);
|
|
- if (abc.celf) {
|
|
|
|
- abcData.abc.celf = abc.celf;
|
|
|
|
- }
|
|
|
|
- if (abc.key?.value) {
|
|
|
|
- abcData.abc.key = abc.key.value;
|
|
|
|
- }
|
|
|
|
- if (abc.meter?.value) {
|
|
|
|
- abcData.abc.meter = abc.meter.value;
|
|
|
|
- }
|
|
|
|
- if (abc.speed) {
|
|
|
|
- abcData.abc.speed = abc.speed;
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ abcData.abc.celf = abc.celf || "K:treble";
|
|
|
|
+ abcData.abc.key = abc.key.value || "K:C";
|
|
|
|
+ abcData.abc.meter = abc.meter.value || "M:4/4";
|
|
|
|
+ abcData.abc.speed = abc.speed || "Q:1/4=60";
|
|
|
|
+ abcData.abc.visualTranspose = abc.visualTranspose || 0;
|
|
|
|
+ abcData.abc.transposeKey = abc.transposeKey || "K:C";
|
|
abcData.abc.measures = abc.measures || initMusic(30);
|
|
abcData.abc.measures = abc.measures || initMusic(30);
|
|
console.log("🚀 ~ abcData.abc:", abcData.abc);
|
|
console.log("🚀 ~ abcData.abc:", abcData.abc);
|
|
}
|
|
}
|
|
@@ -1003,7 +993,6 @@ export default defineComponent({
|
|
await getDetailData();
|
|
await getDetailData();
|
|
console.log(ABCJS);
|
|
console.log(ABCJS);
|
|
await handleResetRender();
|
|
await handleResetRender();
|
|
- console.log(ABCJS.extractMeasures(data.music));
|
|
|
|
document.addEventListener("keyup", handleKeyUp);
|
|
document.addEventListener("keyup", handleKeyUp);
|
|
window.onbeforeunload = (e) => {
|
|
window.onbeforeunload = (e) => {
|
|
if (!data.isSave) {
|
|
if (!data.isSave) {
|
|
@@ -1260,38 +1249,38 @@ export default defineComponent({
|
|
</div>
|
|
</div>
|
|
))}
|
|
))}
|
|
|
|
|
|
- <Trigger trigger="click">
|
|
|
|
|
|
+ <NPopover trigger="click" contentStyle={{ width: "400px" }}>
|
|
{{
|
|
{{
|
|
- default: () => (
|
|
|
|
|
|
+ trigger: () => (
|
|
<div class={styles.topDownArrow}>
|
|
<div class={styles.topDownArrow}>
|
|
<img src={getImage("icon_arrow.png")} />
|
|
<img src={getImage("icon_arrow.png")} />
|
|
</div>
|
|
</div>
|
|
),
|
|
),
|
|
- content: () => (
|
|
|
|
- <div class={[styles.wrapBox, styles.dropDownWrap]}>
|
|
|
|
|
|
+ default: () => (
|
|
|
|
+ <NGrid cols={4} yGap={8}>
|
|
{ABC_DATA.play.slice(4).map((item) => (
|
|
{ABC_DATA.play.slice(4).map((item) => (
|
|
- <div
|
|
|
|
- class={[styles.topBtn]}
|
|
|
|
- onClick={() => {
|
|
|
|
- data.morePlay = false;
|
|
|
|
- handleChange({ type: "play", value: item.value });
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
|
|
+ <NGi>
|
|
<div
|
|
<div
|
|
class={[
|
|
class={[
|
|
- styles.btnImg,
|
|
|
|
- noteComputed.value.play?.includes(item.value) && styles.btnImgActive,
|
|
|
|
|
|
+ styles.btnItem,
|
|
|
|
+ noteComputed.value.play?.includes(item.value) && styles.btnItemActive,
|
|
]}
|
|
]}
|
|
|
|
+ onClick={() => {
|
|
|
|
+ data.morePlay = false;
|
|
|
|
+ handleChange({ type: "play", value: item.value });
|
|
|
|
+ }}
|
|
>
|
|
>
|
|
- <TheIcon iconClassName={item.icon} />
|
|
|
|
|
|
+ <div class={styles.btnItemIcon}>
|
|
|
|
+ <TheIcon iconClassName={item.icon} />
|
|
|
|
+ </div>
|
|
|
|
+ <div>{item.name}</div>
|
|
</div>
|
|
</div>
|
|
- <div>{item.name}</div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </NGi>
|
|
))}
|
|
))}
|
|
- </div>
|
|
|
|
|
|
+ </NGrid>
|
|
),
|
|
),
|
|
}}
|
|
}}
|
|
- </Trigger>
|
|
|
|
|
|
+ </NPopover>
|
|
|
|
|
|
<div class={styles.topLine}></div>
|
|
<div class={styles.topLine}></div>
|
|
|
|
|
|
@@ -1372,11 +1361,27 @@ export default defineComponent({
|
|
<div class={styles.btnLineTitle}>移调方式</div>
|
|
<div class={styles.btnLineTitle}>移调方式</div>
|
|
|
|
|
|
<NSpace>
|
|
<NSpace>
|
|
- <NButton secondary onClick={() => handleMoveKey(-1)}>
|
|
|
|
|
|
+ <NButton
|
|
|
|
+ secondary
|
|
|
|
+ type={data.moveKeyType === "inset" ? "primary" : "default"}
|
|
|
|
+ onClick={() => (data.moveKeyType = "inset")}
|
|
|
|
+ >
|
|
|
|
+ <NIcon component={GripLinesVertical} />
|
|
|
|
+ 最靠近
|
|
|
|
+ </NButton>
|
|
|
|
+ <NButton
|
|
|
|
+ secondary
|
|
|
|
+ type={data.moveKeyType === "down" ? "primary" : "default"}
|
|
|
|
+ onClick={() => (data.moveKeyType = "down")}
|
|
|
|
+ >
|
|
<NIcon component={LongArrowAltDown} />
|
|
<NIcon component={LongArrowAltDown} />
|
|
向下移调
|
|
向下移调
|
|
</NButton>
|
|
</NButton>
|
|
- <NButton secondary onClick={() => handleMoveKey(1)}>
|
|
|
|
|
|
+ <NButton
|
|
|
|
+ secondary
|
|
|
|
+ type={data.moveKeyType === "up" ? "primary" : "default"}
|
|
|
|
+ onClick={() => (data.moveKeyType = "up")}
|
|
|
|
+ >
|
|
<NIcon component={LongArrowAltUp} />
|
|
<NIcon component={LongArrowAltUp} />
|
|
向上移调
|
|
向上移调
|
|
</NButton>
|
|
</NButton>
|
|
@@ -1385,19 +1390,24 @@ export default defineComponent({
|
|
<div class={styles.btnLineTitle}>目标音调</div>
|
|
<div class={styles.btnLineTitle}>目标音调</div>
|
|
|
|
|
|
<NGrid cols={5} yGap={8}>
|
|
<NGrid cols={5} yGap={8}>
|
|
- {ABC_DATA.key.map((item) => (
|
|
|
|
- <NGi>
|
|
|
|
- <div
|
|
|
|
- class={styles.btnItem}
|
|
|
|
- onClick={() => handleChange({ type: "key", value: item.value })}
|
|
|
|
- >
|
|
|
|
- <div class={[styles.btnItemIcon]}>
|
|
|
|
- <TheIcon iconClassName={item.icon} />
|
|
|
|
|
|
+ {ABC_DATA.key
|
|
|
|
+ .sort((a, b) => b.step - a.step)
|
|
|
|
+ .map((item) => (
|
|
|
|
+ <NGi>
|
|
|
|
+ <div
|
|
|
|
+ class={[
|
|
|
|
+ styles.btnItem,
|
|
|
|
+ abcData.abc.transposeKey === item.value && styles.btnItemActive,
|
|
|
|
+ ]}
|
|
|
|
+ onClick={() => handleMoveKey(item)}
|
|
|
|
+ >
|
|
|
|
+ <div class={[styles.btnItemIcon]}>
|
|
|
|
+ <TheIcon iconClassName={item.icon} />
|
|
|
|
+ </div>
|
|
|
|
+ <div class={styles.btnItemName}>{item.name}</div>
|
|
</div>
|
|
</div>
|
|
- <div class={styles.btnItemName}>{item.name}</div>
|
|
|
|
- </div>
|
|
|
|
- </NGi>
|
|
|
|
- ))}
|
|
|
|
|
|
+ </NGi>
|
|
|
|
+ ))}
|
|
</NGrid>
|
|
</NGrid>
|
|
</>
|
|
</>
|
|
),
|
|
),
|
|
@@ -1822,11 +1832,8 @@ export default defineComponent({
|
|
</div>
|
|
</div>
|
|
<div id="paper"></div>
|
|
<div id="paper"></div>
|
|
<Keys show={data.active ? true : false} onClick={(val) => handleChange(val)} />
|
|
<Keys show={data.active ? true : false} onClick={(val) => handleChange(val)} />
|
|
- {/* <div>
|
|
|
|
- <button onClick={handleCreateSvg}>重置曲谱</button>
|
|
|
|
- </div> */}
|
|
|
|
|
|
|
|
- <div style={{ display: "none" }}>
|
|
|
|
|
|
+ {/* <div>
|
|
<textarea
|
|
<textarea
|
|
ref={textAreaRef}
|
|
ref={textAreaRef}
|
|
class={styles.value}
|
|
class={styles.value}
|
|
@@ -1837,7 +1844,7 @@ export default defineComponent({
|
|
handleResetRender();
|
|
handleResetRender();
|
|
}}
|
|
}}
|
|
></textarea>
|
|
></textarea>
|
|
- </div>
|
|
|
|
|
|
+ </div> */}
|
|
<div id="audio" style={{ opacity: 0 }}></div>
|
|
<div id="audio" style={{ opacity: 0 }}></div>
|
|
<div id="warnings"></div>
|
|
<div id="warnings"></div>
|
|
|
|
|