#160 picture uploader
This commit is contained in:
parent
b1b65bd789
commit
3a0010fb22
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<a :href="getUrl('big')" target="_blank" rel="noopener"
|
||||
@click.prevent="$eventHub.$emit('lightbox', getUrl('big'))"
|
||||
>
|
||||
<img :src="getUrl('thumb')" class="border rounded-lg"/>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
id: {required: true},
|
||||
},
|
||||
methods: {
|
||||
getUrl(size) {
|
||||
return `${process.env.BUCKET}/images/${this.id}-${size}.png`;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
img {
|
||||
height: 8rem;
|
||||
width: 8rem;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<div
|
||||
:class="['uploader-container', 'p-2', 'form-control', drag ? 'drag' : '']"
|
||||
@dragover="drag=true" @dragleave="drag=false"
|
||||
>
|
||||
<input type="file"
|
||||
:name="name + (multiple ? '[]' : '')"
|
||||
:multiple="multiple"
|
||||
:disabled="uploading"
|
||||
@change="filesChange($event.target.name, $event.target.files)"
|
||||
accept="image/*">
|
||||
<p v-if="errorMessage" class="text-danger">
|
||||
<Icon v="exclamation-circle"/>
|
||||
<T>{{errorMessage}}</T>
|
||||
</p>
|
||||
<p v-else-if="uploading">
|
||||
<Spinner/>
|
||||
</p>
|
||||
<p v-else>
|
||||
<Icon v="upload"/>
|
||||
<T>images.upload.instruction</T>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
multiple: {type: Boolean},
|
||||
name: {'default': 'images'},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uploading: false,
|
||||
drag: false,
|
||||
errorMessage: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async filesChange(fieldName, fileList) {
|
||||
if (!fileList.length) {
|
||||
return;
|
||||
}
|
||||
const formData = new FormData();
|
||||
for (let file of fileList) {
|
||||
formData.append(fieldName, file, file.name);
|
||||
}
|
||||
await this.save(formData);
|
||||
},
|
||||
async save(formData) {
|
||||
this.uploading = true;
|
||||
this.errorMessage = '';
|
||||
try {
|
||||
const ids = await this.$axios.$post('/images/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
this.$emit('uploaded', ids);
|
||||
} catch {
|
||||
this.errorMessage = 'error.generic';
|
||||
}
|
||||
this.uploading = false;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../assets/style";
|
||||
|
||||
.uploader-container {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
&:hover, &.drag {
|
||||
background: lighten($primary, 50%);
|
||||
}
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div class="form-group">
|
||||
<ul class="list-unstyled">
|
||||
<li v-for="image in images" class="mb-4">
|
||||
<ImageThumb :id="image"/>
|
||||
<a href="#" @click.prevent="removeFile(image)" class="small">
|
||||
<Icon v="trash"/>
|
||||
<T>crud.remove</T>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ImageUploader :multiple="multiple" :name="name" @uploaded="addFiles"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {},
|
||||
multiple: {type: Boolean},
|
||||
name: {'default': 'images'},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
images: this.value,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.images = this.value;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addFiles(files) {
|
||||
this.$emit('input', [...this.images, ...files]);
|
||||
},
|
||||
async removeFile(id) {
|
||||
await this.$confirm(this.$t('crud.removeConfirm'), 'danger');
|
||||
this.$emit('input', this.images.filter(i => i !== id));
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<div :class="['lightbox-wrapper', currentUrl === null ? 'd-none' : '']" ref="wrapper" @click.self="hide">
|
||||
<div :class="['lightbox-inner', center ? 'align-items-center' : '']" ref="inner" @click.self="hide">
|
||||
<img class="lightbox-image" :src="currentUrl" ref="image" @load="loaded">
|
||||
</div>
|
||||
<span class="lightbox-menu">
|
||||
<span class="lightbox-close fal fa-times" @click="hide"></span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentUrl: null,
|
||||
center: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$eventHub.$on('lightbox', this.show);
|
||||
|
||||
if (!process.client) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.addEventListener('resize', e => {
|
||||
if (!this.currentUrl) {
|
||||
return;
|
||||
}
|
||||
this.center = this.$refs.image.offsetHeight < this.$refs.inner.offsetHeight;
|
||||
});
|
||||
|
||||
document.body.addEventListener('keyup', e => {
|
||||
if (!this.currentUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.keyCode === 27) { // ESC
|
||||
this.hide();
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
show(url) {
|
||||
this.currentUrl = url;
|
||||
this.$refs.inner.focus();
|
||||
},
|
||||
hide() {
|
||||
this.currentUrl = null;
|
||||
this.$refs.inner.blur();
|
||||
this.center = false;
|
||||
},
|
||||
loaded() {
|
||||
if (this.$refs.image.offsetHeight < this.$refs.inner.offsetHeight) {
|
||||
this.center = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../assets/style";
|
||||
|
||||
.lightbox-wrapper {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
z-index: 10000;
|
||||
|
||||
padding: 2*$spacer 2*$spacer;
|
||||
@include media-breakpoint-up('sm') {
|
||||
padding: 2*$spacer 4*$spacer;
|
||||
}
|
||||
|
||||
.lightbox-inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.lightbox-menu {
|
||||
position: absolute;
|
||||
top: $spacer;
|
||||
right: $spacer;
|
||||
font-size: 2*$spacer;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.lightbox-close {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -9,6 +9,7 @@
|
|||
<Footer/>
|
||||
</div>
|
||||
<Confirm ref="confirm"/>
|
||||
<Lightbox/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -458,6 +458,14 @@ localise:
|
|||
short: 'Adding language versions'
|
||||
long: 'Want to create a new language version? Check out'
|
||||
longLink: 'this manual!'
|
||||
|
||||
images:
|
||||
upload:
|
||||
instruction: 'Click here or drag your pics here' # TODO
|
||||
|
||||
error:
|
||||
generic: 'Something went wrong, please try again…' # TODO
|
||||
|
||||
flags:
|
||||
Abrosexual: 'Abrosexual'
|
||||
Achillean: 'Aquilean{inflection}'
|
||||
|
|
|
@ -459,3 +459,10 @@ localise:
|
|||
short: 'Adding language versions'
|
||||
long: 'Want to create a new language version? Check out'
|
||||
longLink: 'this manual!'
|
||||
|
||||
images:
|
||||
upload:
|
||||
instruction: 'Click here or drag your pics here'
|
||||
|
||||
error:
|
||||
generic: 'Something went wrong, please try again…'
|
||||
|
|
|
@ -467,6 +467,13 @@ localise:
|
|||
long: '¿Quieres añadir una versión en otra lengua? ¡Consulta'
|
||||
longLink: 'este manual!'
|
||||
|
||||
images:
|
||||
upload:
|
||||
instruction: 'Click here or drag your pics here' # TODO
|
||||
|
||||
error:
|
||||
generic: 'Something went wrong, please try again…' # TODO
|
||||
|
||||
flags:
|
||||
Abrosexual: 'Abrosexual'
|
||||
Achillean: 'Aquilean{inflection}'
|
||||
|
|
|
@ -1039,6 +1039,13 @@ localise:
|
|||
long: 'Chcesz dodać nową wersję językową? Informacje znajdziesz w'
|
||||
longLink: 'tej instrukcji.'
|
||||
|
||||
images:
|
||||
upload:
|
||||
instruction: 'Kliknij tutaj lub upuść tu obrazek'
|
||||
|
||||
error:
|
||||
generic: 'Coś poszło nie tak, spróbuj ponownie…'
|
||||
|
||||
flags:
|
||||
Abrosexual: 'Abroseksualn{adjective_n}'
|
||||
Achillean: 'Achillejs{adjective_n_k}'
|
||||
|
|
|
@ -135,6 +135,7 @@ export default {
|
|||
LOCALE: config.locale,
|
||||
LOCALES: locales,
|
||||
FLAGS: buildFlags(),
|
||||
BUCKET: `https://${process.env.AWS_S3_BUCKET}.s3-${process.env.AWS_REGION}.amazonaws.com`,
|
||||
},
|
||||
serverMiddleware: ['~/server/index.js'],
|
||||
axios: {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
"luxon": "^1.25.0",
|
||||
"mailer": "^0.6.7",
|
||||
"markdown-loader": "^6.0.0",
|
||||
"multer": "^1.4.2",
|
||||
"nuxt": "^2.14.7",
|
||||
"sha1": "^1.1.1",
|
||||
"sql-template-strings": "^2.2.2",
|
||||
|
|
|
@ -4,6 +4,7 @@ import config from '../data/config.suml';
|
|||
import {buildDict} from "../src/helpers";
|
||||
|
||||
export default ({ app, store }) => {
|
||||
Vue.prototype.$eventHub = new Vue();
|
||||
Vue.prototype.$base = process.env.BASE_URL;
|
||||
Vue.prototype.$t = t;
|
||||
Vue.prototype.$translateForPronoun = (str, pronoun) =>
|
||||
|
|
|
@ -48,6 +48,8 @@ app.use(require('./routes/terms').default);
|
|||
app.use(require('./routes/pronounce').default);
|
||||
app.use(require('./routes/census').default);
|
||||
|
||||
app.use(require('./routes/images').default);
|
||||
|
||||
export default {
|
||||
path: '/api',
|
||||
handler: app,
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import { Router } from 'express';
|
||||
import {ulid} from "ulid";
|
||||
import multer from 'multer';
|
||||
import {loadImage, createCanvas} from 'canvas';
|
||||
|
||||
import awsConfig from '../aws';
|
||||
import S3 from 'aws-sdk/clients/s3';
|
||||
|
||||
const sizes = {
|
||||
big: [1600, false],
|
||||
thumb: [240, true],
|
||||
}
|
||||
|
||||
const resizeImage = (image, width, height, sx = null, sy = null) => {
|
||||
const canvas = createCanvas(width, height);
|
||||
if (sx === null) {
|
||||
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
|
||||
} else {
|
||||
canvas.getContext('2d').drawImage(image, sx, sy, width, height, 0, 0, width, height);
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
const cropToSquare = (image) => {
|
||||
return image.width > image.height
|
||||
? resizeImage(image, image.height, image.height, (image.width - image.height) / 2, 0)
|
||||
: resizeImage(image, image.width, image.width, 0, (image.height - image.width) / 2);
|
||||
}
|
||||
|
||||
const scaleDownTo = (image, size) => {
|
||||
if (image.width > image.height) {
|
||||
return image.width > size
|
||||
? resizeImage(image, size, image.height * size / image.width)
|
||||
: image;
|
||||
}
|
||||
|
||||
return image.height > size
|
||||
? resizeImage(image, image.width * size / image.height, size)
|
||||
: image;
|
||||
}
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post('/images/upload', multer({limits: {fileSize: 5 * 1024 * 1024}}).any('images[]', 12), async (req, res) => {
|
||||
const s3 = new S3(awsConfig);
|
||||
|
||||
const ids = [];
|
||||
for (let file of req.files) {
|
||||
const id = ulid();
|
||||
const image = await loadImage(file.buffer);
|
||||
|
||||
for (let s in sizes) {
|
||||
if (!sizes.hasOwnProperty(s)) { continue; }
|
||||
const [size, square] = sizes[s];
|
||||
|
||||
let canvas = createCanvas(image.width, image.height);
|
||||
canvas.getContext('2d').drawImage(image, 0, 0);
|
||||
|
||||
if (square) {
|
||||
console.log('crop to square');
|
||||
canvas = cropToSquare(canvas);
|
||||
}
|
||||
|
||||
canvas = scaleDownTo(canvas, size);
|
||||
|
||||
await s3.putObject({
|
||||
Key: `images/${id}-${s}.png`,
|
||||
Body: canvas.toBuffer('image/png'),
|
||||
ContentType: 'image/png',
|
||||
ACL: 'public-read',
|
||||
}).promise();
|
||||
}
|
||||
|
||||
ids.push(id);
|
||||
}
|
||||
return res.json(ids);
|
||||
});
|
||||
|
||||
export default router;
|
64
yarn.lock
64
yarn.lock
|
@ -1842,6 +1842,11 @@ anymatch@~3.1.1:
|
|||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
append-field@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
|
||||
integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
|
||||
|
||||
aproba@^1.0.3, aproba@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
|
||||
|
@ -2335,6 +2340,14 @@ builtin-status-codes@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
||||
|
||||
busboy@^0.2.11:
|
||||
version "0.2.14"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
|
||||
integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=
|
||||
dependencies:
|
||||
dicer "0.2.5"
|
||||
readable-stream "1.1.x"
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
|
@ -2802,7 +2815,7 @@ concat-map@0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
concat-stream@^1.5.0:
|
||||
concat-stream@^1.5.0, concat-stream@^1.5.2:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
|
||||
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
|
||||
|
@ -3431,6 +3444,14 @@ detect-libc@^1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
|
||||
|
||||
dicer@0.2.5:
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
|
||||
integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=
|
||||
dependencies:
|
||||
readable-stream "1.1.x"
|
||||
streamsearch "0.1.2"
|
||||
|
||||
diffie-hellman@^5.0.0:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
|
||||
|
@ -5135,6 +5156,11 @@ is-wsl@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
||||
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
|
||||
|
||||
isarray@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
|
||||
|
||||
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
|
@ -5893,6 +5919,20 @@ ms@2.1.2, ms@^2.1.1:
|
|||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
multer@^1.4.2:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
|
||||
integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==
|
||||
dependencies:
|
||||
append-field "^1.0.0"
|
||||
busboy "^0.2.11"
|
||||
concat-stream "^1.5.2"
|
||||
mkdirp "^0.5.1"
|
||||
object-assign "^4.1.1"
|
||||
on-finished "^2.3.0"
|
||||
type-is "^1.6.4"
|
||||
xtend "^4.0.0"
|
||||
|
||||
mustache@^2.3.0:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.2.tgz#a6d4d9c3f91d13359ab889a812954f9230a3d0c5"
|
||||
|
@ -7517,6 +7557,16 @@ read-cache@^1.0.0:
|
|||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@1.1.x:
|
||||
version "1.1.14"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
||||
integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readable-stream@^3.1.1, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
|
@ -8292,6 +8342,11 @@ stream-shift@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
|
||||
integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
|
||||
|
||||
streamsearch@0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
|
||||
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
|
||||
|
||||
strict-uri-encode@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||
|
@ -8355,6 +8410,11 @@ string_decoder@^1.0.0, string_decoder@^1.1.1:
|
|||
dependencies:
|
||||
safe-buffer "~5.2.0"
|
||||
|
||||
string_decoder@~0.10.x:
|
||||
version "0.10.31"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
||||
integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
|
@ -8705,7 +8765,7 @@ type-fest@^0.8.0, type-fest@^0.8.1:
|
|||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||
|
||||
type-is@~1.6.17, type-is@~1.6.18:
|
||||
type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
|
||||
version "1.6.18"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||
|
|
Reference in New Issue