Compare commits
10 Commits
master
...
robbi-insp
Author | SHA1 | Date |
---|---|---|
Khaled Aldayeh | 5e334d3bfd | |
Robert Rapp | 653b9220f8 | |
Robert Rapp | fd3ccb8fa2 | |
Robert Rapp | f33e61f2d3 | |
Robert Rapp | 23ac4743f5 | |
Robert Rapp | 7a40953f04 | |
Robert Rapp | cfc32b0229 | |
Robert Rapp | 63f795d4c9 | |
Robert Rapp | 771a847148 | |
Robert Rapp | bc54b1a089 |
|
@ -0,0 +1,49 @@
|
|||
# Dependency directories
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
||||
# Build directory
|
||||
/dist
|
||||
|
||||
# Various log files
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.editorconfig
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
.vs/
|
||||
.vscode/
|
||||
|
||||
# Operating system files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional gitignore file
|
||||
.gitignore
|
||||
|
||||
# Optional markdown files
|
||||
*.md
|
||||
|
||||
# Optional configuration files
|
||||
*.env
|
||||
*.yml
|
||||
|
||||
# Other unnecessary files
|
||||
*.tar.gz
|
||||
*.zip
|
||||
*.tgz
|
||||
*.gzip
|
|
@ -1,8 +1,35 @@
|
|||
node_modules
|
||||
*.log*
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
.output
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
|
||||
# Nuxt build output
|
||||
.nuxt/
|
||||
dist/
|
||||
.nuxt-build/
|
||||
.output/
|
||||
|
||||
# Production build files
|
||||
build/
|
||||
|
||||
# Generated files
|
||||
.nuxtignore
|
||||
nuxt.config.js
|
||||
nuxt.config.ts
|
||||
|
||||
# Dotfiles and directories
|
||||
.env
|
||||
dist
|
||||
.env.*
|
||||
!.env.example
|
||||
.DS_Store
|
||||
.gitattributes
|
||||
.editorconfig
|
||||
.vscode/
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Local development
|
||||
local/
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
#FROM node:18.14.2 as builder1
|
||||
|
||||
#WORKDIR /app
|
||||
|
||||
#ENV NODE_OPTIONS=--openssl-legacy-provider
|
||||
#COPY package*.json ./
|
||||
|
||||
#RUN npm install
|
||||
|
||||
#COPY . .
|
||||
#FROM node:18.14.2 as run1
|
||||
#WORKDIR /app
|
||||
#COPY package*.json ./
|
||||
#COPY --from=builder /app/.output /.output
|
||||
#EXPOSE 3000
|
||||
#CMD [ "npm", "run", "start" ]
|
||||
|
||||
# Stage 1: Build
|
||||
FROM node:18.14.2 as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install only necessary dependencies for building
|
||||
COPY package*.json ./
|
||||
RUN npm install --only=production
|
||||
|
||||
# Copy the necessary source files to build your application
|
||||
COPY . .
|
||||
|
||||
# Build the application
|
||||
# Add any build scripts here. For example, if you're using a framework
|
||||
# like Next.js, you might run `npm run build` here.
|
||||
RUN npx nuxt build
|
||||
|
||||
# Stage 2: Runtime
|
||||
FROM node:18.14.2-slim as run
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy only necessary files from the builder stage
|
||||
COPY --from=builder /app/package*.json ./
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
# If you have any build output, copy it here
|
||||
COPY --from=builder /app/.output ./.output
|
||||
|
||||
# Copy only the production dependencies
|
||||
RUN npm prune --production
|
||||
|
||||
EXPOSE 3000
|
||||
CMD [ "npm", "run", "start" ]
|
59
README.md
59
README.md
|
@ -1,6 +1,63 @@
|
|||
|
||||
|
||||
|
||||
|
||||
pro Messpunkt
|
||||
125ms
|
||||
LAF90
|
||||
LAF10
|
||||
TargetGain
|
||||
CurrentGain
|
||||
MicrofonSignal clear
|
||||
MicofoneSigal gedämpft (AWeighted)
|
||||
|
||||
[time: 125, values: [35,50,50,40]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Nuxt 3 Minimal Starter
|
||||
|
||||
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
## Preparation
|
||||
To run the project you need to have node 19 installed. As the current version is newer you cannot just start the application if you have downloaded and installed node on your machine. In docker this is solved by the docker script but to run test on your application you need to install the node version manager (nvm).
|
||||
|
||||
1. Install nvm using your terminal:
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
|
||||
|
||||
2. Make nvm available in your terminal. Note: If you install a programm like you cannot just access it via the terminal because it is not registered in the list of commands for your terminal. What you need to do is register it manually. Just paste the following command and hit enter.
|
||||
|
||||
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
|
||||
|
||||
3. You have now nvm available in your terminal so you will install node with version 19 by the command
|
||||
nvm install 19
|
||||
|
||||
4. Now you set the node version of your current terminal to 19. This is necessary every time you run a new terminal, because the default node version is the newest. Just type
|
||||
nvm use 19
|
||||
|
||||
## Setup
|
||||
|
||||
|
@ -40,3 +97,5 @@ npm run preview
|
|||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
<template>
|
||||
<div>
|
||||
<button @click="startMicrophone">Start Microphone</button>
|
||||
<button @click="stopMicrophone">Stop Microphone</button>
|
||||
<div v-if="errorMessage">{{ errorMessage }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
console.log("mounted Bandprocessor");
|
||||
//this.initAudioContext();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
audioContext: null,
|
||||
microphoneStream: null,
|
||||
audioProcessorNode: null,
|
||||
errorMessage: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async initAudioContext() {
|
||||
try {
|
||||
const audioContext = new AudioContext();
|
||||
console.log("Current URL:", window.location.href);
|
||||
await audioContext.audioWorklet.addModule("/scripts/octave.js"
|
||||
|
||||
);
|
||||
// Now the 'bandpass-processor' is registered and can be used
|
||||
} catch (e) {
|
||||
console.error("Error loading audio worklet:", e);
|
||||
}
|
||||
},
|
||||
async startMicrophone() {
|
||||
console.log("Start initialization of AudioContext");
|
||||
try {
|
||||
this.initializeAudioContext();
|
||||
await this.requestMicrophoneAccess();
|
||||
await this.setupAudioProcessing();
|
||||
console.log("AudioContext sucessful initialized");
|
||||
} catch (error) {
|
||||
console.error("Error starting microphone:", error.message);
|
||||
this.errorMessage = error.message;
|
||||
}
|
||||
},
|
||||
stopMicrophone() {
|
||||
this.cleanup();
|
||||
},
|
||||
initializeAudioContext() {
|
||||
this.audioContext = new AudioContext();
|
||||
},
|
||||
async requestMicrophoneAccess() {
|
||||
try {
|
||||
this.microphoneStream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error accessing microphone:", error.message);
|
||||
this.errorMessage =
|
||||
"Microphone access denied. Please grant permission in your browser settings.";
|
||||
throw new Error("Microphone access denied.");
|
||||
}
|
||||
|
||||
if (
|
||||
!this.microphoneStream ||
|
||||
!(this.microphoneStream instanceof MediaStream)
|
||||
) {
|
||||
throw new Error("Microphone stream is not available.");
|
||||
}
|
||||
},
|
||||
async setupAudioProcessing() {
|
||||
try {
|
||||
const microphoneSource = this.audioContext.createMediaStreamSource(
|
||||
this.microphoneStream
|
||||
);
|
||||
await this.audioContext.audioWorklet.addModule("/scripts/octave.js");
|
||||
|
||||
this.audioProcessorNode = new AudioWorkletNode(this.audioContext, 'octave');
|
||||
microphoneSource.connect(this.audioProcessorNode);
|
||||
this.audioProcessorNode.connect(this.audioContext.destination);
|
||||
} catch (error) {
|
||||
console.error("Error setting up audio processing:", error.message);
|
||||
this.errorMessage =
|
||||
"Error setting up audio processing. Please check your microphone and try again.";
|
||||
throw new Error("Audio processing setup failed.");
|
||||
}
|
||||
},
|
||||
cleanup() {
|
||||
if (this.audioContext) {
|
||||
if (this.audioProcessorNode) {
|
||||
this.audioProcessorNode.disconnect();
|
||||
this.audioProcessorNode.port.postMessage({ command: "stop" });
|
||||
}
|
||||
this.audioContext.close();
|
||||
this.resetVariables();
|
||||
}
|
||||
},
|
||||
resetVariables() {
|
||||
this.audioContext = null;
|
||||
this.microphoneStream = null;
|
||||
this.audioProcessorNode = null;
|
||||
this.errorMessage = null;
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.cleanup();
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -137,7 +137,7 @@
|
|||
<span><i class="fa-solid fs-3 fa-arrow-left-long" style="cursor: pointer" data-bs-dismiss="modal"></i></span>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<h4 class="text-center fw-bolder">Adaptive Soundscape</h4>
|
||||
<h4 class="text-center fw-bolder">{{t('Adaptive Soundscape')}} </h4>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<div class="form-check form-switch float-end">
|
||||
|
@ -148,9 +148,9 @@
|
|||
</div>
|
||||
<div class="row px-2 pt-4">
|
||||
<div class="col-12 ps-3 fs-5" style="line-height: 25px">
|
||||
<p class="p-0 m-0"> The Mindboost sounscape responds to the acousitcs in your room.</p>
|
||||
<p class="p-0 m-0"> {{t('The Mindboost sounscape responds to the acousitcs in your room.')}}</p>
|
||||
<p class="p-0 m-0"></p>
|
||||
<p class="">Currently, your room has a:</p>
|
||||
<p class="">{{t('Currently, your room has a:')}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pt-4 ps-3">
|
||||
|
@ -162,8 +162,8 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="col-11 col-md-10 ps-3">
|
||||
<h5>Noisy Environment</h5>
|
||||
<p>The background noise at your workplace is disturbing. Your concentration is severely impaired. Mindboost protects you from the disturbing background noise.</p>
|
||||
<h5>{{t('Noisy Environment')}}</h5>
|
||||
<p>{{ t('The background noise at your workplace is disturbing. Your concentration is severely impaired. Mindboost protects you from the disturbing background noise.')}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -177,8 +177,8 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="col-11 col-md-10 ps-3">
|
||||
<h5>Medium-noise Environment</h5>
|
||||
<p>The background noise at your workplace should be optimized. In the long term, it could disturb and have a negative impact on your health. Protect yourself with mindboost.</p>
|
||||
<h5>{{t('Medium-noise Environment')}}</h5>
|
||||
<p>{{t('The background noise at your workplace should be optimized. In the long term, it could disturb and have a negative impact on your health. Protect yourself with mindboost.')}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -191,9 +191,9 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="col-11 col-md-10 ps-3">
|
||||
<h5>Good Environment</h5>
|
||||
<h5>{{ t('Good Environment')}}</h5>
|
||||
<p>
|
||||
The background noise at your workplace provides a long’term healthy basis for concentrated work. With Mindboost you make sure that even sudden disturbances do not distract you.
|
||||
{{t('The background noise at your workplace provides a long’term healthy basis for concentrated work. With Mindboost you make sure that even sudden disturbances do not distract you.')}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -345,4 +345,4 @@ export default {
|
|||
width: 87%;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -285,6 +285,13 @@ export default defineNuxtConfig({
|
|||
"All soundscapes in Mindboost have been tested and optimized in listening tests in cooperation with the Fraunhofer IBP. So you can be sure that Mindboost supports you optimally with your concentration.":"All soundscapes in Mindboost have been tested and optimized in listening tests in cooperation with the Fraunhofer IBP. So you can be sure that Mindboost supports you optimally with your concentration.",
|
||||
'Audio_Output':'Audio Output',
|
||||
'Audio_Input':'Audio Input',
|
||||
'Language':'Language',
|
||||
'How is your audio hardware connected?':'How is your audio hardware connected?',
|
||||
'select laptop or mobile device microphone':'select laptop or mobile device microphone',
|
||||
'select headphones or headphone output':'select headphones or headphone output',
|
||||
'Output device:':'Output device',
|
||||
'Input device:':'Input device:',
|
||||
'As input, please select the microphone of your laptop or mobile device – not of your headphones.':'As input, please select the microphone of your laptop or mobile device – not of your headphones.',
|
||||
},
|
||||
de: {
|
||||
"welcome": "Willkommen",
|
||||
|
@ -491,6 +498,13 @@ export default defineNuxtConfig({
|
|||
"gemäß Art. 77 DSGVO bei einer Aufsichtsbehörde zu beschweren. In der Regel können Sie sich hierfür an die Aufsichtsbehörde an Ihrem üblichen Aufenthaltsort oder Arbeitsplatz oder unserem Firmensitz wenden.":"gemäß Art. 77 DSGVO bei einer Aufsichtsbehörde zu beschweren. In der Regel können Sie sich hierfür an die Aufsichtsbehörde an Ihrem üblichen Aufenthaltsort oder Arbeitsplatz oder unserem Firmensitz wenden.",
|
||||
'Audio_Output':'Audioausgang',
|
||||
'Audio_Input':'Audioeingang',
|
||||
'Language':'Sprache',
|
||||
'How is your audio hardware connected?':'Wie ist Ihre Audio-Hardware angeschlossen?',
|
||||
'select laptop or mobile device microphone':'Eingangsgerät:',
|
||||
'select headphones or headphone output':'(Mikrofon von Laptop oder Mobilgerät auswählen)',
|
||||
'Output device:':'Ausgangsgerät:',
|
||||
'Input device:':'Eingangsgerät:',
|
||||
'As input, please select the microphone of your laptop or mobile device – not of your headphones.':'Als Eingang wählen Sie bitte das Mikrofon Ihres Laptops oder mobilen Geräts - nicht das Ihres Kopfhörers.',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
|
@ -1,22 +1,24 @@
|
|||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
"build": "npx nuxt build",
|
||||
"dev": "npx nuxt dev",
|
||||
"generate": "npx nuxt generate",
|
||||
"preview": "npx nuxt preview",
|
||||
"postinstall": "npx nuxt prepare",
|
||||
"start": "node .output/server/index.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/vite-builder": "^3.0.0",
|
||||
"@nuxtjs/i18n": "^8.0.0-beta.10",
|
||||
"@nuxtjs/tailwindcss": "^6.1.3",
|
||||
"nuxt": "3.0.0",
|
||||
"nuxt-headlessui": "^1.0.4",
|
||||
"vue-stripe-js": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/vue": "^2.0.13",
|
||||
"nuxt": "3.0.0",
|
||||
"@nuxtjs/i18n": "^8.0.0-beta.10",
|
||||
"nuxt-headlessui": "^1.0.4",
|
||||
"@heroicons/vue": "^2.0.13",
|
||||
"@incuca/vue3-toaster": "^1.1.1",
|
||||
"@meforma/vue-toaster": "^1.3.0",
|
||||
"@pinia/nuxt": "^0.4.6",
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<div>
|
||||
<button @click="startMicrophone">Start Microphone</button>
|
||||
<button @click="stopMicrophone">Stop Microphone</button>
|
||||
<canvas ref="visualizationCanvas" width="800" height="200"></canvas>
|
||||
<div v-if="errorMessage">{{ errorMessage }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
audioContext: null,
|
||||
microphoneStream: null,
|
||||
audioProcessorNode: null,
|
||||
errorMessage: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async startMicrophone() {
|
||||
try {
|
||||
this.initializeAudioContext();
|
||||
await this.requestMicrophoneAccess();
|
||||
await this.setupAudioProcessing();
|
||||
} catch (error) {
|
||||
console.error('Error starting microphone:', error.message);
|
||||
this.errorMessage = error.message;
|
||||
}
|
||||
finally{
|
||||
console.log("Microphone started")
|
||||
}
|
||||
},
|
||||
stopMicrophone() {
|
||||
this.cleanup();
|
||||
},
|
||||
initializeAudioContext() {
|
||||
this.audioContext = new window.AudioContext();
|
||||
},
|
||||
async requestMicrophoneAccess() {
|
||||
try {
|
||||
this.microphoneStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
} catch (error) {
|
||||
console.error('Error accessing microphone:', error.message);
|
||||
this.errorMessage = 'Microphone access denied. Please grant permission in your browser settings.';
|
||||
throw new Error('Microphone access denied.');
|
||||
}
|
||||
|
||||
if (!this.microphoneStream || !(this.microphoneStream instanceof MediaStream)) {
|
||||
throw new Error('Microphone stream is not available.');
|
||||
}
|
||||
},
|
||||
async setupAudioProcessing() {
|
||||
try {
|
||||
const microphoneSource = this.audioContext.createMediaStreamSource(this.microphoneStream);
|
||||
await this.audioContext.audioWorklet.addModule('/scripts/octave2.js');
|
||||
|
||||
//this.audioProcessorNode = new AudioWorkletNode(this.audioContext, 'octave');
|
||||
//microphoneSource.connect(this.audioProcessorNode);
|
||||
//this.audioProcessorNode.connect(this.audioContext.destination);
|
||||
} catch (error) {
|
||||
console.error('Error setting up audio processing:', error.message);
|
||||
this.errorMessage = 'Error setting up audio processing. Please check your microphone and try again.';
|
||||
throw new Error('Audio processing setup failed.');
|
||||
}
|
||||
},
|
||||
cleanup() {
|
||||
if (this.audioContext) {
|
||||
if (this.audioProcessorNode) {
|
||||
this.audioProcessorNode.disconnect();
|
||||
this.audioProcessorNode.port.postMessage({ command: 'stop' });
|
||||
}
|
||||
this.audioContext.close();
|
||||
this.resetVariables();
|
||||
}
|
||||
},
|
||||
resetVariables() {
|
||||
this.audioContext = null;
|
||||
this.microphoneStream = null;
|
||||
this.audioProcessorNode = null;
|
||||
this.errorMessage = null;
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.cleanup();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
poster="/images/poster.png"
|
||||
>
|
||||
<div class="container-fluid overflow-auto" >
|
||||
<div class="row"> <BandProcessor /> <ChannelStreamer /> </div>
|
||||
<div class="row ">
|
||||
<div class="col-12 col-lg-4 bg-img d-none d-lg-block" style="background-image: url('/images/login.svg');background-size: cover;height: 100vh;" >
|
||||
</div>
|
||||
|
@ -68,7 +69,7 @@
|
|||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</video-background>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -76,7 +77,10 @@
|
|||
import backgroundImagePath from '~/assets/image/login4.png';
|
||||
import {useUserStore} from '@/stores/user';
|
||||
import {mapState,mapActions} from "pinia";
|
||||
import BandProcessor from "@/components/BandProcessor";
|
||||
import ChannelStreamer from "@/pages/ChannelStreamer";
|
||||
export default {
|
||||
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
|
@ -86,6 +90,9 @@ export default {
|
|||
localePath,
|
||||
}
|
||||
},
|
||||
//Components BEGIN
|
||||
components: {BandProcessor,ChannelStreamer},
|
||||
//Components END
|
||||
mounted() {
|
||||
// if (this.is_login){
|
||||
// this.$router.push('/onboarding');
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<div class="col-12 text-center pt-5 mt-3 pb-2 mb-2" >
|
||||
<NuxtLink class="btn btn-warning px-2 mx-1" exact-active-class="px-4 mx-2" :to="localePath('/onboarding/selectinput')"></NuxtLink>
|
||||
<NuxtLink class="btn btn-warning px-2" exact-active-class="px-4 mx-2" :to="localePath('/onboarding')"></NuxtLink>
|
||||
<NuxtLink class="btn btn-warning mx-2" exact-active-class="px-4 mx-2" :to="localePath('/onboarding/onboarding2')"></NuxtLink>
|
||||
<NuxtLink class="btn btn-warning px-2 mx-2" exact-active-class="px-4 mx-2" :to="localePath('/onboarding/onboarding2')"></NuxtLink>
|
||||
<NuxtLink class="btn btn-warning px-2 " exact-active-class="px-4 mx-2" :to="localePath('/onboarding/onboarding3')"></NuxtLink>
|
||||
<NuxtLink class="btn btn-warning px-2 mx-2" exact-active-class="px-4 mx-2" :to="localePath('/onboarding/onboarding4')"></NuxtLink>
|
||||
<h6 class="text-muted text-center pt-3">You can customize your selection later</h6>
|
||||
|
@ -132,4 +132,4 @@ export default {
|
|||
.px-4{
|
||||
transition: 1s;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<div class="row">
|
||||
<div class="col-12 ">
|
||||
<h4 class="text-center fw-bold pt-5">{{t("How is your audio hardware connected?")}}</h4>
|
||||
<p class="text-center mb-0 pb-0 text-muted">As input, please select the microphone of your laptop or mobile device – not of your headphones.</p>
|
||||
<p class="text-center mt-0 pt-0 text-muted">To use Mindboost, headphones are required.</p>
|
||||
<p class="text-center mb-0 pb-0 text-muted">{{t('As input, please select the microphone of your laptop or mobile device – not of your headphones.')}}</p>
|
||||
<p class="text-center mt-0 pt-0 text-muted">{{t('To use Mindboost, headphones are required.')}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
|
@ -12,8 +12,8 @@
|
|||
<form>
|
||||
<div class="row justify-content-center ">
|
||||
<div class="col-md-3 text-center">
|
||||
<h6 class="pb-0 mb-0">Input device:</h6>
|
||||
<p class="pt-0 mt-0 text-muted pb-0 mb-0" style="font-size: 14px;font-weight: 500">(select laptop or mobile device microphone)</p>
|
||||
<h6 class="pb-0 mb-0">{{t('Input device:')}}</h6>
|
||||
<p class="pt-0 mt-0 text-muted pb-0 mb-0" style="font-size: 14px;font-weight: 500">({{t('select laptop or mobile device microphone')}})</p>
|
||||
<select class="form-select pt-1 mt-0 select-box " v-model="selectedInput">
|
||||
<option :value="index" v-for="(item,index) in audioInputDevices" :key="index" >{{item.label}}</option>
|
||||
</select>
|
||||
|
@ -22,8 +22,8 @@
|
|||
|
||||
<div class="row justify-content-center pt-3">
|
||||
<div class="col-md-3 text-center">
|
||||
<h6 class="pb-0 mb-0 " >Output device:</h6>
|
||||
<p class="pt-0 mt-0 text-muted pb-0 mb-0" style="font-size: 14px;font-weight: 500">(select headphones or headphone output)</p>
|
||||
<h6 class="pb-0 mb-0 " >{{t('Output device:')}}</h6>
|
||||
<p class="pt-0 mt-0 text-muted pb-0 mb-0" style="font-size: 14px;font-weight: 500">({{ t('select headphones or headphone output')}})</p>
|
||||
<select class="form-select pt-1 mt-0 select-box " v-model="selectedOutput">
|
||||
<option :value="index" v-for="(item,index) in audioOutputDevices" :key="index">{{item.label}}</option>
|
||||
</select>
|
||||
|
@ -32,7 +32,7 @@
|
|||
|
||||
<div class="row justify-content-center pt-3">
|
||||
<div class="col-md-3 text-center" style="z-index: 1000000;">
|
||||
<a href="#" @click.prevent="saveDevices" style="z-index: 1000000" class="btn col-4 next-btn" >NEXT</a>
|
||||
<a href="#" @click.prevent="saveDevices" style="z-index: 1000000" class="btn col-4 next-btn" >{{t("Next")}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -37,6 +37,17 @@
|
|||
<div class="invalid-feedback d-block" v-if="errors.password">{{errors.password[0]}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pt-3">
|
||||
<div class="col-12">
|
||||
<label class="text-muted ">{{t("Language")}} </label>
|
||||
<select @change="changeLanguage" v-model="form.language" class="form-select">
|
||||
<option value="en">English</option>
|
||||
<option value="de">German</option>
|
||||
|
||||
</select>
|
||||
<div class="invalid-feedback d-block" v-if="errors.language">{{errors.language[0]}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pt-5 ">
|
||||
<div class="col-12 text-center">
|
||||
<button type="submit" class="btn text-white fs-5 col-12 fw-bold py-2 " style="background-color: #e9c046">{{t("Save Changes")}} <div v-if="loading" class="spinner-border spinner-border-sm" role="status">
|
||||
|
@ -64,14 +75,23 @@ export default {
|
|||
},
|
||||
setup(){
|
||||
const { t } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
return {t,localePath}
|
||||
const localePath = useLocalePath();
|
||||
const switchLocalePath = useSwitchLocalePath();
|
||||
let changeLanguage=(event)=>{
|
||||
console.log('switch',event.target.value)
|
||||
useRouter().push(switchLocalePath(event.target.value));
|
||||
|
||||
|
||||
// i18n.global.locale.value=
|
||||
}
|
||||
return {t,localePath,changeLanguage}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.user)
|
||||
this.form.first_name=this.user.first_name;
|
||||
this.form.email=this.user.email;
|
||||
this.form.surname=this.user.surname;
|
||||
this.form.language=this.user.language;
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
|
@ -80,7 +100,8 @@ export default {
|
|||
first_name:"",
|
||||
surname:"",
|
||||
email:"email",
|
||||
password:""
|
||||
password:"",
|
||||
language:'en'
|
||||
},
|
||||
errors:[],
|
||||
}
|
||||
|
@ -90,6 +111,10 @@ export default {
|
|||
...mapActions(useUserStore,['updateUser']),
|
||||
saveUser(){
|
||||
this.loading=true;
|
||||
|
||||
this.t.locale.value=this.form.language;
|
||||
|
||||
|
||||
this.$axios.post('/api/account/update',this.form).then(({data})=>{
|
||||
this.loading=false;
|
||||
if(data.success){
|
||||
|
@ -110,4 +135,4 @@ export default {
|
|||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -38,6 +38,16 @@
|
|||
<div class="col-6">
|
||||
<h5 class="fw-bold text-end">•••••••••</h5> </div>
|
||||
</div>
|
||||
<div class="row pt-4">
|
||||
<div class="col-6">
|
||||
<h5 class="fw-bold text-muted">{{ t('Language') }}</h5>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h5 v-if="user.language=='de'" class="fw-bold text-end">German</h5>
|
||||
<h5 v-else class="fw-bold text-end">English</h5>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pt-4">
|
||||
<div class="col-12 text-center">
|
||||
<button @click="logoutNow" class="btn col-12 col-sm-12 col-md-3 fw-bold btn-outline-dark">{{t("Log Out")}} </button>
|
||||
|
@ -98,4 +108,4 @@ export default {
|
|||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,180 @@
|
|||
class OctaveBandProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super()
|
||||
// Define center frequencies for 9 octave bands
|
||||
|
||||
this.centerFrequencies = [63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000]
|
||||
this.filters = []
|
||||
this.lastUpdateTimestamp = 0
|
||||
this.updateInterval = 0.125 // Update every 0.125 seconds
|
||||
this.filteredMicSignal =[]
|
||||
|
||||
// Create an A-weighting filter for specific frequencies
|
||||
this.createAWeightingFilter()
|
||||
|
||||
// Create bandpass filters for each center frequency
|
||||
this.centerFrequencies.forEach((frequency) => {
|
||||
const filter = new BiquadFilterNode(
|
||||
audioContext,
|
||||
{
|
||||
type: "bandpass",
|
||||
frequency: frequency,
|
||||
Q: 1.41, // Set the desired Q value
|
||||
},
|
||||
this.filters.push(filter),
|
||||
)
|
||||
})
|
||||
|
||||
// Set up analyzers for calculating percentiles
|
||||
this.setupAnalyzers()
|
||||
}
|
||||
|
||||
setupAnalyzers() {
|
||||
this.analyzers = []
|
||||
this.centerFrequencies.forEach((frequency) => {
|
||||
this.analyzers.push([])
|
||||
for (let i = 0; i < 5; i++) {
|
||||
// Unique identifiers from 0 to 4
|
||||
const analyzer = audioContext.createAnalyser()
|
||||
analyzer.fftSize = 2048
|
||||
|
||||
// Check if the identifier is 0 (microphone audio) before connecting to the A-weighting filter
|
||||
if (i === 0) {
|
||||
this.aWeightingFilter.connect(analyzer)
|
||||
}
|
||||
|
||||
this.analyzers[this.analyzers.length - 1].push(analyzer)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
process(inputs, outputs) {
|
||||
const numOutputoctaves = filters.length
|
||||
for (let i = 0; i < numOutputoctaves; i++) {
|
||||
// const outputChannel = outputs[i][0]
|
||||
|
||||
const mic = inputs[0]
|
||||
const maskingsig = inputs[1]
|
||||
const harmonic = inputs[2]
|
||||
|
||||
// Apply the filter to the input channel
|
||||
const filteredMicSignal[i] = this.filters[i].process(mic)
|
||||
const filteredMaskSignal = this.filters[i].process(maskingsig)
|
||||
const filteredHarmoSignal = this.filters[i].process(harmonic)
|
||||
|
||||
// Apply A-weighting only to the microphone signal (channel 0)
|
||||
|
||||
const aWeightedSignal[i] = this.aWeightingFilter.process(filteredMicSignal)
|
||||
this.calculateRMSLevel(aWeightedSignal)
|
||||
outputChannel.set(aWeightedSignal)
|
||||
|
||||
// For other channels, pass the signal without A-weighting
|
||||
outputChannel.set(filteredSignal)
|
||||
|
||||
|
||||
// Check if it's time to update percentiles
|
||||
const currentTime = this.currentTime
|
||||
if (currentTime - this.lastUpdateTimestamp >= this.updateInterval) {
|
||||
this.updatePercentiles(i)
|
||||
this.lastUpdateTimestamp = currentTime
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
calculateRMSLevel(signal, channelIndex) {
|
||||
const data = new Float32Array(signal.length)
|
||||
signal.copyFromChannel(data, 0)
|
||||
const sum = data.reduce((acc, val) => acc + val * val, 0)
|
||||
const rmsLevel = Math.sqrt(sum / data.length)
|
||||
const dBLevel = 20 * Math.log10(rmsLevel) // Convert to dB
|
||||
return dBLevel
|
||||
}
|
||||
|
||||
updatePercentiles(channelIndex) {
|
||||
for (let i = 0; i < this.centerFrequencies.length; i++) {
|
||||
//const analyzer = this.analyzers[i][channelIndex]
|
||||
//const levelData = new Float32Array(analyzer.frequencyBinCount)
|
||||
analyzer.getFloatFrequencyData(levelData)
|
||||
|
||||
// Calculate percentiles for each octave band and each channel
|
||||
const percentile10 = this.calculatePercentile(levelData, 10)
|
||||
const percentile90 = this.calculatePercentile(levelData, 90)
|
||||
|
||||
const percentileDiff = percentile10 - percentile90
|
||||
|
||||
// Store the percentile difference for each channel and each octave band
|
||||
// You can use suitable data structures to store these values for future comparisons
|
||||
}
|
||||
}
|
||||
|
||||
calculatePercentile(data, percentile) {
|
||||
const sortedData = data.slice().sort((a, b) => a - b)
|
||||
const index = Math.floor((percentile / 100) * sortedData.length)
|
||||
return sortedData[index]
|
||||
}
|
||||
|
||||
createAWeightingFilter() {
|
||||
// Use the provided A-weighting filter coefficients
|
||||
const aWeightingCoefficients = [
|
||||
0, -0.051, -0.142, -0.245, -0.383, -0.65, -1.293, -2.594, -6.554,
|
||||
] //David
|
||||
|
||||
// Create a custom IIR filter node with the A-weighting coefficients
|
||||
this.aWeightingFilter = new IIRFilterNode(audioContext, { //infinit Impuls Response
|
||||
feedforward: aWeightingCoefficients,
|
||||
feedback: [1],
|
||||
})
|
||||
}
|
||||
|
||||
// combineAndCalculate() {
|
||||
// let LAF10_90_total = 0 // Initialize the total LAF10%-90%
|
||||
|
||||
// for (let i = 0; i < this.centerFrequencies.length; i++) {
|
||||
// const micAnalyzer = this.analyzers[i][0] // Analyzer for microphone audio (identifier 0)
|
||||
// const audioFile1Analyzer = this.analyzers[i][3] // Analyzer for audioFile1 (identifier 3)
|
||||
// const audioFile2Analyzer = this.analyzers[i][4] // Analyzer for audioFile2 (identifier 4)
|
||||
|
||||
// // Calculate percentiles for the microphone audio
|
||||
// const micPercentile10 = this.calculatePercentile(micAnalyzer, 10)
|
||||
// const micPercentile90 = this.calculatePercentile(micAnalyzer, 90)
|
||||
|
||||
// // Calculate percentiles for audioFile1
|
||||
// const audioFile1Percentile10 = this.calculatePercentile(
|
||||
// audioFile1Analyzer,
|
||||
// 10,
|
||||
// )
|
||||
// const audioFile1Percentile90 = this.calculatePercentile(
|
||||
// audioFile1Analyzer,
|
||||
// 90,
|
||||
// )
|
||||
|
||||
// // Calculate percentiles for audioFile2
|
||||
// const audioFile2Percentile10 = this.calculatePercentile(
|
||||
// audioFile2Analyzer,
|
||||
// 10,
|
||||
// )
|
||||
// const audioFile2Percentile90 = this.calculatePercentile(
|
||||
// audioFile2Analyzer,
|
||||
// 90,
|
||||
// )
|
||||
|
||||
// // Calculate LAF10%-90% for microphone audio, audioFile1, and audioFile2 separately
|
||||
// const micLAF10_90 = micPercentile10 - micPercentile90
|
||||
// const audioFile1LAF10_90 = audioFile1Percentile10 - audioFile1Percentile90
|
||||
// const audioFile2LAF10_90 = audioFile2Percentile10 - audioFile2Percentile90
|
||||
|
||||
// // Calculate combined LAF10%-90% for microphone audio, audioFile1, and audioFile2
|
||||
// const combinedLAF10_90 =
|
||||
// micLAF10_90 + audioFile1LAF10_90 + audioFile2LAF10_90
|
||||
|
||||
// // Add the combined LAF10%-90% to the total
|
||||
// LAF10_90_total += combinedLAF10_90
|
||||
// }
|
||||
|
||||
// // return LAF10_90_total;
|
||||
// }
|
||||
}
|
||||
|
||||
registerProcessor("octave", OctaveBandProcessor)
|
|
@ -0,0 +1,153 @@
|
|||
class OctaveBandProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
// Define center frequencies for 9 octave bands
|
||||
this.centerFrequencies = [63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000];
|
||||
this.filters = [];
|
||||
this.lastUpdateTimestamp = 0;
|
||||
this.updateInterval = 0.125; // Update every 0.125 seconds
|
||||
|
||||
// Create an A-weighting filter for specific frequencies
|
||||
this.createAWeightingFilter();
|
||||
|
||||
// Create bandpass filters for each center frequency
|
||||
this.centerFrequencies.forEach(frequency => {
|
||||
const filter = new BiquadFilterNode(audioContext, {
|
||||
type: 'bandpass',
|
||||
frequency: frequency,
|
||||
Q: 1.41, // Set the desired Q value
|
||||
});
|
||||
this.filters.push(filter);
|
||||
});
|
||||
|
||||
// Set up analyzers for calculating percentiles
|
||||
this.setupAnalyzers();
|
||||
}
|
||||
|
||||
createAWeightingFilter() {
|
||||
// Use the provided A-weighting filter coefficients
|
||||
const aWeightingCoefficients = [0, -0.051, -0.142, -0.245, -0.383, -0.65, -1.293, -2.594, -6.554]; //David
|
||||
|
||||
// Create a custom IIR filter node with the A-weighting coefficients
|
||||
this.aWeightingFilter = new IIRFilterNode(audioContext, {
|
||||
feedforward: aWeightingCoefficients,
|
||||
feedback: [1],
|
||||
});
|
||||
}
|
||||
|
||||
setupAnalyzers() {
|
||||
this.analyzers = [];
|
||||
this.centerFrequencies.forEach((frequency) => {
|
||||
this.analyzers.push([]);
|
||||
for (let i = 0; i < 5; i++) { // Unique identifiers from 0 to 4
|
||||
const analyzer = audioContext.createAnalyser();
|
||||
analyzer.fftSize = 2048;
|
||||
|
||||
// Check if the identifier is 0 (microphone audio) before connecting to the A-weighting filter
|
||||
if (i === 0) {
|
||||
this.aWeightingFilter.connect(analyzer);
|
||||
}
|
||||
|
||||
this.analyzers[this.analyzers.length - 1].push(analyzer);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
process(inputs, outputs) {
|
||||
const numOutputChannels = outputs.length;
|
||||
for (let i = 0; i < numOutputChannels; i++) {
|
||||
const outputChannel = outputs[i][0];
|
||||
const inputChannel = inputs[i][0];
|
||||
|
||||
// Apply the filter to the input channel
|
||||
const filteredSignal = this.filters[i].process(inputChannel);
|
||||
|
||||
// Apply A-weighting only to the microphone signal (channel 0)
|
||||
if (i === 0) {
|
||||
const aWeightedSignal = this.aWeightingFilter.process(filteredSignal);
|
||||
outputChannel.set(aWeightedSignal);
|
||||
} else {
|
||||
// For other channels, pass the signal without A-weighting
|
||||
outputChannel.set(filteredSignal);
|
||||
}
|
||||
|
||||
// Check if it's time to update percentiles
|
||||
const currentTime = this.currentTime;
|
||||
if (currentTime - this.lastUpdateTimestamp >= this.updateInterval) {
|
||||
this.updatePercentiles(i);
|
||||
this.lastUpdateTimestamp = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
calculateRMSLevel(signal, channelIndex) {
|
||||
const data = new Float32Array(signal.length);
|
||||
signal.copyFromChannel(data, 0);
|
||||
const sum = data.reduce((acc, val) => acc + val * val, 0);
|
||||
const rmsLevel = Math.sqrt(sum / data.length);
|
||||
const dBLevel = 20 * Math.log10(rmsLevel); // Convert to dB
|
||||
return dBLevel;
|
||||
}
|
||||
|
||||
updatePercentiles(channelIndex) {
|
||||
for (let i = 0; i < this.centerFrequencies.length; i++) {
|
||||
const analyzer = this.analyzers[i][channelIndex];
|
||||
const levelData = new Float32Array(analyzer.frequencyBinCount);
|
||||
analyzer.getFloatFrequencyData(levelData);
|
||||
|
||||
// Calculate percentiles for each octave band and each channel
|
||||
const percentile10 = this.calculatePercentile(levelData, 10);
|
||||
const percentile90 = this.calculatePercentile(levelData, 90);
|
||||
|
||||
const percentileDiff = percentile10 - percentile90;
|
||||
|
||||
// Store the percentile difference for each channel and each octave band
|
||||
// You can use suitable data structures to store these values for future comparisons
|
||||
}
|
||||
}
|
||||
|
||||
calculatePercentile(data, percentile) {
|
||||
const sortedData = data.slice().sort((a, b) => a - b);
|
||||
const index = Math.floor((percentile / 100) * sortedData.length);
|
||||
return sortedData[index];
|
||||
}
|
||||
|
||||
combineAndCalculate() {
|
||||
let LAF10_90_total = 0; // Initialize the total LAF10%-90%
|
||||
|
||||
for (let i = 0; i < this.centerFrequencies.length; i++) {
|
||||
const micAnalyzer = this.analyzers[i][0]; // Analyzer for microphone audio (identifier 0)
|
||||
const audioFile1Analyzer = this.analyzers[i][3]; // Analyzer for audioFile1 (identifier 3)
|
||||
const audioFile2Analyzer = this.analyzers[i][4]; // Analyzer for audioFile2 (identifier 4)
|
||||
|
||||
// Calculate percentiles for the microphone audio
|
||||
const micPercentile10 = this.calculatePercentile(micAnalyzer, 10);
|
||||
const micPercentile90 = this.calculatePercentile(micAnalyzer, 90);
|
||||
|
||||
// Calculate percentiles for audioFile1
|
||||
const audioFile1Percentile10 = this.calculatePercentile(audioFile1Analyzer, 10);
|
||||
const audioFile1Percentile90 = this.calculatePercentile(audioFile1Analyzer, 90);
|
||||
|
||||
// Calculate percentiles for audioFile2
|
||||
const audioFile2Percentile10 = this.calculatePercentile(audioFile2Analyzer, 10);
|
||||
const audioFile2Percentile90 = this.calculatePercentile(audioFile2Analyzer, 90);
|
||||
|
||||
// Calculate LAF10%-90% for microphone audio, audioFile1, and audioFile2 separately
|
||||
const micLAF10_90 = micPercentile10 - micPercentile90;
|
||||
const audioFile1LAF10_90 = audioFile1Percentile10 - audioFile1Percentile90;
|
||||
const audioFile2LAF10_90 = audioFile2Percentile10 - audioFile2Percentile90;
|
||||
|
||||
// Calculate combined LAF10%-90% for microphone audio, audioFile1, and audioFile2
|
||||
const combinedLAF10_90 = micLAF10_90 + audioFile1LAF10_90 + audioFile2LAF10_90;
|
||||
|
||||
// Add the combined LAF10%-90% to the total
|
||||
LAF10_90_total += combinedLAF10_90;
|
||||
}
|
||||
|
||||
return LAF10_90_total;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('octave', OctaveBandProcessor);
|
|
@ -2471,10 +2471,10 @@ es-module-lexer@^0.9.0:
|
|||
resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz"
|
||||
integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
|
||||
|
||||
esbuild-darwin-arm64@0.15.18:
|
||||
esbuild-darwin-64@0.15.18:
|
||||
version "0.15.18"
|
||||
resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz"
|
||||
integrity sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==
|
||||
resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz"
|
||||
integrity sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==
|
||||
|
||||
esbuild@^0.15.14, esbuild@^0.15.9:
|
||||
version "0.15.18"
|
||||
|
@ -4082,7 +4082,7 @@ nuxt-headlessui@^1.0.4:
|
|||
"@nuxt/kit" "^3.0.0"
|
||||
pathe "^1.0.0"
|
||||
|
||||
nuxt@3.0.0:
|
||||
nuxt@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/nuxt/-/nuxt-3.0.0.tgz"
|
||||
integrity sha512-RNlD78uv04ZiXWmlx9f1tnJfrqsYAWHU+4gbgOTQpIBmQzHWPWiox+fm/1m93iKfEd5sJi9TJUoXX5yBObVZYw==
|
||||
|
|
Loading…
Reference in New Issue