ECMAPortal integration / Development start

This commit is contained in:
Andrew Illarionov 2023-11-10 18:42:55 +03:00
parent c5f9981c86
commit 309452f16e
13 changed files with 10009 additions and 35 deletions

20
.eslintrc.cjs Normal file
View File

@ -0,0 +1,20 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
},
extends: [
'@nuxtjs/eslint-config-typescript',
'plugin:nuxt/recommended',
'prettier',
],
plugins: [],
// add your custom rules here
rules: {
'no-console': 'off',
indent: ['error', 2],
'vue/no-multiple-template-root': 'off',
quotes: [2, 'single', { avoidEscape: true }],
},
}

96
.prettierignore Normal file
View File

@ -0,0 +1,96 @@
###
# Place your Prettier ignore content here
###
# .gitignore content is duplicated here due to https://github.com/prettier/prettier/issues/8506
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# IDE / Editor
.idea
# Service worker
sw.*
# macOS
.DS_Store
# Vim swap files
*.swp

6
.prettierrc Normal file
View File

@ -0,0 +1,6 @@
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all"
}

89
app.vue
View File

@ -1,5 +1,90 @@
<template>
<script>
// Lazy loading: prepend Lazy to the component name.
// Imports come from #components (usually it's an auto import though)
// Auto import from npm package
/* import { addComponent, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup() {
// import { MyComponent as MyAutoImportedComponent } from 'my-npm-package'
addComponent({
name: 'MyAutoImportedComponent',
export: 'MyComponent',
filePath: 'my-npm-package',
})
},
}) */
// Client components: Component.client.vue
// .client components are rendered only after being mounted
// To access the rendered template using onMounted(), add await nextTick() in the callback of the onMounted() hook.
// <ClientOnly></ClientOnly>
// Use slot as fallback until clientonly is mounted:
/* <template>
<div>
<NuxtWelcome />
<Sidebar />
<!-- This renders the "span" element on the server side -->
<ClientOnly fallbackTag="span">
<!-- this component will only be rendered on client side -->
<Comments />
<template #fallback>
<!-- this will be rendered on server side -->
<p>Loading comments...</p>
</template>
</ClientOnly>
</div>
</template> */
// <DevOnly></DevOnly>
/* <DevOnly>
<!-- this component will only be rendered during development -->
<LazyDebugBar />
<!-- if you ever require to have a replacement during production -->
<!-- be sure to test these using `nuxt preview` -->
<template #fallback>
<div><!-- empty div for flex.justify-between --></div>
</template>
</DevOnly> */
// <NuxtClientFallback></NuxtClientFallback> component to render its content on the client if any of its children trigger an error in SSR.
// You can specify a fallbackTag to make it render a specific tag if it fails to render on the server.
/* <template>
<div>
<Sidebar />
<!-- this component will be rendered on client-side -->
<NuxtClientFallback fallback-tag="span">
<Comments />
<BrokeInSSR />
</NuxtClientFallback>
</div>
</template> */
// Then in awesome-ui/nuxt.js you can use the components:dirs hook:
/* import { defineNuxtModule, createResolver } from '@nuxt/kit'
export default defineNuxtModule({
hooks: {
'components:dirs': (dirs) => {
const { resolve } = createResolver(import.meta.url)
// Add ./components dir to the list
dirs.push({
path: resolve('./components'),
prefix: 'awesome'
})
}
}
}) */
/* export default defineNuxtConfig({
modules: ['awesome-ui/nuxt']
}) */
// Catch-all route using <ContentDoc> component
/*
<template>
<main>
<ContentDoc :path="$route.path" />
</main>
</template>
*/
</script>
<template>
<main></main>
<ECMAPortal directory="/images/portal" animate randomize fade />
</template>

14
assets/styles/main.css Normal file
View File

@ -0,0 +1,14 @@
body {
background-color: rgb(6, 25, 28);
background-image: url("~/assets/images/sky.png");
background-attachment: fixed;
background-size: cover;
background-blend-mode: multiply;
image-rendering: pixelated;
background-repeat: no-repeat;
color: white;
font-family: "Lato", sans-serif;
font-size: 18px;
}
/*# sourceMappingURL=main.css.map */

View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["main.scss"],"names":[],"mappings":"AAAA;EACE;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA","file":"main.css"}

14
assets/styles/main.scss Normal file
View File

@ -0,0 +1,14 @@
body {
background-color: rgb(6, 25, 28);
background-image: url('~/assets/images/sky.png');
background-attachment: fixed;
background-size: cover;
background-blend-mode: multiply;
image-rendering: pixelated;
background-repeat: no-repeat;
color: white;
font-family: 'Lato', sans-serif;
font-size: 18px;
}

635
components/ECMAPortal.vue Normal file
View File

@ -0,0 +1,635 @@
<script setup lang="ts">
const props = defineProps({
directory: {
default: '/images/portal',
type: String,
},
create: Boolean,
animate: Boolean,
randomize: Boolean,
fade: Boolean,
speed: {
default: 1,
type: Number,
},
})
class Canvas {
element: HTMLCanvasElement
constructor(create: boolean = true, transparent: boolean = false) {
this.element = create ? this.create() : this.query()
if (transparent) this.element.style.opacity = '0'
this.fill()
}
create(): HTMLCanvasElement {
const canvas = document.createElement('canvas')
canvas.width = window.innerWidth
canvas.height = window.innerHeight
canvas.style.display = 'block'
canvas.style.position = 'fixed'
canvas.style.bottom = '0'
canvas.style.left = '0'
canvas.style.zIndex = '-1'
canvas.style.transition = 'all 0.69420s ease-in'
canvas.innerHTML =
'<span>Your browser does not support the &lt;canvas /&gt; element, which is required for parallax animation.</span>'
// Add a class for subclassing support.
canvas.classList.add('ecmaportal')
canvas.id = 'ecmaportal'
document.body.appendChild(canvas)
return canvas
}
compatible(
obj: HTMLCanvasElement | HTMLElement | Element,
): obj is HTMLCanvasElement {
return obj.tagName === 'CANVAS'
}
query(): HTMLCanvasElement {
const canvas = document.querySelector('#ecmaportal')
if (!canvas) throw new Error('ECMAPortal canvas not found.')
if (!this.compatible(canvas))
throw new Error('The ECMAPortal element is not a canvas.')
return canvas
}
fadeIn() {
this.element.style.opacity = '1'
}
fadeOut() {
this.element.style.opacity = '0'
}
fill() {
this.element.width = window.innerWidth
this.element.height = window.innerHeight
}
full(): boolean {
return (
this.element.width === window.innerWidth &&
this.element.height === window.innerHeight
)
}
destroy() {
this.element.remove()
}
}
class Portal {
private readonly version: string = '1.4T'
private readonly canvas: Canvas
private readonly prog?: WebGLProgram | null
private readonly gl: WebGL2RenderingContext | null
private animate: boolean = false
private readonly randomize: boolean = false
private speed: number = 1
private readonly initialSpeed: number = 1
private readonly dv = 20
// It's integral for the animation to tie it to the current time, else it will be tied to the framerate.
private currentTime: number = Date.now()
private pauseTime: number = 0
private clickTime: number = 0
private tick: number = 0
private dt: number = 6 / 1000000
private promises: Promise<HTMLImageElement>[] = []
private uniforms!: {
modelViewMatrix: WebGLUniformLocation
projectionMatrix: WebGLUniformLocation
dt: WebGLUniformLocation
resolution: WebGLUniformLocation
sky: WebGLUniformLocation
particles: WebGLUniformLocation
}
constructor(
directory: string = '/',
create: boolean = true,
animate: boolean = true,
randomize: boolean = false,
fade: boolean = false,
speed: number = 1,
) {
// Vertex shader.
const vglsl = `#version 300 es
layout (location = 0) in vec3 Position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform vec2 canvasResolution;
vec4 projection_from_position(vec4 position) {
vec4 projection = position * 0.5;
projection.xy = vec2(projection.x + projection.w, projection.y + projection.w);
projection.zw = position.zw;
return projection;
}
out vec4 texProj0;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(Position, 1.0);
texProj0 = projection_from_position(gl_Position);
texProj0 = vec4(texProj0.xy * canvasResolution / max(canvasResolution.x, canvasResolution.y), texProj0.zw);
}`
// Fragment shader.
const fglsl = `#version 300 es
precision highp float;
uniform sampler2D sky;
uniform sampler2D particles;
uniform float dt;
in vec4 texProj0;
const int LAYERS = 15;
const vec3 COLORS[] = vec3[](
vec3(0.022087, 0.098399, 0.110818),
vec3(0.011892, 0.095924, 0.089485),
vec3(0.027636, 0.101689, 0.100326),
vec3(0.046564, 0.109883, 0.114838),
vec3(0.064901, 0.117696, 0.097189),
vec3(0.063761, 0.086895, 0.123646),
vec3(0.084817, 0.111994, 0.166380),
vec3(0.097489, 0.154120, 0.091064),
vec3(0.106152, 0.131144, 0.195191),
vec3(0.097721, 0.110188, 0.187229),
vec3(0.133516, 0.138278, 0.148582),
vec3(0.070006, 0.243332, 0.235792),
vec3(0.196766, 0.142899, 0.214696),
vec3(0.047281, 0.315338, 0.321970),
vec3(0.204675, 0.390010, 0.302066),
vec3(0.080955, 0.314821, 0.661491)
);
const mat4 SCALE_TRANSLATE = mat4(
0.5, 0.0, 0.0, 0.25,
0.0, 0.5, 0.0, 0.25,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
mat2 mat2_rotate_z(float radians) {
return mat2(
cos(radians), -sin(radians),
sin(radians), cos(radians)
);
}
mat4 portal_layer(float layer) {
mat4 translate = mat4(
1.0, 0.0, 0.0, 17.0 / layer,
0.0, 1.0, 0.0, (2.0 + layer / 1.5) * (dt * 1.5),
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
mat2 rotate = mat2_rotate_z(radians((layer * layer * 4321.0 + layer * 9.0) * 2.0));
mat2 scale = mat2((4.5 - layer / 4.0) * 2.0);
return mat4(scale * rotate) * translate * SCALE_TRANSLATE;
}
out vec4 fragColor;
void main() {
vec3 color = textureProj(sky, texProj0).rgb * COLORS[0];
for (int i = 0; i < LAYERS; i++) {
color += textureProj(particles, texProj0 * portal_layer(float(i + 1))).rgb * COLORS[i];
}
fragColor = vec4(color, 1.0);
}`
// Make sure the resource directory ends with a slash.
if (directory.at(-1) !== '/') directory += '/'
// Images to load.
const images = [`${directory}sky.png`, `${directory}particles.png`]
// Notice.
this.notice()
// Set initial property values.
this.animate = animate
this.randomize = randomize
// Set default speed.
this.speed = speed
this.initialSpeed = this.speed
this.dv = 20
// Create a canvas and acquire its context.
this.canvas = new Canvas(create, fade)
this.gl = this.canvas.element.getContext('webgl2')
// If WebGL isn't part of available features, fail.
if (!this.gl) {
this.canvas.destroy()
alert(
'Unable to initialize WebGL 2.\nThe website will lack parallax animation.',
)
console.error(
'Unable to initialize WebGL 2. Your browser or machine may not support it.',
)
return
}
// Get current tick and slightly randomize it if animation is enabled.
this.tick = Number(this.animate && this.randomize) * this.randomRange(0, 10)
// Build shaders.
this.prog = this.build(vglsl, fglsl)
if (!this.prog) {
this.canvas.destroy()
alert(
'Failed to compile WebGL 2 shaders.\nOpen the developer console for debug output.',
)
return
}
// Add an event listener to the canvas if animation is enabled.
if (this.animate) this.canvas.element.onclick = this.click.bind(this)
// Bind class context to the resize handler, pass it to the event bus.
window.addEventListener('resize', this.resize.bind(this))
// Create image loading promises.
this.promises = images.map((image) => this.loadImage(image))
// Initialize the scene.
this.initialize()
// Once all promises have been fulfilled, build the scene.
Promise.all(this.promises).then((resources) => {
// Load resources.
resources.forEach((image, index) => this.loadResource(image, index))
// Bind program
this.gl!.useProgram(this.prog!)
// Begin render.
this.render()
if (fade) this.canvas.fadeIn()
})
}
notice() {
console.log(
`%c \u2587%c\u2587%c\u2587 %c\u2587%c\u2587%c\u2587 %c // ECMAPortal v${this.version} by Endermanch & WiPet\n\n\thttps://enderman.ch\n\thttps://go.enderman.ch/wipet`,
'color: #E58EFF',
'color: #D52DFF',
'color: #E58EFF',
'color: #E58EFF',
'color: #D52DFF',
'color: #E58EFF',
'color: #008000',
)
console.log(
'If any errors occur below, please send a screenshot of them my way!\n\t%ccontact@enderman.ch',
'color: #87CEFA',
)
}
randomRange(min: number, max: number): number {
return Math.random() * (max - min) + min
}
build(vshSource: string, fshSource: string): WebGLProgram | null {
const vsh = this.gl!.createShader(this.gl!.VERTEX_SHADER)
this.gl!.shaderSource(vsh!, vshSource)
this.gl!.compileShader(vsh!)
if (!this.gl!.getShaderParameter(vsh!, this.gl!.COMPILE_STATUS)) {
console.error(this.gl!.getShaderInfoLog(vsh!))
return null
}
const fsh = this.gl!.createShader(this.gl!.FRAGMENT_SHADER)
this.gl!.shaderSource(fsh!, fshSource)
this.gl!.compileShader(fsh!)
if (!this.gl!.getShaderParameter(fsh!, this.gl!.COMPILE_STATUS)) {
console.error(this.gl!.getShaderInfoLog(fsh!))
return null
}
const program: WebGLProgram = this.gl!.createProgram()!
this.gl!.attachShader(program, vsh!)
this.gl!.attachShader(program, fsh!)
this.gl!.linkProgram(program)
if (!this.gl!.getProgramParameter(program, this.gl!.LINK_STATUS)) {
console.error(this.gl!.getProgramInfoLog(program))
return null
}
return program
}
loadImage(url: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = url
})
}
loadResource(image: HTMLImageElement, index: number) {
const samplerParameters = [this.gl!.CLAMP_TO_EDGE, this.gl!.MIRRORED_REPEAT]
const sampler = this.gl!.createSampler()!
this.gl!.samplerParameteri(
sampler,
this.gl!.TEXTURE_WRAP_S,
samplerParameters[index],
)
this.gl!.samplerParameteri(
sampler,
this.gl!.TEXTURE_WRAP_T,
samplerParameters[index],
)
this.gl!.samplerParameteri(
sampler,
this.gl!.TEXTURE_WRAP_R,
samplerParameters[index],
)
this.gl!.samplerParameteri(
sampler,
this.gl!.TEXTURE_MIN_FILTER,
this.gl!.NEAREST_MIPMAP_LINEAR,
)
this.gl!.samplerParameteri(
sampler,
this.gl!.TEXTURE_MAG_FILTER,
this.gl!.NEAREST,
)
this.gl!.bindSampler(index, sampler)
const texture = this.gl!.createTexture()
this.gl!.activeTexture(this.gl!.TEXTURE0 + index)
this.gl!.bindTexture(this.gl!.TEXTURE_2D, texture)
this.gl!.texImage2D(
this.gl!.TEXTURE_2D,
0,
this.gl!.RGBA,
this.gl!.RGBA,
this.gl!.UNSIGNED_BYTE,
image,
)
this.gl!.generateMipmap(this.gl!.TEXTURE_2D)
}
initialize() {
this.uniforms = {
modelViewMatrix: this.gl!.getUniformLocation(
this.prog!,
'modelViewMatrix',
)!,
projectionMatrix: this.gl!.getUniformLocation(
this.prog!,
'projectionMatrix',
)!,
dt: this.gl!.getUniformLocation(this.prog!, 'dt')!,
resolution: this.gl!.getUniformLocation(this.prog!, 'canvasResolution')!,
sky: this.gl!.getUniformLocation(this.prog!, 'sky')!,
particles: this.gl!.getUniformLocation(this.prog!, 'particles')!,
}
const vertexPosBuffer = this.gl!.createBuffer()
const positions = new Float32Array([
-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
])
this.gl!.bindBuffer(this.gl!.ARRAY_BUFFER, vertexPosBuffer)
this.gl!.bufferData(this.gl!.ARRAY_BUFFER, positions, this.gl!.STATIC_DRAW)
this.gl!.bindBuffer(this.gl!.ARRAY_BUFFER, null)
const vertexTexBuffer = this.gl!.createBuffer()
const texCoords = new Float32Array([
0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
])
this.gl!.bindBuffer(this.gl!.ARRAY_BUFFER, vertexTexBuffer)
this.gl!.bufferData(this.gl!.ARRAY_BUFFER, texCoords, this.gl!.STATIC_DRAW)
this.gl!.bindBuffer(this.gl!.ARRAY_BUFFER, null)
const vertexPosLocation = 0
this.gl!.bindBuffer(this.gl!.ARRAY_BUFFER, vertexPosBuffer)
this.gl!.vertexAttribPointer(
vertexPosLocation,
2,
this.gl!.FLOAT,
false,
0,
0,
)
this.gl!.enableVertexAttribArray(vertexPosLocation)
this.gl!.bindBuffer(this.gl!.ARRAY_BUFFER, null)
const vertexTexLocation = 4
this.gl!.bindBuffer(this.gl!.ARRAY_BUFFER, vertexTexBuffer)
this.gl!.vertexAttribPointer(
vertexTexLocation,
2,
this.gl!.FLOAT,
false,
0,
0,
)
this.gl!.enableVertexAttribArray(vertexTexLocation)
this.gl!.bindBuffer(this.gl!.ARRAY_BUFFER, null)
}
scene() {
const identityMatrix = new Float32Array([
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
1.0,
])
if (this.animate) {
// Speed up the animation if the user has clicked.
if (this.clickTime !== null) {
this.speed =
this.dv * this.initialSpeed -
Math.min(
((Date.now() - this.clickTime) / 100) * this.initialSpeed,
(this.dv - 1) * this.initialSpeed,
)
if (this.speed === this.initialSpeed) this.clickTime = 0
}
// R(t) = t + dt (mod 20)
this.tick += this.dt
this.tick %= 20
}
this.gl!.uniformMatrix4fv(
this.uniforms.modelViewMatrix,
false,
identityMatrix,
)
this.gl!.uniformMatrix4fv(
this.uniforms.projectionMatrix,
false,
identityMatrix,
)
this.gl!.uniform2f(
this.uniforms.resolution,
this.canvas.element.width,
this.canvas.element.height,
)
this.gl!.uniform1f(this.uniforms.dt, this.tick)
this.gl!.uniform1i(this.uniforms.sky, 0)
this.gl!.uniform1i(this.uniforms.particles, 1)
this.gl!.drawArraysInstanced(this.gl!.TRIANGLES, 0, 6, 1)
}
render() {
// Make sure the viewport matches the size of the canvas' drawingBuffer.
this.gl!.viewport(
0,
0,
this.gl!.drawingBufferWidth,
this.gl!.drawingBufferHeight,
)
// Calculate the delta time.
this.dt = ((Date.now() - this.currentTime) * this.speed) / 1000000
this.currentTime = Date.now()
// Run the scene.
this.scene()
// Request the next animation frame if animation is enabled.
if (this.animate) requestAnimationFrame(this.render.bind(this))
}
resize() {
if (!this.canvas.full()) this.canvas.fill()
// If we have animation disabled, we still have to re-render the scene once on resize.
if (!this.animate) requestAnimationFrame(this.render.bind(this))
}
click() {
this.clickTime = Date.now()
}
continue() {
if (this.pauseTime === 0) return
// Add the time that has passed since the pause to the current time.
this.currentTime += Date.now() - this.pauseTime
this.pauseTime = 0
this.animate = true
this.render()
}
pause() {
if (this.pauseTime !== 0) return
// Save the pause time to calculate the delta time.
this.pauseTime = Date.now()
this.animate = false
}
destroy() {
// Doesn't need to be called usually, the garbage collector should do its job.
// The method isn't implemented, but the pseudocode is as follows:
// this.gl!.deleteBuffer(vertexPosBuffer);
// this.gl!.deleteBuffer(vertexTexBuffer);
// this.gl!.deleteSampler(sampler);
// this.gl!.deleteTexture(texture);
this.gl!.deleteProgram(this.prog!)
}
}
onMounted(
() =>
new Portal(
props.directory,
props.create,
props.animate,
props.randomize,
props.fade,
props.speed,
),
)
</script>
<template>
<canvas id="ecmaportal" class="parallax">
<span>
Your browser does not support the &lt;canvas /&gt; element, which is
required for parallax animation.
</span>
</canvas>
</template>
<style scoped>
.parallax {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: all 0.6942s ease-in;
}
</style>

View File

@ -1,4 +1,39 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true }
app: {
head: {
title: "Enderman's Website",
htmlAttrs: {
lang: 'en',
},
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
'http-equiv': 'X-UA-Compatible',
content: 'ie=edge',
},
],
},
},
components: {
dirs: [
{
path: '~/components',
pathPrefix: false,
extensions: ['.vue'],
},
],
},
css: ['~/assets/styles/main.css'],
plugins: [],
modules: ['@nuxt/content', '@nuxtjs/eslint-module', '@pinia/nuxt'],
typescript: {
typeCheck: true,
},
})

9087
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,33 @@
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
"postinstall": "nuxt prepare",
"lint:js": "eslint --ext \".js,.ts,.vue\" --ignore-path .gitignore .",
"lint:prettier": "prettier --check .",
"lint": "npm run lint:js && npm run lint:style && npm run lint:prettier",
"lintfix": "prettier --write --list-different . && npm run lint:js -- --fix"
},
"devDependencies": {
"@nuxt/content": "^2.9.0",
"@nuxt/devtools": "latest",
"@nuxt/types": "^2.17.2",
"@nuxtjs/eslint-config-typescript": "^12.1.0",
"@nuxtjs/eslint-module": "^4.1.0",
"@pinia/nuxt": "^0.5.1",
"@typescript-eslint/parser": "^6.10.0",
"eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-nuxt": "^4.0.0",
"eslint-plugin-prettier": "^5.0.1",
"nuxt": "^3.8.1",
"prettier": "^3.0.3",
"sass": "^1.69.5",
"typescript": "^5.2.2",
"vue": "^3.3.8",
"vue-router": "^4.2.5"
"vue-router": "^4.2.5",
"vue-tsc": "^1.8.22"
},
"dependencies": {
"pinia": "^2.1.7"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,3 +1,21 @@
{
"extends": "../.nuxt/tsconfig.server.json"
"compilerOptions": {
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "Node",
"lib": ["ESNext", "ESNext.AsyncIterable", "DOM"],
"esModuleInterop": true,
"allowJs": true,
"sourceMap": true,
"strict": true,
"noEmit": true,
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"~/*": ["./*"],
"@/*": ["./*"]
},
"types": ["@nuxt/types", "@nuxtjs/axios", "@nuxt/content", "@types/node"]
},
"exclude": ["node_modules", ".nuxt", "dist"]
}