Rewritten codes for home uploader config.
All options are now defined in a single config object in home.js.
Config tab content will be dynamically generated through that config.
This should eliminate the need of modifying home.njk whenever a new
option needs to be added,
make the codes more readable, and easier to extend.

Upgrade stylelint dev dependency.

Bumped v1 version string.
This commit is contained in:
Bobby Wibowo 2019-10-11 12:36:59 +07:00
parent b2f96360ae
commit 7855801d62
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
7 changed files with 267 additions and 223 deletions

2
dist/js/home.js vendored

File diff suppressed because one or more lines are too long

2
dist/js/home.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -70,7 +70,7 @@
"gulp-stylelint": "^9.0.0",
"gulp-terser": "^1.2.0",
"postcss-preset-env": "^6.7.0",
"stylelint": "^11.0.0",
"stylelint": "^11.1.1",
"stylelint-config-standard": "^19.0.0"
}
}

View File

@ -25,7 +25,7 @@ const page = {
// store album id that will be used with upload requests
album: null,
parallelUploads: null,
parallelUploads: 2,
previewImages: null,
fileLength: null,
uploadAge: null,
@ -587,129 +587,256 @@ page.createAlbum = () => {
page.prepareUploadConfig = () => {
const fallback = {
chunkSize: page.chunkSize,
parallelUploads: 2
parallelUploads: page.parallelUploads
}
page.chunkSize = parseInt(localStorage[lsKeys.chunkSize]) || fallback.chunkSize
page.parallelUploads = parseInt(localStorage[lsKeys.parallelUploads]) || fallback.parallelUploads
document.querySelector('#chunkSize').value = page.chunkSize
document.querySelector('#parallelUploads').value = page.parallelUploads
const temporaryUploadAges = Array.isArray(page.temporaryUploadAges) && page.temporaryUploadAges.length
const fileIdentifierLength = page.fileIdentifierLength &&
typeof page.fileIdentifierLength.min === 'number' &&
typeof page.fileIdentifierLength.max === 'number'
const numConfig = {
chunkSize: { min: 1, max: 95 },
parallelUploads: { min: 1, max: 10 }
}
document.querySelector('#chunkSizeDiv .help').innerHTML =
`Default is ${fallback.chunkSize} MB. Max is ${numConfig.chunkSize.max} MB.`
document.querySelector('#parallelUploadsDiv .help').innerHTML =
`Default is ${fallback.parallelUploads}. Max is ${numConfig.parallelUploads.max}.`
const fileLengthDiv = document.querySelector('#fileLengthDiv')
if (page.fileIdentifierLength && fileLengthDiv) {
const element = document.querySelector('#fileLength')
const stored = parseInt(localStorage[lsKeys.fileLength])
fallback.fileLength = page.fileIdentifierLength.default
let helpText = `Default is ${page.fileIdentifierLength.default}.`
const range = typeof page.fileIdentifierLength.min === 'number' &&
typeof page.fileIdentifierLength.max === 'number'
if (range) {
helpText += ` Min is ${page.fileIdentifierLength.min}. Max is ${page.fileIdentifierLength.max}`
numConfig.fileLength = {
const config = {
siBytes: {
label: 'File size display',
select: [
{ value: 'default', text: '1000 B = 1 kB = 1 Kilobyte' },
{ value: '0', text: '1024 B = 1 KiB = 1 Kibibyte' }
],
help: 'This will be used in our homepage, dashboard, and album public pages.',
valueHandler () {} // Do nothing
},
fileLength: {
display: fileIdentifierLength,
label: 'File identifier length',
number: fileIdentifierLength ? {
min: page.fileIdentifierLength.min,
max: page.fileIdentifierLength.max
max: page.fileIdentifierLength.max,
round: true
} : undefined,
help: true, // true means auto-generated, for number-based configs only
disabled: fileIdentifierLength && page.fileIdentifierLength.force
},
uploadAge: {
display: temporaryUploadAges,
label: 'Upload age',
select: [],
help: 'This allows your files to automatically be deleted after a certain period of time.'
},
chunkSize: {
display: !isNaN(page.chunkSize),
label: 'Upload chunk size (MB)',
number: {
min: 1,
max: 95,
suffix: ' MB',
round: true
},
help: true
},
parallelUploads: {
label: 'Parallel uploads',
number: {
min: 1,
max: 10,
round: true
},
help: true
},
uploadsHistoryOrder: {
label: 'Uploads history order',
select: [
{ value: 'default', text: 'Older files on top' },
{ value: '0', text: 'Newer files on top' }
],
help: `Newer files on top will use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction#Accessibility_Concerns" target="_blank" rel="noopener">a CSS technique</a>.<br>
Trying to select their texts manually from top to bottom will end up selecting the texts from bottom to top instead.`,
valueHandler (value) {
if (value === '0') {
const uploadFields = document.querySelectorAll('.tab-content > .uploads')
for (let i = 0; i < uploadFields.length; i++)
uploadFields[i].classList.add('is-reversed')
}
}
},
previewImages: {
label: 'Load images for preview',
select: [
{ value: 'default', text: 'Yes' },
{ value: '0', text: 'No' }
],
help: 'By default, uploaded images will be loaded as their previews.',
valueHandler (value) {
page.previewImages = value !== '0'
}
}
if (page.fileIdentifierLength.force) {
helpText += ' This option is currently disabled.'
element.disabled = true
}
if (page.fileIdentifierLength.force ||
isNaN(stored) ||
!range ||
stored < page.fileIdentifierLength.min ||
stored > page.fileIdentifierLength.max) {
element.value = fallback.fileLength
page.fileLength = null
} else {
element.value = stored
page.fileLength = stored
}
fileLengthDiv.classList.remove('is-hidden')
fileLengthDiv.querySelector('.help').innerHTML = helpText
}
Object.keys(numConfig).forEach(key => {
document.querySelector(`#${key}`).setAttribute('min', numConfig[key].min)
document.querySelector(`#${key}`).setAttribute('max', numConfig[key].max)
})
const uploadAgeDiv = document.querySelector('#uploadAgeDiv')
if (Array.isArray(page.temporaryUploadAges) && page.temporaryUploadAges.length && uploadAgeDiv) {
const element = document.querySelector('#uploadAge')
if (temporaryUploadAges) {
const stored = parseFloat(localStorage[lsKeys.uploadAge])
for (let i = 0; i < page.temporaryUploadAges.length; i++) {
const age = page.temporaryUploadAges[i]
const option = document.createElement('option')
option.value = i === 0 ? 'default' : age
option.innerHTML = page.getPrettyUploadAge(age) +
(i === 0 ? ' (default)' : '')
element.appendChild(option)
if (age === stored) {
element.value = option.value
page.uploadAge = stored
}
config.uploadAge.select.push({
value: i === 0 ? 'default' : String(age),
text: page.getPrettyUploadAge(age)
})
if (age === stored)
config.uploadAge.value = stored
}
uploadAgeDiv.classList.remove('is-hidden')
}
if (fileIdentifierLength) {
fallback.fileLength = page.fileIdentifierLength.default || undefined
const stored = parseInt(localStorage[lsKeys.fileLength])
if (!page.fileIdentifierLength.force &&
!isNaN(stored) &&
stored >= page.fileIdentifierLength.min &&
stored <= page.fileIdentifierLength.max)
config.fileLength.value = stored
}
const tabContent = document.querySelector('#tab-config')
const form = tabContent.querySelector('form')
form.addEventListener('submit', event => {
event.preventDefault()
})
const form = document.createElement('form')
form.addEventListener('submit', event => event.preventDefault())
const siBytes = localStorage[lsKeys.siBytes] !== '0'
if (!siBytes) document.querySelector('#siBytes').value = '0'
const configKeys = Object.keys(config)
for (let i = 0; i < configKeys.length; i++) {
const key = configKeys[i]
const conf = config[key]
const olderOnTop = localStorage[lsKeys.uploadsHistoryOrder] !== '0'
if (!olderOnTop) {
document.querySelector('#uploadsHistoryOrder').value = '0'
const uploadFields = document.querySelectorAll('.tab-content > .uploads')
for (let i = 0; i < uploadFields.length; i++)
uploadFields[i].classList.add('is-reversed')
// Skip only if display attribute is explicitly set to false
if (conf.display === false)
continue
const field = document.createElement('div')
field.className = 'field'
let value
if (!conf.disabled) {
if (conf.value !== undefined) {
value = conf.value
} else if (conf.number !== undefined) {
const parsed = parseInt(localStorage[lsKeys[key]])
if (!isNaN(parsed))
value = parsed
} else {
value = localStorage[lsKeys[key]]
}
// If valueHandler function exists, defer to the function,
// otherwise pass value to global page object
if (typeof conf.valueHandler === 'function')
conf.valueHandler(value)
else if (value !== undefined)
page[key] = value
}
let control
if (Array.isArray(conf.select)) {
control = document.createElement('div')
control.className = 'select is-fullwidth'
const opts = []
for (let j = 0; j < conf.select.length; j++) {
const opt = conf.select[j]
const selected = value && (opt.value === String(value))
opts.push(`
<option value="${opt.value}"${selected ? ' selected' : ''}>
${opt.text}${opt.value === 'default' ? ' (default)' : ''}
</option>
`)
}
control.innerHTML = `
<select id="${key}">
${opts.join('\n')}
</select>
`
} else if (conf.number !== undefined) {
control = document.createElement('input')
control.id = control.name = key
control.className = 'input is-fullwidth'
control.type = 'number'
if (conf.number.min !== undefined)
control.min = conf.number.min
if (conf.number.max !== undefined)
control.max = conf.number.max
if (typeof value === 'number')
control.value = value
else if (fallback[key] !== undefined)
control.value = fallback[key]
}
let help
if (conf.disabled) {
control.disabled = conf.disabled
help = 'This option is currently disabled.'
} else if (typeof conf.help === 'string') {
help = conf.help
} else if (conf.help === true && conf.number !== undefined) {
const tmp = []
if (fallback[key] !== undefined)
tmp.push(`Default is ${fallback[key]}${conf.number.suffix || ''}.`)
if (conf.number.min !== undefined)
tmp.push(`Min is ${conf.number.min}${conf.number.suffix || ''}.`)
if (conf.number.max !== undefined)
tmp.push(`Max is ${conf.number.max}${conf.number.suffix || ''}.`)
help = tmp.join(' ')
}
field.innerHTML = `
<label class="label">${conf.label}</label>
<div class="control"></div>
${help ? `<p class="help">${help}</p>` : ''}
`
field.querySelector('div.control').appendChild(control)
form.appendChild(field)
}
page.previewImages = localStorage[lsKeys.previewImages] !== '0'
if (!page.previewImages) document.querySelector('#previewImages').value = '0'
const submit = document.createElement('div')
submit.className = 'field'
submit.innerHTML = `
<p class="control">
<button id="saveConfig" type="submit" class="button is-danger is-outlined is-fullwidth">
<span class="icon">
<i class="icon-floppy"></i>
</span>
<span>Save & reload</span>
</button>
</p>
<p class="help">
This configuration will only be used in this browser.<br>
After reloading the page, some of them will also be applied to the ShareX config that you can download by clicking on the ShareX icon below.
</p>
`
document.querySelector('#saveConfig').addEventListener('click', () => {
form.appendChild(submit)
form.querySelector('#saveConfig').addEventListener('click', () => {
if (!form.checkValidity())
return
const prefKeys = ['siBytes', 'uploadsHistoryOrder', 'previewImages', 'uploadAge']
for (let i = 0; i < prefKeys.length; i++) {
const value = form.elements[prefKeys[i]].value
if (value !== 'default' && value !== fallback[prefKeys[i]])
localStorage[lsKeys[prefKeys[i]]] = value
else
localStorage.removeItem(lsKeys[prefKeys[i]])
}
const keys = Object.keys(config)
.filter(key => config[key].display !== false && config[key].disabled !== true)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const numKeys = Object.keys(numConfig)
for (let i = 0; i < numKeys.length; i++) {
const parsed = parseInt(form.elements[numKeys[i]].value) || 0
const value = Math.min(Math.max(parsed, numConfig[numKeys[i]].min), numConfig[numKeys[i]].max)
if (value > 0 && value !== fallback[numKeys[i]])
localStorage[lsKeys[numKeys[i]]] = value
let value
if (config[key].select !== undefined) {
if (form.elements[key].value !== 'default')
value = form.elements[key].value
} else if (config[key].number !== undefined) {
const parsed = parseInt(form.elements[key].value)
if (!isNaN(parsed))
value = Math.min(Math.max(parsed, config[key].number.min), config[key].number.max)
}
if (value !== undefined && value !== fallback[key])
localStorage[lsKeys[key]] = value
else
localStorage.removeItem(lsKeys[numKeys[i]])
localStorage.removeItem(lsKeys[key])
}
swal({
@ -720,6 +847,8 @@ page.prepareUploadConfig = () => {
location.reload()
})
})
tabContent.appendChild(form)
}
page.getPrettyUploadAge = hours => {

View File

@ -1,5 +1,5 @@
{
"1": "1570419183",
"1": "1570772107",
"2": "1568894058",
"3": "1568894058",
"4": "1568894058",

View File

@ -130,92 +130,7 @@
<div class="field uploads"></div>
</div>
{%- endif %}
<div id="tab-config" class="tab-content is-hidden">
<form>
<div class="field">
<label class="label">File size display</label>
<div class="control">
<div class="select is-fullwidth">
<select id="siBytes">
<option value="default">1000 B = 1 kB = 1 Kilobyte (default)</option>
<option value="0">1024 B = 1 KiB = 1 Kibibyte</option>
</select>
</div>
</div>
<p class="help">This will be used in our homepage, dashboard, and album public pages.</p>
</div>
<div id="fileLengthDiv" class="field is-hidden">
<label class="label">File identifier length</label>
<div class="control">
<input id="fileLength" class="input is-fullwidth" type="number" min="0">
</div>
<p class="help"></p>
</div>
{%- if temporaryUploadAges and temporaryUploadAges.length %}
<div id="uploadAgeDiv" class="field is-hidden">
<label class="label">Upload age</label>
<div class="control">
<div class="select is-fullwidth">
<select id="uploadAge"></select>
</div>
</div>
<p class="help">This allows your files to automatically be deleted after a certain period of time.</p>
</div>
{%- endif %}
<div id="chunkSizeDiv" class="field">
<label class="label">Upload chunk size (MB)</label>
<div class="control">
<input id="chunkSize" class="input is-fullwidth" type="number" min="0">
</div>
<p class="help"></p>
</div>
<div id="parallelUploadsDiv" class="field">
<label class="label">Parallel uploads</label>
<div class="control">
<input id="parallelUploads" class="input is-fullwidth" type="number" name="parallelUploads" min="0">
</div>
<p class="help"></p>
</div>
<div class="field">
<label class="label">Uploads history order</label>
<div class="control">
<div class="select is-fullwidth">
<select id="uploadsHistoryOrder">
<option value="default">Older files on top (default)</option>
<option value="0">Newer files on top</option>
</select>
</div>
</div>
<p class="help">Newer files on top will use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction#Accessibility_Concerns" target="_blank" rel="noopener">a CSS technique</a>. Trying to select their texts manually from top to bottom will end up selecting the texts from bottom to top instead.</p>
</div>
<div class="field">
<label class="label">Load images for preview</label>
<div class="control">
<div class="select is-fullwidth">
<select id="previewImages">
<option value="default">Yes (default)</option>
<option value="0">No</option>
</select>
</div>
</div>
<p class="help">By default, uploaded images will be loaded as their previews.</p>
</div>
<div class="field">
<p class="control">
<button id="saveConfig" type="submit" class="button is-danger is-outlined is-fullwidth">
<span class="icon">
<i class="icon-floppy"></i>
</span>
<span>Save & reload</span>
</button>
</p>
<p class="help">
This configuration will only be used in this browser.<br>
After reloading the page, some of them will also be applied to the ShareX config that you can download by clicking on the ShareX icon below.
</p>
</div>
</form>
</div>
<div id="tab-config" class="tab-content is-hidden"></div>
</div>
<div class="column is-hidden-mobile"></div>
</div>

View File

@ -10,14 +10,14 @@
"@babel/highlight" "^7.0.0"
"@babel/core@>=7.2.2":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.3.tgz#44de824e89eaa089bb12da7337bc9bdff2ab68f9"
integrity sha512-QfQ5jTBgXLzJuo7Mo8bZK/ePywmgNRgk/UQykiKwEtZPiFIn8ZqE6jB+AnD1hbB1S2xQyL4//it5vuAUOVAMTw==
version "7.6.4"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.4.tgz#6ebd9fe00925f6c3e177bb726a188b5f578088ff"
integrity sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==
dependencies:
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.6.3"
"@babel/generator" "^7.6.4"
"@babel/helpers" "^7.6.2"
"@babel/parser" "^7.6.3"
"@babel/parser" "^7.6.4"
"@babel/template" "^7.6.0"
"@babel/traverse" "^7.6.3"
"@babel/types" "^7.6.3"
@ -27,17 +27,17 @@
lodash "^4.17.13"
resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.6.1"
source-map "^0.5.0"
"@babel/generator@^7.6.3":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.3.tgz#71d5375264f93ec7bac7d9f35a67067733f5578e"
integrity sha512-hLhYbAb3pHwxjlijC4AQ7mqZdcoujiNaW7izCT04CIowHK8psN0IN8QjDv0iyFtycF5FowUOTwDloIheI25aMw==
"@babel/generator@^7.6.3", "@babel/generator@^7.6.4":
version "7.6.4"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.4.tgz#a4f8437287bf9671b07f483b76e3bb731bc97671"
integrity sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==
dependencies:
"@babel/types" "^7.6.3"
jsesc "^2.5.1"
lodash "^4.17.13"
source-map "^0.6.1"
source-map "^0.5.0"
"@babel/helper-function-name@^7.1.0":
version "7.1.0"
@ -80,10 +80,10 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
"@babel/parser@^7.6.0", "@babel/parser@^7.6.3":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.3.tgz#9eff8b9c3eeae16a74d8d4ff30da2bd0d6f0487e"
integrity sha512-sUZdXlva1dt2Vw2RqbMkmfoImubO0D0gaCrNngV6Hi0DA4x3o4mlrq0tbfY0dZEUIccH8I6wQ4qgEtwcpOR6Qg==
"@babel/parser@^7.6.0", "@babel/parser@^7.6.3", "@babel/parser@^7.6.4":
version "7.6.4"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81"
integrity sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==
"@babel/runtime@^7.4.5":
version "7.6.3"
@ -1817,9 +1817,9 @@ ee-first@1.1.1:
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.3.247:
version "1.3.278"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.278.tgz#04c8f96382395aca225bc340be6b9dbbe2bf50eb"
integrity sha512-4cPkOCY5k4z69MHOA96VUt+Wl24AbLHQcm7W9ckabJ/iRe7oBFNMiliw75lK/w++R9bKCUxJ0mFnMRMylnAlbA==
version "1.3.280"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.280.tgz#5f8950c8329e3e11b59c705fd59b4b8d9b3de5b9"
integrity sha512-qYWNMjKLEfQAWZF2Sarvo+ahigu0EArnpCFSoUuZJS3W5wIeVfeEvsgmT2mgIrieQkeQ0+xFmykK3nx2ezekPQ==
emoji-regex@^7.0.1:
version "7.0.3"
@ -3154,9 +3154,9 @@ ignore-by-default@^1.0.1:
integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
ignore-walk@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.2.tgz#99d83a246c196ea5c93ef9315ad7b0819c35069b"
integrity sha512-EXyErtpHbn75ZTsOADsfx6J/FPo6/5cjev46PXrcTpd8z3BoRkXgYu9/JVqrI7tusjmwCZutGeRJeU0Wo1e4Cw==
version "3.0.3"
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37"
integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==
dependencies:
minimatch "^3.0.4"
@ -3823,10 +3823,10 @@ knex@^0.19.5:
uuid "^3.3.3"
v8flags "^3.1.3"
known-css-properties@^0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.15.0.tgz#5aa14a98b5a1652448aad44a1c67e867e4e7d88c"
integrity sha512-TS0RCcQfHYsA+59uIHhnsA71NBkpILbqi0W+hde4R5FtESdzur0tCJFoko/1Pbhx+8rmdUc0R1VE4ixnnD+9xw==
known-css-properties@^0.16.0:
version "0.16.0"
resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.16.0.tgz#3f0597214db11a460df77cd44bcb39e263b9da6c"
integrity sha512-0g5vDDPvNnQk7WM/aE92dTDxXJoOE0biiIcUb3qkn/F6h/ZQZPlZIbE2XSXH2vFPfphkgCxuR2vH6HHnobEOaQ==
last-run@^1.1.0:
version "1.1.1"
@ -4521,9 +4521,9 @@ npm-bundled@^1.0.1:
integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
npm-packlist@^1.1.6:
version "1.4.4"
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44"
integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==
version "1.4.6"
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4"
integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==
dependencies:
ignore-walk "^3.0.1"
npm-bundled "^1.0.1"
@ -6439,7 +6439,7 @@ source-map-url@^0.4.0:
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6:
source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
@ -6733,10 +6733,10 @@ stylelint-config-standard@^19.0.0:
dependencies:
stylelint-config-recommended "^3.0.0"
stylelint@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-11.0.0.tgz#1458d1e126d4f2fb9f41076197f852aa1fcae91d"
integrity sha512-esKkG7CUXI5yr4jgCNuwjiiV6NJ4BpodB0e47oFvUBaHgpiXXHRPOajpb0IXL7Ucpk+X3dcrlPxVHpmJ5XUDwg==
stylelint@^11.1.1:
version "11.1.1"
resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-11.1.1.tgz#6dbbb348036576ac6b033ddfedba72a877c1d6bb"
integrity sha512-Vx6TAJsxG6qksiFvxQTKriQhp1CqUWdpTDITEkAjTR+l+8Af7qNlvrUDXfpuFJgXh/ayF8xdMSKE+SstcsPmMA==
dependencies:
autoprefixer "^9.5.1"
balanced-match "^1.0.0"
@ -6753,7 +6753,7 @@ stylelint@^11.0.0:
ignore "^5.0.6"
import-lazy "^4.0.0"
imurmurhash "^0.1.4"
known-css-properties "^0.15.0"
known-css-properties "^0.16.0"
leven "^3.1.0"
lodash "^4.17.14"
log-symbols "^3.0.0"