You've already forked AstralRinth
forked from didirus/AstralRinth
Knossos Catch-up (#58)
* Knossos Catch-up * bump version * fix build * fix build again * Fix lint * downgrade pnpm * fix modals * fix btn style * add missing styles
This commit is contained in:
28
.github/workflows/build.yml
vendored
28
.github/workflows/build.yml
vendored
@@ -16,18 +16,26 @@ jobs:
|
|||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 18.x
|
||||||
- name: Get yarn cache
|
- name: Install pnpm via corepack
|
||||||
id: yarn-cache
|
shell: bash
|
||||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
run: |
|
||||||
- uses: actions/cache@v3
|
corepack enable
|
||||||
|
corepack prepare --activate
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
id: pnpm-cache
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||||
|
- name: Setup pnpm cache
|
||||||
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.yarn-cache.outputs.dir }}
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-yarn-
|
${{ runner.os }}-pnpm-store-
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --immutable --immutable-cache --check-cache
|
run: pnpm install
|
||||||
- name: Run Lint
|
- name: Run Lint
|
||||||
run: npm run lint
|
run: pnpm lint
|
||||||
- name: Build
|
- name: Build
|
||||||
run: npm run build
|
run: pnpm build
|
||||||
|
|||||||
29
.github/workflows/publish.yml
vendored
29
.github/workflows/publish.yml
vendored
@@ -17,15 +17,28 @@ jobs:
|
|||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 18.x
|
||||||
registry-url: https://registry.npmjs.org/
|
- name: Install pnpm via corepack
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
id: pnpm-cache
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||||
|
- name: Setup pnpm cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --immutable --immutable-cache --check-cache
|
run: pnpm install
|
||||||
|
- name: Build
|
||||||
- name: Build package
|
run: pnpm build
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
- name: Publish package
|
- name: Publish package
|
||||||
run: npm publish
|
run: pnpm publish
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|||||||
@@ -2,13 +2,23 @@
|
|||||||
:::raw
|
:::raw
|
||||||
|
|
||||||
<DemoContainer>
|
<DemoContainer>
|
||||||
<Button :action="() => this.$refs.reportModal.modal.show()">Show Modal</Button>
|
<Button :action="() => this.$refs.reportModal.show()">Show Report Modal</Button>
|
||||||
|
<Button :action="() => this.$refs.confirmModal.show()">Show Confirm Modal</Button>
|
||||||
<ModalReport
|
<ModalReport
|
||||||
ref="reportModal"
|
ref="reportModal"
|
||||||
itemType="project"
|
itemType="project"
|
||||||
:reportTypes="['cringitude', 'rudeness', 'notgamer', 'windowsuser']"
|
:reportTypes="['cringitude', 'rudeness', 'notgamer', 'windowsuser']"
|
||||||
>
|
>
|
||||||
</ModalReport>
|
</ModalReport>
|
||||||
|
<ModalConfirm
|
||||||
|
ref="confirmModal"
|
||||||
|
title="Are you sure you want to delete this version?"
|
||||||
|
description="This will remove this version forever (like really forever)."
|
||||||
|
:has-to-type="true"
|
||||||
|
proceed-label="Delete"
|
||||||
|
confirmationText="Hello"
|
||||||
|
>
|
||||||
|
</ModalConfirm>
|
||||||
</DemoContainer>
|
</DemoContainer>
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|||||||
5
lib/assets/icons/history.svg
Normal file
5
lib/assets/icons/history.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M3 3v5h5"></path>
|
||||||
|
<path d="M3.05 13A9 9 0 1 0 6 5.3L3 8"></path>
|
||||||
|
<path d="M12 7v5l4 2"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 299 B |
@@ -13,3 +13,6 @@
|
|||||||
|
|
||||||
// Finally, apply accessibility-related global styling
|
// Finally, apply accessibility-related global styling
|
||||||
@import 'styles/accessibility';
|
@import 'styles/accessibility';
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
@import 'styles/inter';
|
||||||
|
|||||||
@@ -160,6 +160,14 @@
|
|||||||
margin-bottom: var(--gap-md);
|
margin-bottom: var(--gap-md);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
@@ -965,9 +973,10 @@ select {
|
|||||||
.multiselect__placeholder {
|
.multiselect__placeholder {
|
||||||
color: var(--color-base);
|
color: var(--color-base);
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
|
margin-bottom: 8px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1.25rem;
|
line-height: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,3 +1025,38 @@ select {
|
|||||||
border-top-left-radius: var(--radius-md) !important;
|
border-top-left-radius: var(--radius-md) !important;
|
||||||
border-top-right-radius: var(--radius-md) !important;
|
border-top-right-radius: var(--radius-md) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
grid-gap: var(--gap-sm);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
max-width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.multiselect {
|
||||||
|
width: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex-shrink: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.shrink-first {
|
||||||
|
:first-child {
|
||||||
|
flex-shrink: 2;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-basis: min-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(:first-child) {
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.push-right:not(.input-group),
|
||||||
|
.push-right.input-group > :first-child {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|||||||
40
lib/assets/styles/inter.scss
Normal file
40
lib/assets/styles/inter.scss
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Regular.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Regular.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Medium.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Medium.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-SemiBold.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-SemiBold.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Bold.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-Bold.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('https://cdn-raw.modrinth.com/fonts/inter/Inter-ExtraBold.woff2?v=3.19') format('woff2'),
|
||||||
|
url('https://cdn-raw.modrinth.com/fonts/inter/Inter-ExtraBold.woff?v=3.19') format('woff');
|
||||||
|
}
|
||||||
@@ -2,10 +2,13 @@
|
|||||||
<img
|
<img
|
||||||
v-if="src"
|
v-if="src"
|
||||||
ref="img"
|
ref="img"
|
||||||
:class="`avatar size-${size} ${circle ? 'circle' : ''} ${noShadow ? 'no-shadow' : ''}`"
|
:class="`avatar size-${size} ${circle ? 'circle' : ''} ${noShadow ? 'no-shadow' : ''} ${
|
||||||
|
pixelated ? 'pixelated' : ''
|
||||||
|
}`"
|
||||||
:src="src"
|
:src="src"
|
||||||
:alt="alt"
|
:alt="alt"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
|
@load="updatePixelated"
|
||||||
/>
|
/>
|
||||||
<svg
|
<svg
|
||||||
v-else
|
v-else
|
||||||
@@ -60,21 +63,20 @@ export default {
|
|||||||
default: 'eager',
|
default: 'eager',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
data() {
|
||||||
if (this.$refs.img && this.$refs.img.naturalWidth) {
|
return {
|
||||||
const isPixelated = () => {
|
pixelated: false,
|
||||||
if (this.$refs.img.naturalWidth < 96 && this.$refs.img.naturalWidth > 0) {
|
|
||||||
this.$refs.img.style.imageRendering = 'pixelated'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.$refs.img.naturalWidth) {
|
|
||||||
isPixelated()
|
|
||||||
} else {
|
|
||||||
this.$refs.img.onload = isPixelated
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
updatePixelated() {
|
||||||
|
if (this.$refs.img && this.$refs.img.naturalWidth && this.$refs.img.naturalWidth <= 96) {
|
||||||
|
this.pixelated = true
|
||||||
|
} else {
|
||||||
|
this.pixelated = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -122,5 +124,9 @@ export default {
|
|||||||
&.no-shadow {
|
&.no-shadow {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.pixelated {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ defineProps({
|
|||||||
|
|
||||||
&.type--accepted,
|
&.type--accepted,
|
||||||
&.type--admin,
|
&.type--admin,
|
||||||
|
&.type--success,
|
||||||
&.green {
|
&.green {
|
||||||
--badge-color: var(--color-green);
|
--badge-color: var(--color-green);
|
||||||
}
|
}
|
||||||
@@ -98,12 +99,12 @@ defineProps({
|
|||||||
&.type--creator,
|
&.type--creator,
|
||||||
&.type--approved,
|
&.type--approved,
|
||||||
&.blue {
|
&.blue {
|
||||||
color: var(--color-blue);
|
--badge-color: var(--color-blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.type--unlisted,
|
&.type--unlisted,
|
||||||
&.purple {
|
&.purple {
|
||||||
color: var(--color-purple);
|
--badge-color: var(--color-purple);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.type--private,
|
&.type--private,
|
||||||
|
|||||||
51
lib/components/base/Breadcrumbs.vue
Normal file
51
lib/components/base/Breadcrumbs.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<nav class="breadcrumbs">
|
||||||
|
<template v-for="(link, index) in linkStack" :key="index">
|
||||||
|
<RouterLink
|
||||||
|
:to="link.href"
|
||||||
|
class="breadcrumb goto-link"
|
||||||
|
:class="{ trim: link.allowTrimming ? link.allowTrimming : false }"
|
||||||
|
>
|
||||||
|
{{ link.label }}
|
||||||
|
</RouterLink>
|
||||||
|
<ChevronRightIcon />
|
||||||
|
</template>
|
||||||
|
<span class="breadcrumb">{{ currentTitle }}</span>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ChevronRightIcon } from '@/components'
|
||||||
|
defineProps({
|
||||||
|
linkStack: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
currentTitle: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.breadcrumbs {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: var(--gap-lg);
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.breadcrumb {
|
||||||
|
padding-block: var(--gap-xs);
|
||||||
|
&.trim {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,7 +2,13 @@
|
|||||||
<label :class="{ 'long-style': longStyle }" @drop.prevent="handleDrop" @dragover.prevent>
|
<label :class="{ 'long-style': longStyle }" @drop.prevent="handleDrop" @dragover.prevent>
|
||||||
<slot />
|
<slot />
|
||||||
{{ prompt }}
|
{{ prompt }}
|
||||||
<input type="file" :multiple="multiple" :accept="accept" @change="handleChange" />
|
<input
|
||||||
|
type="file"
|
||||||
|
:multiple="multiple"
|
||||||
|
:accept="accept"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -42,6 +48,10 @@ export default defineComponent({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
emits: ['change'],
|
emits: ['change'],
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -1,58 +1,66 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div v-if="shown">
|
||||||
<div
|
<div
|
||||||
:class="{
|
:class="{
|
||||||
shown: shown,
|
shown: actuallyShown,
|
||||||
noblur: noblur,
|
noblur: props.noblur,
|
||||||
}"
|
}"
|
||||||
class="modal-overlay"
|
class="modal-overlay"
|
||||||
@click="hide"
|
@click="hide"
|
||||||
/>
|
/>
|
||||||
<div class="modal-body" :class="{ shown: shown }">
|
<div class="modal-container" :class="{ shown: actuallyShown }">
|
||||||
<div v-if="header" class="header">
|
<div class="modal-body">
|
||||||
<h1>{{ header }}</h1>
|
<div v-if="props.header" class="header">
|
||||||
<button class="btn icon-only transparent" @click="hide">
|
<h1>{{ props.header }}</h1>
|
||||||
<XIcon />
|
<button class="btn icon-only transparent" @click="hide">
|
||||||
</button>
|
<XIcon />
|
||||||
</div>
|
</button>
|
||||||
<div class="content">
|
</div>
|
||||||
<slot />
|
<div class="content">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { XIcon } from '@/components'
|
import { XIcon } from '@/components'
|
||||||
</script>
|
import { ref } from 'vue'
|
||||||
<script>
|
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
props: {
|
header: {
|
||||||
header: {
|
type: String,
|
||||||
type: String,
|
default: null,
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
noblur: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
data() {
|
noblur: {
|
||||||
return {
|
type: Boolean,
|
||||||
shown: false,
|
default: false,
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
show() {
|
|
||||||
this.shown = true
|
|
||||||
},
|
|
||||||
hide() {
|
|
||||||
this.shown = false
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const shown = ref(false)
|
||||||
|
const actuallyShown = ref(false)
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
shown.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
actuallyShown.value = true
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
actuallyShown.value = false
|
||||||
|
setTimeout(() => {
|
||||||
|
shown.value = false
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
hide,
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -64,7 +72,6 @@ export default defineComponent({
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
|
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
|
|
||||||
&.shown {
|
&.shown {
|
||||||
@@ -79,48 +86,62 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-body {
|
.modal-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 50%;
|
top: 0;
|
||||||
transform: translate(-50%, -50%);
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
z-index: 21;
|
z-index: 21;
|
||||||
box-shadow: var(--shadow-raised), var(--shadow-inset);
|
visibility: hidden;
|
||||||
border-radius: var(--radius-lg);
|
pointer-events: none;
|
||||||
max-height: calc(100% - 2 * var(--gap-lg));
|
|
||||||
overflow-y: auto;
|
|
||||||
width: 600px;
|
|
||||||
|
|
||||||
.header {
|
&.shown {
|
||||||
display: flex;
|
visibility: visible;
|
||||||
justify-content: space-between;
|
.modal-body {
|
||||||
align-items: center;
|
opacity: 1;
|
||||||
background-color: var(--color-bg);
|
visibility: visible;
|
||||||
padding: var(--gap-md) var(--gap-lg);
|
transform: translateY(0);
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
color: var(--color-contrast);
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.modal-body {
|
||||||
background-color: var(--color-raised-bg);
|
position: fixed;
|
||||||
}
|
box-shadow: var(--shadow-raised), var(--shadow-inset);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
max-height: calc(100% - 2 * var(--gap-lg));
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 600px;
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
top: calc(100% + 400px);
|
.header {
|
||||||
visibility: hidden;
|
display: flex;
|
||||||
opacity: 0;
|
justify-content: space-between;
|
||||||
transition: all 0.25s ease-in-out;
|
align-items: center;
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
padding: var(--gap-md) var(--gap-lg);
|
||||||
|
|
||||||
&.shown {
|
h1 {
|
||||||
opacity: 1;
|
font-weight: bold;
|
||||||
visibility: visible;
|
font-size: 1.25rem;
|
||||||
top: 50%;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 650px) {
|
.content {
|
||||||
width: calc(100% - 2 * var(--gap-lg));
|
background-color: var(--color-raised-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
transform: translateY(50vh);
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.25s ease-in-out;
|
||||||
|
|
||||||
|
@media screen and (max-width: 650px) {
|
||||||
|
width: calc(100% - 2 * var(--gap-lg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
122
lib/components/base/ModalConfirm.vue
Normal file
122
lib/components/base/ModalConfirm.vue
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<Modal ref="modal" :header="props.title">
|
||||||
|
<div class="modal-delete">
|
||||||
|
<div class="markdown-body" v-html="renderString(props.description)" />
|
||||||
|
<label v-if="props.hasToType" for="confirmation" class="confirmation-label">
|
||||||
|
<span>
|
||||||
|
<strong>To verify, type</strong>
|
||||||
|
<em class="confirmation-text">{{ props.confirmationText }}</em>
|
||||||
|
<strong>below:</strong>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div class="confirmation-input">
|
||||||
|
<input
|
||||||
|
v-if="props.hasToType"
|
||||||
|
id="confirmation"
|
||||||
|
v-model="confirmation_typed"
|
||||||
|
type="text"
|
||||||
|
placeholder="Type here..."
|
||||||
|
@input="type"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="input-group push-right">
|
||||||
|
<button class="btn" @click="modal.hide()">
|
||||||
|
<XIcon />
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-danger" :disabled="action_disabled" @click="proceed">
|
||||||
|
<TrashIcon />
|
||||||
|
{{ props.proceedLabel }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { renderString } from '@/helpers/parse'
|
||||||
|
import { XIcon, TrashIcon, Modal } from '@/components'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
confirmationText: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
hasToType: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: 'No title defined',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: 'No description defined',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
proceedLabel: {
|
||||||
|
type: String,
|
||||||
|
default: 'Proceed',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['proceed'])
|
||||||
|
const modal = ref(null)
|
||||||
|
|
||||||
|
const action_disabled = ref(props.hasToType)
|
||||||
|
const confirmation_typed = ref('')
|
||||||
|
|
||||||
|
function proceed() {
|
||||||
|
modal.value.hide()
|
||||||
|
emit('proceed')
|
||||||
|
}
|
||||||
|
|
||||||
|
function type() {
|
||||||
|
if (props.hasToType) {
|
||||||
|
action_disabled.value =
|
||||||
|
confirmation_typed.value.toLowerCase() !== props.confirmationText.toLowerCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
modal.value.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ show })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.modal-delete {
|
||||||
|
padding: var(--gap-lg);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.markdown-body {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirmation-label {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirmation-text {
|
||||||
|
padding-right: 0.25ch;
|
||||||
|
margin: 0 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirmation-input {
|
||||||
|
input {
|
||||||
|
width: 20rem;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal ref="modal" :header="`Report ${itemType}`">
|
<Modal ref="modal" :header="`Report ${props.itemType}`">
|
||||||
<div class="modal-report">
|
<div class="modal-report">
|
||||||
<div class="markdown-body">
|
<div class="markdown-body">
|
||||||
<p>
|
<p>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<router-link to="/legal/rules">Rules</router-link>
|
<router-link to="/legal/rules">Rules</router-link>
|
||||||
. Rest assured, we’ll keep your identifying information private.
|
. Rest assured, we’ll keep your identifying information private.
|
||||||
</p>
|
</p>
|
||||||
<p v-if="itemType === 'project' || itemType === 'version'">
|
<p v-if="props.itemType === 'project' || props.itemType === 'version'">
|
||||||
Please <strong>do not</strong> use this to report bugs with the project itself. This form
|
Please <strong>do not</strong> use this to report bugs with the project itself. This form
|
||||||
is only for submitting a report to Modrinth staff. If the project has an Issues link or a
|
is only for submitting a report to Modrinth staff. If the project has an Issues link or a
|
||||||
Discord invite, consider reporting it there.
|
Discord invite, consider reporting it there.
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<DropdownSelect
|
<DropdownSelect
|
||||||
id="report-type"
|
id="report-type"
|
||||||
v-model="reportType"
|
v-model="reportType"
|
||||||
:options="reportTypes"
|
:options="props.reportTypes"
|
||||||
default-value="Choose report type"
|
default-value="Choose report type"
|
||||||
class="multiselect"
|
class="multiselect"
|
||||||
/>
|
/>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else class="preview" v-html="renderString(body)"></div>
|
<div v-else class="preview" v-html="renderString(body)"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-group">
|
<div class="input-group push-right">
|
||||||
<Button @click="cancel">
|
<Button @click="cancel">
|
||||||
<XIcon />
|
<XIcon />
|
||||||
Cancel
|
Cancel
|
||||||
@@ -59,52 +59,46 @@ import { Modal, Chips, XIcon, CheckIcon, DropdownSelect } from '@/components'
|
|||||||
import { renderString } from '@/helpers/parse.js'
|
import { renderString } from '@/helpers/parse.js'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
const modal = ref('modal')
|
const props = defineProps({
|
||||||
defineExpose({
|
itemType: {
|
||||||
modal: modal,
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
itemId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
reportTypes: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
submitReport: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
itemType: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
itemId: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
reportTypes: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
submitReport: {
|
|
||||||
type: Function,
|
|
||||||
default: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
reportType: '',
|
|
||||||
body: '',
|
|
||||||
bodyViewType: 'source',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
renderString,
|
|
||||||
cancel() {
|
|
||||||
this.reportType = ''
|
|
||||||
this.body = ''
|
|
||||||
this.bodyViewType = 'source'
|
|
||||||
|
|
||||||
this.$refs.modal.hide()
|
const reportType = ref('')
|
||||||
},
|
const body = ref('')
|
||||||
show() {
|
const bodyViewType = ref('source')
|
||||||
this.$refs.modal.show()
|
|
||||||
},
|
const modal = ref(null)
|
||||||
},
|
|
||||||
|
function cancel() {
|
||||||
|
reportType.value = ''
|
||||||
|
body.value = ''
|
||||||
|
bodyViewType.value = 'source'
|
||||||
|
|
||||||
|
modal.value.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
modal.value.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -126,13 +120,6 @@ export default {
|
|||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
|
||||||
margin-left: auto;
|
|
||||||
display: flex;
|
|
||||||
grid-gap: 0.5rem;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-input {
|
.text-input {
|
||||||
height: 12rem;
|
height: 12rem;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ export { default as DropArea } from './base/DropArea.vue'
|
|||||||
export { default as Toggle } from './base/Toggle.vue'
|
export { default as Toggle } from './base/Toggle.vue'
|
||||||
export { default as CopyCode } from './base/CopyCode.vue'
|
export { default as CopyCode } from './base/CopyCode.vue'
|
||||||
export { default as Notifications } from './base/Notifications.vue'
|
export { default as Notifications } from './base/Notifications.vue'
|
||||||
|
export { default as ModalConfirm } from './base/ModalConfirm.vue'
|
||||||
|
export { default as Breadcrumbs } from './base/Breadcrumbs.vue'
|
||||||
|
|
||||||
export { default as Categories } from './search/Categories.vue'
|
export { default as Categories } from './search/Categories.vue'
|
||||||
export { default as SearchFilter } from './search/SearchFilter.vue'
|
export { default as SearchFilter } from './search/SearchFilter.vue'
|
||||||
@@ -72,6 +74,7 @@ export { default as HammerIcon } from '@/assets/icons/hammer.svg'
|
|||||||
export { default as HashIcon } from '@/assets/icons/hash.svg'
|
export { default as HashIcon } from '@/assets/icons/hash.svg'
|
||||||
export { default as HeartIcon } from '@/assets/icons/heart.svg'
|
export { default as HeartIcon } from '@/assets/icons/heart.svg'
|
||||||
export { default as HeartHandshakeIcon } from '@/assets/icons/heart-handshake.svg'
|
export { default as HeartHandshakeIcon } from '@/assets/icons/heart-handshake.svg'
|
||||||
|
export { default as HistoryIcon } from '@/assets/icons/history.svg'
|
||||||
export { default as HomeIcon } from '@/assets/icons/home.svg'
|
export { default as HomeIcon } from '@/assets/icons/home.svg'
|
||||||
export { default as ImageIcon } from '@/assets/icons/image.svg'
|
export { default as ImageIcon } from '@/assets/icons/image.svg'
|
||||||
export { default as InfoIcon } from '@/assets/icons/info.svg'
|
export { default as InfoIcon } from '@/assets/icons/info.svg'
|
||||||
|
|||||||
@@ -42,9 +42,12 @@ export default {
|
|||||||
:deep(span) {
|
:deep(span) {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
color: var(--color-icon);
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
&:not(.version-badge) {
|
||||||
|
color: var(--color-gray);
|
||||||
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
margin-right: 0.2rem;
|
margin-right: 0.2rem;
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ export const configuredXss = new xss.FilterXSS({
|
|||||||
kbd: ['id'],
|
kbd: ['id'],
|
||||||
input: ['checked', 'disabled', 'type'],
|
input: ['checked', 'disabled', 'type'],
|
||||||
iframe: ['width', 'height', 'allowfullscreen', 'frameborder', 'start', 'end'],
|
iframe: ['width', 'height', 'allowfullscreen', 'frameborder', 'start', 'end'],
|
||||||
img: [...xss.whiteList.img, 'style'],
|
img: [...xss.whiteList.img, 'usemap'],
|
||||||
|
map: ['name'],
|
||||||
|
area: [...xss.whiteList.a, 'coords'],
|
||||||
a: [...xss.whiteList.a, 'rel'],
|
a: [...xss.whiteList.a, 'rel'],
|
||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
@@ -56,6 +58,42 @@ export const configuredXss = new xss.FilterXSS({
|
|||||||
return name + '="' + xss.escapeAttrValue(value) + '"'
|
return name + '="' + xss.escapeAttrValue(value) + '"'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
safeAttrValue(tag, name, value, cssFilter) {
|
||||||
|
if (tag === 'img' && name === 'src' && !value.startsWith('data:')) {
|
||||||
|
try {
|
||||||
|
const url = new URL(value)
|
||||||
|
|
||||||
|
const allowedHostnames = [
|
||||||
|
'imgur.com',
|
||||||
|
'i.imgur.com',
|
||||||
|
'cdn-raw.modrinth.com',
|
||||||
|
'cdn.modrinth.com',
|
||||||
|
'staging-cdn-raw.modrinth.com',
|
||||||
|
'staging-cdn.modrinth.com',
|
||||||
|
'github.com',
|
||||||
|
'raw.githubusercontent.com',
|
||||||
|
'img.shields.io',
|
||||||
|
'i.postimg.cc',
|
||||||
|
'wsrv.nl',
|
||||||
|
'cf.way2muchnoise.eu',
|
||||||
|
'bstats.org',
|
||||||
|
]
|
||||||
|
|
||||||
|
if (!allowedHostnames.includes(url.hostname)) {
|
||||||
|
return xss.safeAttrValue(
|
||||||
|
tag,
|
||||||
|
name,
|
||||||
|
`https://wsrv.nl/?url=${encodeURIComponent(value)}&n=-1`,
|
||||||
|
cssFilter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xss.safeAttrValue(tag, name, value, cssFilter)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const md = (options = {}) => {
|
export const md = (options = {}) => {
|
||||||
@@ -96,47 +134,6 @@ export const md = (options = {}) => {
|
|||||||
return defaultLinkOpenRenderer(tokens, idx, options, env, self)
|
return defaultLinkOpenRenderer(tokens, idx, options, env, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultImageRenderer =
|
|
||||||
md.renderer.rules.image ||
|
|
||||||
function (tokens, idx, options, _env, self) {
|
|
||||||
return self.renderToken(tokens, idx, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
md.renderer.rules.image = function (tokens, idx, options, env, self) {
|
|
||||||
const token = tokens[idx]
|
|
||||||
const index = token.attrIndex('src')
|
|
||||||
|
|
||||||
if (index !== -1) {
|
|
||||||
const src = token.attrs[index][1]
|
|
||||||
|
|
||||||
try {
|
|
||||||
const url = new URL(src)
|
|
||||||
|
|
||||||
const allowedHostnames = [
|
|
||||||
'imgur.com',
|
|
||||||
'i.imgur.com',
|
|
||||||
'cdn-raw.modrinth.com',
|
|
||||||
'cdn.modrinth.com',
|
|
||||||
'staging-cdn-raw.modrinth.com',
|
|
||||||
'staging-cdn.modrinth.com',
|
|
||||||
'github.com',
|
|
||||||
'raw.githubusercontent.com',
|
|
||||||
'img.shields.io',
|
|
||||||
'i.postimg.cc',
|
|
||||||
]
|
|
||||||
|
|
||||||
if (allowedHostnames.includes(url.hostname)) {
|
|
||||||
return defaultImageRenderer(tokens, idx, options, env, self)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
/* empty */
|
|
||||||
}
|
|
||||||
token.attrs[index][1] = `https://wsrv.nl/?url=${encodeURIComponent(src)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultImageRenderer(tokens, idx, options, env, self)
|
|
||||||
}
|
|
||||||
|
|
||||||
return md
|
return md
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
export const formatNumber = (number) => {
|
export const formatNumber = (number, abbreviate = true) => {
|
||||||
const x = +number
|
const x = +number
|
||||||
if (x >= 1000000) {
|
if (x >= 1000000 && abbreviate) {
|
||||||
return (x / 1000000).toFixed(2).toString() + 'M'
|
return (x / 1000000).toFixed(2).toString() + 'M'
|
||||||
} else if (x >= 10000) {
|
} else if (x >= 10000 && abbreviate) {
|
||||||
return (x / 1000).toFixed(1).toString() + 'K'
|
return (x / 1000).toFixed(1).toString() + 'k'
|
||||||
} else {
|
} else {
|
||||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatMoney(number) {
|
export function formatMoney(number, abbreviate = false) {
|
||||||
const x = +number
|
const x = +number
|
||||||
if (x >= 1000000) {
|
if (x >= 1000000 && abbreviate) {
|
||||||
return '$' + (x / 1000000).toFixed(2).toString() + 'M'
|
return '$' + (x / 1000000).toFixed(2).toString() + 'M'
|
||||||
} else if (x >= 10000) {
|
} else if (x >= 10000 && abbreviate) {
|
||||||
return '$' + (x / 1000).toFixed(1).toString() + 'K'
|
return '$' + (x / 1000).toFixed(2).toString() + 'k'
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
'$' +
|
'$' +
|
||||||
|
|||||||
34
package.json
34
package.json
@@ -3,7 +3,8 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.4.21",
|
"version": "0.4.21",
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist",
|
||||||
|
"lib"
|
||||||
],
|
],
|
||||||
"main": "./dist/omorphia.umd.cjs",
|
"main": "./dist/omorphia.umd.cjs",
|
||||||
"module": "./dist/omorphia.js",
|
"module": "./dist/omorphia.js",
|
||||||
@@ -17,7 +18,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"lint:js": "eslint --ext .js,.vue,.ts,.jsx,.tsx,.html,.vue .",
|
"lint:js": "eslint --ext .js,.vue,.ts,.jsx,.tsx,.html,.vue .",
|
||||||
"lint": "npm run lint:js && prettier --check .",
|
"lint": "pnpm run lint:js && prettier --check .",
|
||||||
"fix": "eslint --fix --ext .js,.vue,.ts,.jsx,.tsx,.html,.vue . && prettier --write .",
|
"fix": "eslint --fix --ext .js,.vue,.ts,.jsx,.tsx,.html,.vue . && prettier --write .",
|
||||||
"docs:dev": "vitepress dev docs",
|
"docs:dev": "vitepress dev docs",
|
||||||
"docs:build": "vitepress build docs",
|
"docs:build": "vitepress build docs",
|
||||||
@@ -26,27 +27,28 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"floating-vue": "^2.0.0-beta.20",
|
"floating-vue": "^2.0.0-beta.20",
|
||||||
"highlight.js": "^11.7.0",
|
"highlight.js": "^11.8.0",
|
||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.2.1",
|
||||||
"vue-select": "^4.0.0-beta.6",
|
"vue-select": "^4.0.0-beta.6",
|
||||||
"xss": "^1.0.14"
|
"xss": "^1.0.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^4.0.0",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
"eslint": "^8.33.0",
|
"eslint": "^8.41.0",
|
||||||
"eslint-config-prettier": "^8.6.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-vue": "^9.9.0",
|
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"postcss": "^8.4.21",
|
"eslint-plugin-vue": "^9.14.1",
|
||||||
|
"postcss": "^8.4.24",
|
||||||
"postcss-prefix-selector": "^1.16.0",
|
"postcss-prefix-selector": "^1.16.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.8.8",
|
||||||
"sass": "^1.57.1",
|
"sass": "^1.62.1",
|
||||||
"sass-loader": "^13.2.0",
|
"sass-loader": "^13.3.1",
|
||||||
"vite": "^4.0.0",
|
"vite": "^4.3.9",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-svg-loader": "^4.0.0",
|
"vite-svg-loader": "^4.0.0",
|
||||||
"vitepress": "^1.0.0-alpha.46"
|
"vitepress": "^1.0.0-beta.1"
|
||||||
}
|
},
|
||||||
|
"packageManager": "pnpm@8.5.1"
|
||||||
}
|
}
|
||||||
|
|||||||
2459
pnpm-lock.yaml
generated
Normal file
2459
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user