mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2024-12-12 15:36:22 +00:00
Updated
Updated some dev dependencies. --- Gulp will now build CSS/JS files during development into dist-dev directory, to prevent IDE's Git from unnecessarily building diff's. Added dist-dev to ignore files. --- The entire config fille will now be passed to Nunjuck templates for ease of access of config values. Root domain for use in Nunjuck templates will now be parsed from config. Better page titles. Updated help message for "Uploads history order" option in homepage's config tab. Added "Load images for preview" option to homepage's config tab. Setting this to false will now prevent image uploads from loading themselves for previews. Uploads' original names in homepage's uploads history are now selectable. Min/max length for user/pass are now enforced in auth's front-end. Improved performance of album public pages. Their generated HTML pages will now be cached into memory. Unfortunately, No-JS version of their pages will be cached separately, so each album may take up to double the memory space. File names in thumbnails no longer have their full URLs as tooltips. I saw no point in that behavior. Added video icons. Homepage's uploads history will now display video icons for videos. "View thumbnail" button in Dashboard is now renamed to "Show preview". Their icons will also be changed depending on their file types. Added max length for albums' title & description. These will be enforced both in front-end and back-end. Existing albums that have surpassed the limits will not be enforced. A few other small improvements.
This commit is contained in:
parent
21f39dff9d
commit
9e9b0d4439
@ -1,4 +1,5 @@
|
||||
**/*.min.js
|
||||
dist/js/*
|
||||
dist/*
|
||||
dist-dev/*
|
||||
public/libs/*
|
||||
src/libs/*
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -51,6 +51,9 @@ package-lock.json
|
||||
# Custom pages directory
|
||||
/pages/custom
|
||||
|
||||
# Dist dev
|
||||
/dist-dev
|
||||
|
||||
# User files
|
||||
.DS_Store
|
||||
.nvmrc
|
||||
|
@ -1,3 +1,4 @@
|
||||
dist/css/*
|
||||
dist/*
|
||||
dist-dev/*
|
||||
public/libs/*
|
||||
src/libs/*
|
||||
|
@ -10,6 +10,11 @@ const logger = require('./../logger')
|
||||
const db = require('knex')(config.database)
|
||||
|
||||
const self = {
|
||||
// Don't forget to update max length of text inputs in
|
||||
// home.js & dashboard.js when changing these values
|
||||
titleMaxLength: 280,
|
||||
descMaxLength: 4000,
|
||||
|
||||
onHold: new Set()
|
||||
}
|
||||
|
||||
@ -109,7 +114,7 @@ self.create = async (req, res, next) => {
|
||||
if (!user) return
|
||||
|
||||
const name = typeof req.body.name === 'string'
|
||||
? utils.escape(req.body.name.trim())
|
||||
? utils.escape(req.body.name.trim().substring(0, self.titleMaxLength))
|
||||
: ''
|
||||
|
||||
if (!name)
|
||||
@ -140,7 +145,7 @@ self.create = async (req, res, next) => {
|
||||
download: (req.body.download === false || req.body.download === 0) ? 0 : 1,
|
||||
public: (req.body.public === false || req.body.public === 0) ? 0 : 1,
|
||||
description: typeof req.body.description === 'string'
|
||||
? utils.escape(req.body.description.trim())
|
||||
? utils.escape(req.body.description.trim().substring(0, self.descMaxLength))
|
||||
: ''
|
||||
})
|
||||
utils.invalidateStatsCache('albums')
|
||||
@ -159,7 +164,7 @@ self.delete = async (req, res, next) => {
|
||||
|
||||
const id = req.body.id
|
||||
const purge = req.body.purge
|
||||
if (id === undefined || id === '')
|
||||
if (!Number.isFinite(id))
|
||||
return res.json({ success: false, description: 'No album specified.' })
|
||||
|
||||
try {
|
||||
@ -184,7 +189,7 @@ self.delete = async (req, res, next) => {
|
||||
userid: user.id
|
||||
})
|
||||
.update('enabled', 0)
|
||||
utils.invalidateStatsCache('albums')
|
||||
utils.invalidateAlbumsCache([id])
|
||||
|
||||
const identifier = await db.table('albums')
|
||||
.select('identifier')
|
||||
@ -215,7 +220,7 @@ self.edit = async (req, res, next) => {
|
||||
return res.json({ success: false, description: 'No album specified.' })
|
||||
|
||||
const name = typeof req.body.name === 'string'
|
||||
? utils.escape(req.body.name.trim())
|
||||
? utils.escape(req.body.name.trim().substring(0, self.titleMaxLength))
|
||||
: ''
|
||||
|
||||
if (!name)
|
||||
@ -245,13 +250,14 @@ self.edit = async (req, res, next) => {
|
||||
})
|
||||
.update({
|
||||
name,
|
||||
editedAt: Math.floor(Date.now() / 1000),
|
||||
download: Boolean(req.body.download),
|
||||
public: Boolean(req.body.public),
|
||||
description: typeof req.body.description === 'string'
|
||||
? utils.escape(req.body.description.trim())
|
||||
? utils.escape(req.body.description.trim().substring(0, self.descMaxLength))
|
||||
: ''
|
||||
})
|
||||
utils.invalidateStatsCache('albums')
|
||||
utils.invalidateAlbumsCache([id])
|
||||
|
||||
if (!req.body.requestLink)
|
||||
return res.json({ success: true, name })
|
||||
|
@ -1,4 +1,3 @@
|
||||
const { promisify } = require('util')
|
||||
const bcrypt = require('bcrypt')
|
||||
const randomstring = require('randomstring')
|
||||
const perms = require('./permissionController')
|
||||
@ -8,11 +7,27 @@ const config = require('./../config')
|
||||
const logger = require('./../logger')
|
||||
const db = require('knex')(config.database)
|
||||
|
||||
// Don't forget to update min/max length of text inputs in auth.njk
|
||||
// when changing these values.
|
||||
const self = {
|
||||
compare: promisify(bcrypt.compare),
|
||||
hash: promisify(bcrypt.hash)
|
||||
user: {
|
||||
min: 4,
|
||||
max: 32
|
||||
},
|
||||
pass: {
|
||||
min: 6,
|
||||
// Should not be more than 72 characters
|
||||
// https://github.com/kelektiv/node.bcrypt.js#security-issues-and-concerns
|
||||
max: 64,
|
||||
// Length of randomized password
|
||||
// when resetting passwordthrough Dashboard's Manage Users.
|
||||
rand: 16
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/kelektiv/node.bcrypt.js#a-note-on-rounds
|
||||
const saltRounds = 10
|
||||
|
||||
self.verify = async (req, res, next) => {
|
||||
const username = typeof req.body.username === 'string'
|
||||
? req.body.username.trim()
|
||||
@ -37,7 +52,7 @@ self.verify = async (req, res, next) => {
|
||||
if (user.enabled === false || user.enabled === 0)
|
||||
return res.json({ success: false, description: 'This account has been disabled.' })
|
||||
|
||||
const result = await self.compare(password, user.password)
|
||||
const result = await bcrypt.compare(password, user.password)
|
||||
if (result === false)
|
||||
return res.json({ success: false, description: 'Wrong password.' })
|
||||
else
|
||||
@ -55,14 +70,14 @@ self.register = async (req, res, next) => {
|
||||
const username = typeof req.body.username === 'string'
|
||||
? req.body.username.trim()
|
||||
: ''
|
||||
if (username.length < 4 || username.length > 32)
|
||||
return res.json({ success: false, description: 'Username must have 4-32 characters.' })
|
||||
if (username.length < self.user.min || username.length > self.user.max)
|
||||
return res.json({ success: false, description: `Username must have ${self.user.min}-${self.user.max} characters.` })
|
||||
|
||||
const password = typeof req.body.password === 'string'
|
||||
? req.body.password.trim()
|
||||
: ''
|
||||
if (password.length < 6 || password.length > 64)
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters.' })
|
||||
if (password.length < self.pass.min || password.length > self.pass.max)
|
||||
return res.json({ success: false, description: `Password must have ${self.pass.min}-${self.pass.max} characters.` })
|
||||
|
||||
try {
|
||||
const user = await db.table('users')
|
||||
@ -72,7 +87,7 @@ self.register = async (req, res, next) => {
|
||||
if (user)
|
||||
return res.json({ success: false, description: 'Username already exists.' })
|
||||
|
||||
const hash = await self.hash(password, 10)
|
||||
const hash = await bcrypt.hash(password, saltRounds)
|
||||
|
||||
const token = await tokens.generateUniqueToken()
|
||||
if (!token)
|
||||
@ -103,11 +118,11 @@ self.changePassword = async (req, res, next) => {
|
||||
const password = typeof req.body.password === 'string'
|
||||
? req.body.password.trim()
|
||||
: ''
|
||||
if (password.length < 6 || password.length > 64)
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters.' })
|
||||
if (password.length < self.pass.min || password.length > self.pass.max)
|
||||
return res.json({ success: false, description: `Password must have ${self.pass.min}-${self.pass.max} characters.` })
|
||||
|
||||
try {
|
||||
const hash = await self.hash(password, 10)
|
||||
const hash = await bcrypt.hash(password, saltRounds)
|
||||
|
||||
await db.table('users')
|
||||
.where('id', user.id)
|
||||
@ -144,8 +159,11 @@ self.editUser = async (req, res, next) => {
|
||||
|
||||
if (req.body.username !== undefined) {
|
||||
update.username = String(req.body.username).trim()
|
||||
if (update.username.length < 4 || update.username.length > 32)
|
||||
return res.json({ success: false, description: 'Username must have 4-32 characters.' })
|
||||
if (update.username.length < self.user.min || update.username.length > self.user.max)
|
||||
return res.json({
|
||||
success: false,
|
||||
description: `Username must have ${self.user.min}-${self.user.max} characters.`
|
||||
})
|
||||
}
|
||||
|
||||
if (req.body.enabled !== undefined)
|
||||
@ -159,8 +177,8 @@ self.editUser = async (req, res, next) => {
|
||||
|
||||
let password
|
||||
if (req.body.resetPassword) {
|
||||
password = randomstring.generate(16)
|
||||
update.password = await self.hash(password, 10)
|
||||
password = randomstring.generate(self.pass.rand)
|
||||
update.password = await bcrypt.hash(password, saltRounds)
|
||||
}
|
||||
|
||||
await db.table('users')
|
||||
|
@ -33,7 +33,9 @@ self.thumbPlaceholder = path.resolve(config.uploads.generateThumbs.placeholder |
|
||||
self.logs = path.resolve(config.logsFolder)
|
||||
|
||||
self.customPages = path.resolve('pages/custom')
|
||||
self.dist = path.resolve('dist')
|
||||
self.dist = process.env.NODE_ENV === 'development'
|
||||
? path.resolve('dist-dev')
|
||||
: path.resolve('dist')
|
||||
self.public = path.resolve('public')
|
||||
|
||||
self.errorRoot = path.resolve(config.errorPages.rootDir)
|
||||
|
@ -51,8 +51,18 @@ const initChunks = async uuid => {
|
||||
}
|
||||
|
||||
const executeMulter = multer({
|
||||
// Guide: https://github.com/expressjs/multer#limits
|
||||
limits: {
|
||||
fileSize: maxSizeBytes
|
||||
fileSize: maxSizeBytes,
|
||||
// Maximum number of non-file fields.
|
||||
// Dropzone.js will add 6 extra fields for chunked uploads.
|
||||
// We don't use them for anything else.
|
||||
fields: 6,
|
||||
// Maximum number of file fields.
|
||||
// Chunked uploads still need to provide only 1 file field.
|
||||
// Otherwise, only one of the files will end up being properly stored,
|
||||
// and that will also be as a chunk.
|
||||
files: 20
|
||||
},
|
||||
fileFilter (req, file, cb) {
|
||||
file.extname = utils.extname(file.originalname)
|
||||
@ -101,7 +111,8 @@ const executeMulter = multer({
|
||||
return cb(null, name)
|
||||
}
|
||||
})
|
||||
}).array('files[]')
|
||||
}).array('files[]', {
|
||||
})
|
||||
|
||||
self.isExtensionFiltered = extname => {
|
||||
// If empty extension needs to be filtered
|
||||
@ -621,10 +632,12 @@ self.storeFilesToDb = async (req, res, user, infoMap) => {
|
||||
utils.invalidateStatsCache('uploads')
|
||||
|
||||
// Update albums' timestamp
|
||||
if (authorizedIds.length)
|
||||
if (authorizedIds.length) {
|
||||
await db.table('albums')
|
||||
.whereIn('id', authorizedIds)
|
||||
.update('editedAt', Math.floor(Date.now() / 1000))
|
||||
utils.invalidateAlbumsCache(authorizedIds)
|
||||
}
|
||||
}
|
||||
|
||||
return files.concat(exists)
|
||||
|
@ -25,7 +25,9 @@ const self = {
|
||||
imageExts: ['.webp', '.jpg', '.jpeg', '.gif', '.png', '.tiff', '.tif', '.svg'],
|
||||
videoExts: ['.webm', '.mp4', '.wmv', '.avi', '.mov', '.mkv'],
|
||||
|
||||
ffprobe: promisify(ffmpeg.ffprobe)
|
||||
ffprobe: promisify(ffmpeg.ffprobe),
|
||||
|
||||
albumsCache: {}
|
||||
}
|
||||
|
||||
const statsCache = {
|
||||
@ -57,7 +59,7 @@ const statsCache = {
|
||||
}
|
||||
}
|
||||
|
||||
const cloudflareAuth = config.cloudflare.apiKey && config.cloudflare.email && config.cloudflare.zoneId
|
||||
const cloudflareAuth = config.cloudflare && config.cloudflare.apiKey && config.cloudflare.email && config.cloudflare.zoneId
|
||||
|
||||
self.mayGenerateThumb = extname => {
|
||||
return (config.uploads.generateThumbs.image && self.imageExts.includes(extname)) ||
|
||||
@ -504,6 +506,14 @@ self.bulkDeleteExpired = async (dryrun) => {
|
||||
return result
|
||||
}
|
||||
|
||||
self.invalidateAlbumsCache = albumids => {
|
||||
for (const albumid of albumids) {
|
||||
delete self.albumsCache[albumid]
|
||||
delete self.albumsCache[`${albumid}-nojs`]
|
||||
}
|
||||
self.invalidateStatsCache('albums')
|
||||
}
|
||||
|
||||
self.invalidateStatsCache = type => {
|
||||
if (!['albums', 'users', 'uploads'].includes(type)) return
|
||||
statsCache[type].invalidatedAt = Date.now()
|
||||
@ -660,6 +670,8 @@ self.stats = async (req, res, next) => {
|
||||
stats.uploads = statsCache.uploads.cache
|
||||
} else {
|
||||
statsCache.uploads.generating = true
|
||||
statsCache.uploads.generatedAt = Date.now()
|
||||
|
||||
stats.uploads = {
|
||||
_types: {
|
||||
number: ['total', 'images', 'videos', 'others']
|
||||
@ -700,7 +712,6 @@ self.stats = async (req, res, next) => {
|
||||
|
||||
// Update cache
|
||||
statsCache.uploads.cache = stats.uploads
|
||||
statsCache.uploads.generatedAt = Date.now()
|
||||
statsCache.uploads.generating = false
|
||||
}
|
||||
|
||||
@ -711,6 +722,8 @@ self.stats = async (req, res, next) => {
|
||||
stats.users = statsCache.users.cache
|
||||
} else {
|
||||
statsCache.users.generating = true
|
||||
statsCache.users.generatedAt = Date.now()
|
||||
|
||||
stats.users = {
|
||||
_types: {
|
||||
number: ['total', 'disabled']
|
||||
@ -742,7 +755,6 @@ self.stats = async (req, res, next) => {
|
||||
|
||||
// Update cache
|
||||
statsCache.users.cache = stats.users
|
||||
statsCache.users.generatedAt = Date.now()
|
||||
statsCache.users.generating = false
|
||||
}
|
||||
|
||||
@ -753,6 +765,8 @@ self.stats = async (req, res, next) => {
|
||||
stats.albums = statsCache.albums.cache
|
||||
} else {
|
||||
statsCache.albums.generating = true
|
||||
statsCache.albums.generatedAt = Date.now()
|
||||
|
||||
stats.albums = {
|
||||
_types: {
|
||||
number: ['total', 'active', 'downloadable', 'public', 'generatedZip']
|
||||
@ -789,7 +803,6 @@ self.stats = async (req, res, next) => {
|
||||
|
||||
// Update cache
|
||||
statsCache.albums.cache = stats.albums
|
||||
statsCache.albums.generatedAt = Date.now()
|
||||
statsCache.albums.generating = false
|
||||
}
|
||||
|
||||
|
2
dist/css/dashboard.css
vendored
2
dist/css/dashboard.css
vendored
@ -1,2 +1,2 @@
|
||||
body{-webkit-animation:none;animation:none}#dashboard{-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}.section{background:none}.menu-list a{color:#3794d2}.menu-list a:hover{color:#60a8dc;background-color:#4d4d4d}.menu-list a.is-active{color:#eff0f1;background-color:#3794d2}.menu-list a[disabled]{color:#7a7a7a;cursor:not-allowed}.menu-list a[disabled]:hover{background:none}ul#albumsContainer{border-left:0;padding-left:0}ul#albumsContainer li{border-left:1px solid #898b8d;padding-left:.75em}#page.fade-in,ul#albumsContainer li{-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}.pagination{margin-bottom:1.25rem}.pagination a:not([disabled]){color:#eff0f1;border-color:#4d4d4d;background-color:#31363b}a.pagination-link:not(.is-current):hover,a.pagination-next:not([disabled]):hover,a.pagination-previous:not([disabled]):hover{color:#eff0f1;border-color:#60a8dc;background-color:#31363b}a.pagination-link.is-current{background-color:#3794d2;border-color:#3794d2}a.pagination-link.is-current:hover{border-color:#60a8dc}li[data-action=page-ellipsis]{cursor:pointer}.label{color:#bdc3c7}.menu-list li ul{border-left-color:#898b8d}.image-container .checkbox{position:absolute;top:12px;left:12px}.no-touch .image-container .checkbox{opacity:.5}.no-touch .image-container .controls,.no-touch .image-container .details{opacity:0}.no-touch .image-container:hover .checkbox,.no-touch .image-container:hover .controls,.no-touch .image-container:hover .details{opacity:1}#page{min-width:0}.table{color:#bdc3c7;background-color:#31363b;font-size:.75rem}.table.is-striped tbody tr:nth-child(2n),.table tr:hover{background:none}.table.is-striped tbody tr:hover,.table.is-striped tbody tr:nth-child(2n):hover,.tag{background-color:#4d4d4d}.table td,.table th{border:0;white-space:nowrap}.table th{color:#eff0f1;height:2.25em}.table thead td,.table thead th{color:#eff0f1;background-color:#ff3860}.table .cell-indent{padding-left:2.25em}.is-linethrough{text-decoration:line-through}#menu.is-loading li a{cursor:progress}#statistics tr :nth-child(2){min-width:50%}.expirydate{color:#bdc3c7}
|
||||
body{-webkit-animation:none;animation:none}#dashboard{-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}.section{background:none}.menu-list a{color:#3794d2}.menu-list a:hover{color:#60a8dc;background-color:#4d4d4d}.menu-list a.is-active{color:#eff0f1;background-color:#3794d2}.menu-list a[disabled]{color:#7a7a7a;cursor:not-allowed}.menu-list a[disabled]:hover{background:none}.menu-list a.is-loading:after{-webkit-animation:spinAround .5s linear infinite;animation:spinAround .5s linear infinite;border-radius:290486px;border-color:transparent transparent #dbdbdb #dbdbdb;border-style:solid;border-width:2px;content:"";display:block;height:1em;width:1em;right:.5em;top:calc(50% - .5em);position:absolute!important}ul#albumsContainer{border-left:0;padding-left:0}ul#albumsContainer li{border-left:1px solid #898b8d;padding-left:.75em}#page.fade-in,ul#albumsContainer li{-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}.pagination{margin-bottom:1.25rem}.pagination a:not([disabled]){color:#eff0f1;border-color:#4d4d4d;background-color:#31363b}a.pagination-link:not(.is-current):hover,a.pagination-next:not([disabled]):hover,a.pagination-previous:not([disabled]):hover{color:#eff0f1;border-color:#60a8dc;background-color:#31363b}a.pagination-link.is-current{background-color:#3794d2;border-color:#3794d2}a.pagination-link.is-current:hover{border-color:#60a8dc}li[data-action=page-ellipsis]{cursor:pointer}.label{color:#bdc3c7}.menu-list li ul{border-left-color:#898b8d}.image-container .checkbox{position:absolute;top:12px;left:12px}.no-touch .image-container .checkbox{opacity:.5}.no-touch .image-container .controls,.no-touch .image-container .details{opacity:0}.no-touch .image-container:hover .checkbox,.no-touch .image-container:hover .controls,.no-touch .image-container:hover .details{opacity:1}#page{min-width:0}.table{color:#bdc3c7;background-color:#31363b;font-size:.75rem}.table.is-striped tbody tr:nth-child(2n),.table tr:hover{background:none}.table.is-striped tbody tr:hover,.table.is-striped tbody tr:nth-child(2n):hover,.tag{background-color:#4d4d4d}.table td,.table th{border:0;white-space:nowrap}.table th{color:#eff0f1;height:2.25em}.table thead td,.table thead th{color:#eff0f1;background-color:#ff3860}.table .cell-indent{padding-left:2.25em}.is-linethrough{text-decoration:line-through}#menu.is-loading .menu-list a{cursor:progress}#statistics tr :nth-child(2){min-width:50%}.expirydate{color:#bdc3c7}
|
||||
/*# sourceMappingURL=dashboard.css.map */
|
||||
|
2
dist/css/dashboard.css.map
vendored
2
dist/css/dashboard.css.map
vendored
@ -1 +1 @@
|
||||
{"version":3,"sources":["css/dashboard.css"],"names":[],"mappings":"AAAA,KACE,sBAAc,CAAd,cACF,CAEA,WACE,mCAA4B,CAA5B,2BACF,CAEA,SACE,eACF,CAEA,aACE,aACF,CAEA,mBACE,aAAc,CACd,wBACF,CAEA,uBACE,aAAc,CACd,wBACF,CAEA,uBACE,aAAc,CACd,kBACF,CAEA,6BACE,eACF,CAEA,mBACE,aAAc,CACd,cACF,CAEA,sBACE,6BAA8B,CAC9B,kBAEF,CAEA,oCAHE,mCAA4B,CAA5B,2BAKF,CAEA,YACE,qBACF,CAEA,8BACE,aAAc,CACd,oBAAqB,CACrB,wBACF,CAEA,6HAGE,aAAc,CACd,oBAAqB,CACrB,wBACF,CAEA,6BACE,wBAAyB,CACzB,oBACF,CAEA,mCACE,oBACF,CAEA,8BACE,cACF,CAEA,OACE,aACF,CAEA,iBACE,yBACF,CAEA,2BACE,iBAAkB,CAClB,QAAS,CACT,SACF,CAEA,qCACE,UACF,CAEA,yEAEE,SACF,CAEA,gIAGE,SACF,CAEA,MAEE,WACF,CAEA,OACE,aAAc,CACd,wBAAyB,CACzB,gBACF,CAEA,yDAEE,eACF,CAEA,qFAGE,wBACF,CAEA,oBAEE,QAAS,CACT,kBACF,CAEA,UACE,aAAc,CACd,aACF,CAEA,gCAEE,aAAc,CACd,wBACF,CAEA,oBACE,mBACF,CAEA,gBACE,4BACF,CAEA,sBACE,eACF,CAEA,6BACE,aACF,CAEA,YACE,aACF","file":"dashboard.css","sourcesContent":["body {\n animation: none\n}\n\n#dashboard {\n animation: fadeInOpacity 0.5s\n}\n\n.section {\n background: none\n}\n\n.menu-list a {\n color: #3794d2\n}\n\n.menu-list a:hover {\n color: #60a8dc;\n background-color: #4d4d4d\n}\n\n.menu-list a.is-active {\n color: #eff0f1;\n background-color: #3794d2\n}\n\n.menu-list a[disabled] {\n color: #7a7a7a;\n cursor: not-allowed\n}\n\n.menu-list a[disabled]:hover {\n background: none\n}\n\nul#albumsContainer {\n border-left: 0;\n padding-left: 0\n}\n\nul#albumsContainer li {\n border-left: 1px solid #898b8d;\n padding-left: 0.75em;\n animation: fadeInOpacity 0.5s\n}\n\n#page.fade-in {\n animation: fadeInOpacity 0.5s\n}\n\n.pagination {\n margin-bottom: 1.25rem\n}\n\n.pagination a:not([disabled]) {\n color: #eff0f1;\n border-color: #4d4d4d;\n background-color: #31363b\n}\n\na.pagination-link:not(.is-current):hover,\na.pagination-next:not([disabled]):hover,\na.pagination-previous:not([disabled]):hover {\n color: #eff0f1;\n border-color: #60a8dc;\n background-color: #31363b\n}\n\na.pagination-link.is-current {\n background-color: #3794d2;\n border-color: #3794d2\n}\n\na.pagination-link.is-current:hover {\n border-color: #60a8dc\n}\n\nli[data-action=\"page-ellipsis\"] {\n cursor: pointer\n}\n\n.label {\n color: #bdc3c7\n}\n\n.menu-list li ul {\n border-left-color: #898b8d\n}\n\n.image-container .checkbox {\n position: absolute;\n top: 12px;\n left: 12px\n}\n\n.no-touch .image-container .checkbox {\n opacity: 0.5\n}\n\n.no-touch .image-container .controls,\n.no-touch .image-container .details {\n opacity: 0\n}\n\n.no-touch .image-container:hover .checkbox,\n.no-touch .image-container:hover .controls,\n.no-touch .image-container:hover .details {\n opacity: 1\n}\n\n#page {\n /* fix overflow issue with flex */\n min-width: 0\n}\n\n.table {\n color: #bdc3c7;\n background-color: #31363b;\n font-size: 0.75rem\n}\n\n.table tr:hover,\n.table.is-striped tbody tr:nth-child(2n) {\n background: none\n}\n\n.table.is-striped tbody tr:hover,\n.table.is-striped tbody tr:nth-child(2n):hover,\n.tag {\n background-color: #4d4d4d\n}\n\n.table td,\n.table th {\n border: 0;\n white-space: nowrap\n}\n\n.table th {\n color: #eff0f1;\n height: 2.25em\n}\n\n.table thead td,\n.table thead th {\n color: #eff0f1;\n background-color: #ff3860\n}\n\n.table .cell-indent {\n padding-left: 2.25em\n}\n\n.is-linethrough {\n text-decoration: line-through\n}\n\n#menu.is-loading li a {\n cursor: progress\n}\n\n#statistics tr *:nth-child(2) {\n min-width: 50%\n}\n\n.expirydate {\n color: #bdc3c7\n}\n"]}
|
||||
{"version":3,"sources":["css/dashboard.css"],"names":[],"mappings":"AAAA,KACE,sBAAc,CAAd,cACF,CAEA,WACE,mCAA4B,CAA5B,2BACF,CAEA,SACE,eACF,CAEA,aACE,aACF,CAEA,mBACE,aAAc,CACd,wBACF,CAEA,uBACE,aAAc,CACd,wBACF,CAEA,uBACE,aAAc,CACd,kBACF,CAEA,6BACE,eACF,CAEA,8BACE,gDAA0C,CAA1C,wCAA0C,CAE1C,sBAAuB,CAEvB,oDAA6B,CAA7B,kBAA6B,CAA7B,gBAA6B,CAC7B,UAAW,CACX,aAAc,CACd,UAAW,CACX,SAAU,CACV,UAA2B,CAC3B,oBAA0B,CAC1B,2BACF,CAEA,mBACE,aAAc,CACd,cACF,CAEA,sBACE,6BAA8B,CAC9B,kBAEF,CAEA,oCAHE,mCAA4B,CAA5B,2BAKF,CAEA,YACE,qBACF,CAEA,8BACE,aAAc,CACd,oBAAqB,CACrB,wBACF,CAEA,6HAGE,aAAc,CACd,oBAAqB,CACrB,wBACF,CAEA,6BACE,wBAAyB,CACzB,oBACF,CAEA,mCACE,oBACF,CAEA,8BACE,cACF,CAEA,OACE,aACF,CAEA,iBACE,yBACF,CAEA,2BACE,iBAAkB,CAClB,QAAS,CACT,SACF,CAEA,qCACE,UACF,CAEA,yEAEE,SACF,CAEA,gIAGE,SACF,CAEA,MAEE,WACF,CAEA,OACE,aAAc,CACd,wBAAyB,CACzB,gBACF,CAEA,yDAEE,eACF,CAEA,qFAGE,wBACF,CAEA,oBAEE,QAAS,CACT,kBACF,CAEA,UACE,aAAc,CACd,aACF,CAEA,gCAEE,aAAc,CACd,wBACF,CAEA,oBACE,mBACF,CAEA,gBACE,4BACF,CAEA,8BACE,eACF,CAEA,6BACE,aACF,CAEA,YACE,aACF","file":"dashboard.css","sourcesContent":["body {\n animation: none\n}\n\n#dashboard {\n animation: fadeInOpacity 0.5s\n}\n\n.section {\n background: none\n}\n\n.menu-list a {\n color: #3794d2\n}\n\n.menu-list a:hover {\n color: #60a8dc;\n background-color: #4d4d4d\n}\n\n.menu-list a.is-active {\n color: #eff0f1;\n background-color: #3794d2\n}\n\n.menu-list a[disabled] {\n color: #7a7a7a;\n cursor: not-allowed\n}\n\n.menu-list a[disabled]:hover {\n background: none\n}\n\n.menu-list a.is-loading::after {\n animation: spinAround 0.5s infinite linear;\n border: 2px solid #dbdbdb;\n border-radius: 290486px;\n border-right-color: transparent;\n border-top-color: transparent;\n content: \"\";\n display: block;\n height: 1em;\n width: 1em;\n right: calc(0% + (1em / 2));\n top: calc(50% - (1em / 2));\n position: absolute !important\n}\n\nul#albumsContainer {\n border-left: 0;\n padding-left: 0\n}\n\nul#albumsContainer li {\n border-left: 1px solid #898b8d;\n padding-left: 0.75em;\n animation: fadeInOpacity 0.5s\n}\n\n#page.fade-in {\n animation: fadeInOpacity 0.5s\n}\n\n.pagination {\n margin-bottom: 1.25rem\n}\n\n.pagination a:not([disabled]) {\n color: #eff0f1;\n border-color: #4d4d4d;\n background-color: #31363b\n}\n\na.pagination-link:not(.is-current):hover,\na.pagination-next:not([disabled]):hover,\na.pagination-previous:not([disabled]):hover {\n color: #eff0f1;\n border-color: #60a8dc;\n background-color: #31363b\n}\n\na.pagination-link.is-current {\n background-color: #3794d2;\n border-color: #3794d2\n}\n\na.pagination-link.is-current:hover {\n border-color: #60a8dc\n}\n\nli[data-action=\"page-ellipsis\"] {\n cursor: pointer\n}\n\n.label {\n color: #bdc3c7\n}\n\n.menu-list li ul {\n border-left-color: #898b8d\n}\n\n.image-container .checkbox {\n position: absolute;\n top: 12px;\n left: 12px\n}\n\n.no-touch .image-container .checkbox {\n opacity: 0.5\n}\n\n.no-touch .image-container .controls,\n.no-touch .image-container .details {\n opacity: 0\n}\n\n.no-touch .image-container:hover .checkbox,\n.no-touch .image-container:hover .controls,\n.no-touch .image-container:hover .details {\n opacity: 1\n}\n\n#page {\n /* fix overflow issue with flex */\n min-width: 0\n}\n\n.table {\n color: #bdc3c7;\n background-color: #31363b;\n font-size: 0.75rem\n}\n\n.table tr:hover,\n.table.is-striped tbody tr:nth-child(2n) {\n background: none\n}\n\n.table.is-striped tbody tr:hover,\n.table.is-striped tbody tr:nth-child(2n):hover,\n.tag {\n background-color: #4d4d4d\n}\n\n.table td,\n.table th {\n border: 0;\n white-space: nowrap\n}\n\n.table th {\n color: #eff0f1;\n height: 2.25em\n}\n\n.table thead td,\n.table thead th {\n color: #eff0f1;\n background-color: #ff3860\n}\n\n.table .cell-indent {\n padding-left: 2.25em\n}\n\n.is-linethrough {\n text-decoration: line-through\n}\n\n#menu.is-loading .menu-list a {\n cursor: progress\n}\n\n#statistics tr *:nth-child(2) {\n min-width: 50%\n}\n\n.expirydate {\n color: #bdc3c7\n}\n"]}
|
2
dist/css/style.css
vendored
2
dist/css/style.css
vendored
@ -1,2 +1,2 @@
|
||||
html{background-color:#232629;overflow-y:auto}body{color:#eff0f1;-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}@-webkit-keyframes fadeInOpacity{0%{opacity:0}to{opacity:1}}@keyframes fadeInOpacity{0%{opacity:0}to{opacity:1}}a{color:#3794d2}a:hover{color:#60a8dc}hr{background-color:#898b8d}.message-body code,code{background-color:#222528;border-radius:5px}.title{color:#eff0f1}.subtitle,.subtitle strong{color:#bdc3c7}.input::-moz-placeholder,.textarea::-moz-placeholder{color:#7f8c8d}.input::-webkit-input-placeholder,.textarea::-webkit-input-placeholder{color:#7f8c8d}.input:-moz-placeholder,.textarea:-moz-placeholder{color:#7f8c8d}.input:-ms-input-placeholder,.textarea:-ms-input-placeholder{color:#7f8c8d}.input.is-active,.input.is-focused,.input:active,.input:focus,.textarea.is-active,.textarea.is-focused,.textarea:active,.textarea:focus{border-color:#3794d2}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#4d4d4d}.table td,.table th{vertical-align:middle}.help{color:#7f8c8d}.button.is-info.is-hovered [class*=" icon-"]:before,.button.is-info.is-hovered [class^=icon-]:before,.button.is-info:hover [class*=" icon-"]:before,.button.is-info:hover [class^=icon-]:before{fill:#fff}.checkbox:hover,.radio:hover{color:#7f8c8d}.message{background-color:#31363b}.message-body{color:#eff0f1;border:0;box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2)}.menu-list a.is-loading:after{-webkit-animation:spinAround .5s linear infinite;animation:spinAround .5s linear infinite;border-radius:290486px;border-color:transparent transparent #dbdbdb #dbdbdb;border-style:solid;border-width:2px;content:"";display:block;height:1em;width:1em;right:.5em;top:calc(50% - .5em);position:absolute!important}.hero.is-fullheight>.hero-body{min-height:100vh;height:100%}.hero.is-fullheight>.hero-body>.container{width:100%}
|
||||
html{background-color:#232629;overflow-y:auto}body{color:#eff0f1;-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}@-webkit-keyframes fadeInOpacity{0%{opacity:0}to{opacity:1}}@keyframes fadeInOpacity{0%{opacity:0}to{opacity:1}}a{color:#3794d2}a:hover{color:#60a8dc}hr{background-color:#898b8d}.message-body code,code{background-color:#222528;border-radius:5px}.title{color:#eff0f1}.subtitle,.subtitle strong{color:#bdc3c7}.input::-moz-placeholder,.textarea::-moz-placeholder{color:#7f8c8d}.input::-webkit-input-placeholder,.textarea::-webkit-input-placeholder{color:#7f8c8d}.input:-moz-placeholder,.textarea:-moz-placeholder{color:#7f8c8d}.input:-ms-input-placeholder,.textarea:-ms-input-placeholder{color:#7f8c8d}.input.is-active,.input.is-focused,.input:active,.input:focus,.textarea.is-active,.textarea.is-focused,.textarea:active,.textarea:focus{border-color:#3794d2}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#4d4d4d}.table td,.table th{vertical-align:middle}.help{color:#7f8c8d}.button.is-info.is-hovered [class*=" icon-"]:before,.button.is-info.is-hovered [class^=icon-]:before,.button.is-info:hover [class*=" icon-"]:before,.button.is-info:hover [class^=icon-]:before{fill:#fff}.checkbox:hover,.radio:hover{color:#7f8c8d}.message{background-color:#31363b}.message-body{color:#eff0f1;border:0;box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2)}.hero.is-fullheight>.hero-body{min-height:100vh;height:100%}.hero.is-fullheight>.hero-body>.container{width:100%}
|
||||
/*# sourceMappingURL=style.css.map */
|
||||
|
2
dist/css/style.css.map
vendored
2
dist/css/style.css.map
vendored
@ -1 +1 @@
|
||||
{"version":3,"sources":["css/style.css"],"names":[],"mappings":"AAAA,KACE,wBAAyB,CACzB,eACF,CAEA,KACE,aAAc,CACd,mCAA4B,CAA5B,2BACF,CAEA,iCACE,GACE,SACF,CAEA,GACE,SACF,CACF,CAEA,yBACE,GACE,SACF,CAEA,GACE,SACF,CACF,CAEA,EACE,aACF,CAEA,QACE,aACF,CAEA,GACE,wBACF,CAEA,wBAEE,wBAAyB,CACzB,iBACF,CAEA,OACE,aACF,CAMA,2BACE,aACF,CAEA,qDAEE,aACF,CAEA,uEAEE,aACF,CAEA,mDAEE,aACF,CAEA,6DAEE,aACF,CAEA,wIAQE,oBACF,CAEA,qDACE,wBACF,CAEA,oBAEE,qBACF,CAEA,MACE,aACF,CAEA,gMAIE,SACF,CAEA,6BAEE,aACF,CAEA,SACE,wBACF,CAEA,cACE,aAAc,CACd,QAAS,CACT,kGACF,CAEA,8BACE,gDAA0C,CAA1C,wCAA0C,CAE1C,sBAAuB,CAEvB,oDAA6B,CAA7B,kBAA6B,CAA7B,gBAA6B,CAC7B,UAAW,CACX,aAAc,CACd,UAAW,CACX,SAAU,CACV,UAA2B,CAC3B,oBAA0B,CAC1B,2BACF,CAGA,+BACE,gBAAiB,CACjB,WACF,CAGA,0CACE,UACF","file":"style.css","sourcesContent":["html {\n background-color: #232629;\n overflow-y: auto\n}\n\nbody {\n color: #eff0f1;\n animation: fadeInOpacity 0.5s\n}\n\n@-webkit-keyframes fadeInOpacity {\n 0% {\n opacity: 0\n }\n\n 100% {\n opacity: 1\n }\n}\n\n@keyframes fadeInOpacity {\n 0% {\n opacity: 0\n }\n\n 100% {\n opacity: 1\n }\n}\n\na {\n color: #3794d2\n}\n\na:hover {\n color: #60a8dc\n}\n\nhr {\n background-color: #898b8d\n}\n\ncode,\n.message-body code {\n background-color: #222528;\n border-radius: 5px\n}\n\n.title {\n color: #eff0f1\n}\n\n.subtitle {\n color: #bdc3c7\n}\n\n.subtitle strong {\n color: #bdc3c7\n}\n\n.input::-moz-placeholder,\n.textarea::-moz-placeholder {\n color: #7f8c8d\n}\n\n.input::-webkit-input-placeholder,\n.textarea::-webkit-input-placeholder {\n color: #7f8c8d\n}\n\n.input:-moz-placeholder,\n.textarea:-moz-placeholder {\n color: #7f8c8d\n}\n\n.input:-ms-input-placeholder,\n.textarea:-ms-input-placeholder {\n color: #7f8c8d\n}\n\n.input.is-active,\n.input.is-focused,\n.input:active,\n.input:focus,\n.textarea.is-active,\n.textarea.is-focused,\n.textarea:active,\n.textarea:focus {\n border-color: #3794d2\n}\n\n.table.is-hoverable tbody tr:not(.is-selected):hover {\n background-color: #4d4d4d\n}\n\n.table td,\n.table th {\n vertical-align: middle\n}\n\n.help {\n color: #7f8c8d\n}\n\n.button.is-info.is-hovered [class^=\"icon-\"]::before,\n.button.is-info.is-hovered [class*=\" icon-\"]::before,\n.button.is-info:hover [class^=\"icon-\"]::before,\n.button.is-info:hover [class*=\" icon-\"]::before {\n fill: #fff\n}\n\n.checkbox:hover,\n.radio:hover {\n color: #7f8c8d\n}\n\n.message {\n background-color: #31363b\n}\n\n.message-body {\n color: #eff0f1;\n border: 0;\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2)\n}\n\n.menu-list a.is-loading::after {\n animation: spinAround 0.5s infinite linear;\n border: 2px solid #dbdbdb;\n border-radius: 290486px;\n border-right-color: transparent;\n border-top-color: transparent;\n content: \"\";\n display: block;\n height: 1em;\n width: 1em;\n right: calc(0% + (1em / 2));\n top: calc(50% - (1em / 2));\n position: absolute !important\n}\n\n/* https://github.com/philipwalton/flexbugs#flexbug-3 */\n.hero.is-fullheight > .hero-body {\n min-height: 100vh;\n height: 100%\n}\n\n/* https://github.com/philipwalton/flexbugs#flexbug-2 */\n.hero.is-fullheight > .hero-body > .container {\n width: 100%\n}\n"]}
|
||||
{"version":3,"sources":["css/style.css"],"names":[],"mappings":"AAAA,KACE,wBAAyB,CACzB,eACF,CAEA,KACE,aAAc,CACd,mCAA4B,CAA5B,2BACF,CAEA,iCACE,GACE,SACF,CAEA,GACE,SACF,CACF,CAEA,yBACE,GACE,SACF,CAEA,GACE,SACF,CACF,CAEA,EACE,aACF,CAEA,QACE,aACF,CAEA,GACE,wBACF,CAEA,wBAEE,wBAAyB,CACzB,iBACF,CAEA,OACE,aACF,CAMA,2BACE,aACF,CAEA,qDAEE,aACF,CAEA,uEAEE,aACF,CAEA,mDAEE,aACF,CAEA,6DAEE,aACF,CAEA,wIAQE,oBACF,CAEA,qDACE,wBACF,CAEA,oBAEE,qBACF,CAEA,MACE,aACF,CAEA,gMAIE,SACF,CAEA,6BAEE,aACF,CAEA,SACE,wBACF,CAEA,cACE,aAAc,CACd,QAAS,CACT,kGACF,CAGA,+BACE,gBAAiB,CACjB,WACF,CAGA,0CACE,UACF","file":"style.css","sourcesContent":["html {\n background-color: #232629;\n overflow-y: auto\n}\n\nbody {\n color: #eff0f1;\n animation: fadeInOpacity 0.5s\n}\n\n@-webkit-keyframes fadeInOpacity {\n 0% {\n opacity: 0\n }\n\n 100% {\n opacity: 1\n }\n}\n\n@keyframes fadeInOpacity {\n 0% {\n opacity: 0\n }\n\n 100% {\n opacity: 1\n }\n}\n\na {\n color: #3794d2\n}\n\na:hover {\n color: #60a8dc\n}\n\nhr {\n background-color: #898b8d\n}\n\ncode,\n.message-body code {\n background-color: #222528;\n border-radius: 5px\n}\n\n.title {\n color: #eff0f1\n}\n\n.subtitle {\n color: #bdc3c7\n}\n\n.subtitle strong {\n color: #bdc3c7\n}\n\n.input::-moz-placeholder,\n.textarea::-moz-placeholder {\n color: #7f8c8d\n}\n\n.input::-webkit-input-placeholder,\n.textarea::-webkit-input-placeholder {\n color: #7f8c8d\n}\n\n.input:-moz-placeholder,\n.textarea:-moz-placeholder {\n color: #7f8c8d\n}\n\n.input:-ms-input-placeholder,\n.textarea:-ms-input-placeholder {\n color: #7f8c8d\n}\n\n.input.is-active,\n.input.is-focused,\n.input:active,\n.input:focus,\n.textarea.is-active,\n.textarea.is-focused,\n.textarea:active,\n.textarea:focus {\n border-color: #3794d2\n}\n\n.table.is-hoverable tbody tr:not(.is-selected):hover {\n background-color: #4d4d4d\n}\n\n.table td,\n.table th {\n vertical-align: middle\n}\n\n.help {\n color: #7f8c8d\n}\n\n.button.is-info.is-hovered [class^=\"icon-\"]::before,\n.button.is-info.is-hovered [class*=\" icon-\"]::before,\n.button.is-info:hover [class^=\"icon-\"]::before,\n.button.is-info:hover [class*=\" icon-\"]::before {\n fill: #fff\n}\n\n.checkbox:hover,\n.radio:hover {\n color: #7f8c8d\n}\n\n.message {\n background-color: #31363b\n}\n\n.message-body {\n color: #eff0f1;\n border: 0;\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2)\n}\n\n/* https://github.com/philipwalton/flexbugs#flexbug-3 */\n.hero.is-fullheight > .hero-body {\n min-height: 100vh;\n height: 100%\n}\n\n/* https://github.com/philipwalton/flexbugs#flexbug-2 */\n.hero.is-fullheight > .hero-body > .container {\n width: 100%\n}\n"]}
|
2
dist/css/thumbs.css
vendored
2
dist/css/thumbs.css
vendored
@ -1,2 +1,2 @@
|
||||
.image-container{display:flex;width:224px;height:224px;margin:9px;padding:12px;background-color:#31363b;overflow:hidden;align-items:center;box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2)}.image-container .title{font-weight:400;word-break:break-all}.image-container .image{display:flex;height:100%;width:100%;align-items:center;justify-content:center}.image-container .image img{max-height:100%;max-width:100%;height:auto;width:auto}.image-container .controls{display:flex;position:absolute;top:12px;right:12px}.image-container .controls .button{border-radius:0}.image-container .controls .button:not(:active):not(:hover){color:#fff;background-color:rgba(49,54,59,.75)}.image-container .details{position:absolute;left:12px;bottom:12px;right:12px;background-color:rgba(49,54,59,.75);color:#eff0f1;padding:3px;font-size:.75rem}.image-container .details p{display:block;text-overflow:ellipsis;overflow:hidden}.image-container .details p span{font-weight:700}
|
||||
.image-container{flex:none;position:relative;width:224px;height:224px;margin:.75rem;padding:12px;background-color:#31363b;overflow:hidden;align-items:center;box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2)}.image-container .title{font-weight:400;word-break:break-all}.image-container .image{display:flex;height:100%;width:100%;align-items:center;justify-content:center}.image-container .image img{max-height:100%;max-width:100%;height:auto;width:auto}.image-container .controls{display:flex;position:absolute;top:12px;right:12px}.image-container .controls .button{border-radius:0}.image-container .controls .button:not(:active):not(:hover){color:#fff;background-color:rgba(49,54,59,.75)}.image-container .details{position:absolute;left:12px;bottom:12px;right:12px;background-color:rgba(49,54,59,.75);color:#eff0f1;padding:3px;font-size:.75rem}.image-container .details p{display:block;text-overflow:ellipsis;overflow:hidden}.image-container .details p span{font-weight:700}
|
||||
/*# sourceMappingURL=thumbs.css.map */
|
||||
|
2
dist/css/thumbs.css.map
vendored
2
dist/css/thumbs.css.map
vendored
@ -1 +1 @@
|
||||
{"version":3,"sources":["css/thumbs.css"],"names":[],"mappings":"AAAA,iBACE,YAAa,CACb,WAAY,CACZ,YAAa,CACb,UAAW,CACX,YAAa,CACb,wBAAyB,CACzB,eAAgB,CAChB,kBAAmB,CACnB,kGACF,CAEA,wBACE,eAAmB,CACnB,oBACF,CAEA,wBACE,YAAa,CACb,WAAY,CACZ,UAAW,CACX,kBAAmB,CACnB,sBACF,CAEA,4BACE,eAAgB,CAChB,cAAe,CACf,WAAY,CACZ,UACF,CAEA,2BACE,YAAa,CACb,iBAAkB,CAClB,QAAS,CACT,UACF,CAEA,mCACE,eACF,CAEA,4DACE,UAAW,CACX,mCACF,CAEA,0BACE,iBAAkB,CAClB,SAAU,CACV,WAAY,CACZ,UAAW,CACX,mCAAwC,CACxC,aAAc,CACd,WAAY,CACZ,gBACF,CAEA,4BACE,aAAc,CACd,sBAAuB,CACvB,eACF,CAEA,iCACE,eACF","file":"thumbs.css","sourcesContent":[".image-container {\n display: flex;\n width: 224px;\n height: 224px;\n margin: 9px;\n padding: 12px;\n background-color: #31363b;\n overflow: hidden;\n align-items: center;\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2)\n}\n\n.image-container .title {\n font-weight: normal;\n word-break: break-all\n}\n\n.image-container .image {\n display: flex;\n height: 100%;\n width: 100%;\n align-items: center;\n justify-content: center\n}\n\n.image-container .image img {\n max-height: 100%;\n max-width: 100%;\n height: auto;\n width: auto\n}\n\n.image-container .controls {\n display: flex;\n position: absolute;\n top: 12px;\n right: 12px\n}\n\n.image-container .controls .button {\n border-radius: 0\n}\n\n.image-container .controls .button:not(:active):not(:hover) {\n color: #fff;\n background-color: rgba(49, 54, 59, 0.75)\n}\n\n.image-container .details {\n position: absolute;\n left: 12px;\n bottom: 12px;\n right: 12px;\n background-color: rgba(49, 54, 59, 0.75);\n color: #eff0f1;\n padding: 3px;\n font-size: 0.75rem\n}\n\n.image-container .details p {\n display: block;\n text-overflow: ellipsis;\n overflow: hidden\n}\n\n.image-container .details p span {\n font-weight: bold\n}\n"]}
|
||||
{"version":3,"sources":["css/thumbs.css"],"names":[],"mappings":"AAAA,iBACE,SAAU,CACV,iBAAkB,CAClB,WAAY,CACZ,YAAa,CACb,aAAe,CACf,YAAa,CACb,wBAAyB,CACzB,eAAgB,CAChB,kBAAmB,CACnB,kGACF,CAEA,wBACE,eAAmB,CACnB,oBACF,CAEA,wBACE,YAAa,CACb,WAAY,CACZ,UAAW,CACX,kBAAmB,CACnB,sBACF,CAEA,4BACE,eAAgB,CAChB,cAAe,CACf,WAAY,CACZ,UACF,CAEA,2BACE,YAAa,CACb,iBAAkB,CAClB,QAAS,CACT,UACF,CAEA,mCACE,eACF,CAEA,4DACE,UAAW,CACX,mCACF,CAEA,0BACE,iBAAkB,CAClB,SAAU,CACV,WAAY,CACZ,UAAW,CACX,mCAAwC,CACxC,aAAc,CACd,WAAY,CACZ,gBACF,CAEA,4BACE,aAAc,CACd,sBAAuB,CACvB,eACF,CAEA,iCACE,eACF","file":"thumbs.css","sourcesContent":[".image-container {\n flex: none;\n position: relative;\n width: 224px;\n height: 224px;\n margin: 0.75rem;\n padding: 12px;\n background-color: #31363b;\n overflow: hidden;\n align-items: center;\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2)\n}\n\n.image-container .title {\n font-weight: normal;\n word-break: break-all\n}\n\n.image-container .image {\n display: flex;\n height: 100%;\n width: 100%;\n align-items: center;\n justify-content: center\n}\n\n.image-container .image img {\n max-height: 100%;\n max-width: 100%;\n height: auto;\n width: auto\n}\n\n.image-container .controls {\n display: flex;\n position: absolute;\n top: 12px;\n right: 12px\n}\n\n.image-container .controls .button {\n border-radius: 0\n}\n\n.image-container .controls .button:not(:active):not(:hover) {\n color: #fff;\n background-color: rgba(49, 54, 59, 0.75)\n}\n\n.image-container .details {\n position: absolute;\n left: 12px;\n bottom: 12px;\n right: 12px;\n background-color: rgba(49, 54, 59, 0.75);\n color: #eff0f1;\n padding: 3px;\n font-size: 0.75rem\n}\n\n.image-container .details p {\n display: block;\n text-overflow: ellipsis;\n overflow: hidden\n}\n\n.image-container .details p span {\n font-weight: bold\n}\n"]}
|
2
dist/js/auth.js
vendored
2
dist/js/auth.js
vendored
@ -1,2 +1,2 @@
|
||||
var lsKeys={token:"token"},page={token:localStorage[lsKeys.token],user:null,pass:null,do:function(e,r){var o=page.user.value.trim();if(!o)return swal("An error occurred!","You need to specify a username.","error");var t=page.pass.value.trim();if(!t)return swal("An error occurred!","You need to specify a password.","error");r.classList.add("is-loading"),axios.post("api/"+e,{username:o,password:t}).then((function(o){if(!1===o.data.success)return r.classList.remove("is-loading"),swal("Unable to "+e+"!",o.data.description,"error");localStorage.token=o.data.token,window.location="dashboard"})).catch((function(e){return console.error(e),r.classList.remove("is-loading"),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},verify:function(){page.token&&axios.post("api/tokens/verify",{token:page.token}).then((function(e){if(!1===e.data.success)return swal("An error occurred!",e.data.description,"error");window.location="dashboard"})).catch((function(e){console.error(e);var r=e.response.data&&e.response.data.description?e.response.data.description:"There was an error with the request, please check the console for more information.";return swal(e.response.status+" "+e.response.statusText,r,"error")}))}};window.onload=function(){page.verify(),page.user=document.querySelector("#user"),page.pass=document.querySelector("#pass"),document.querySelector("#authForm").addEventListener("submit",(function(e){e.preventDefault()})),document.querySelector("#loginBtn").addEventListener("click",(function(e){page.do("login",e.currentTarget)})),document.querySelector("#registerBtn").addEventListener("click",(function(e){page.do("register",e.currentTarget)}))};
|
||||
var lsKeys={token:"token"},page={token:localStorage[lsKeys.token],user:null,pass:null,do:function(e,r){var o=page.user.value.trim();if(!o)return swal("An error occurred!","You need to specify a username.","error");var t=page.pass.value.trim();if(!t)return swal("An error occurred!","You need to specify a password.","error");r.classList.add("is-loading"),axios.post("api/"+e,{username:o,password:t}).then((function(o){if(!1===o.data.success)return r.classList.remove("is-loading"),swal("Unable to "+e+"!",o.data.description,"error");localStorage.token=o.data.token,window.location="dashboard"})).catch((function(e){return console.error(e),r.classList.remove("is-loading"),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},verify:function(){page.token&&axios.post("api/tokens/verify",{token:page.token}).then((function(e){if(!1===e.data.success)return swal("An error occurred!",e.data.description,"error");window.location="dashboard"})).catch((function(e){console.error(e);var r=e.response.data&&e.response.data.description?e.response.data.description:"There was an error with the request, please check the console for more information.";return swal(e.response.status+" "+e.response.statusText,r,"error")}))}};window.onload=function(){page.verify(),page.user=document.querySelector("#user"),page.pass=document.querySelector("#pass");var e=document.querySelector("#authForm");e.addEventListener("submit",(function(e){e.preventDefault()})),document.querySelector("#loginBtn").addEventListener("click",(function(r){e.checkValidity()&&page.do("login",r.currentTarget)})),document.querySelector("#registerBtn").addEventListener("click",(function(r){e.checkValidity()&&page.do("register",r.currentTarget)}))};
|
||||
//# sourceMappingURL=auth.js.map
|
||||
|
2
dist/js/auth.js.map
vendored
2
dist/js/auth.js.map
vendored
@ -1 +1 @@
|
||||
{"version":3,"sources":["auth.js"],"names":["const","lsKeys","token","page","localStorage","user","pass","do","dest","trigger","value","trim","swal","classList","add","axios","post","username","password","then","response","data","success","remove","description","window","location","catch","error","console","verify","onload","document","querySelector","addEventListener","event","preventDefault","currentTarget"],"mappings":"AAEAA,IAAMC,OAAS,CACbC,MAAO,SAGHC,KAAO,CAEXD,MAAOE,aAAaH,OAAOC,OAG3BG,KAAM,KACNC,KAAM,KAGRC,GAAO,SAAIC,EAAMC,GACfT,IAAMK,EAAOF,KAAKE,KAAKK,MAAMC,OAC7B,IAAKN,EACH,OAAOO,KAAK,qBAAsB,kCAAmC,SAEvEZ,IAAMM,EAAOH,KAAKG,KAAKI,MAAMC,OAC7B,IAAKL,EACH,OAAOM,KAAK,qBAAsB,kCAAmC,SAEvEH,EAAQI,UAAUC,IAAI,cACtBC,MAAMC,KAAK,OAAOR,EAAQ,CACxBS,SAAUZ,EACVa,SAAUZ,IACTa,MAAI,SAACC,GACN,IAA8B,IAA1BA,EAASC,KAAKC,QAEhB,OADAb,EAAQI,UAAUU,OAAO,cAClBX,KAAK,aAAaJ,EAAI,IAAKY,EAASC,KAAKG,YAAa,SAG/DpB,aAAaF,MAAQkB,EAASC,KAAKnB,MACnCuB,OAAOC,SAAW,eACjBC,OAAK,SAACC,GAGP,OAFAC,QAAQD,MAAMA,GACdnB,EAAQI,UAAUU,OAAO,cAClBX,KAAK,qBAAsB,sFAAuF,aAI7HkB,OAAW,WACJ3B,KAAKD,OAEVa,MAAMC,KAAK,oBAAqB,CAC9Bd,MAAOC,KAAKD,QACXiB,MAAI,SAACC,GACN,IAA8B,IAA1BA,EAASC,KAAKC,QAChB,OAAOV,KAAK,qBAAsBQ,EAASC,KAAKG,YAAa,SAE/DC,OAAOC,SAAW,eACjBC,OAAK,SAACC,GACPC,QAAQD,MAAMA,GACd5B,IAAMwB,EAAcI,EAAMR,SAASC,MAAQO,EAAMR,SAASC,KAAKG,YAC3DI,EAAMR,SAASC,KAAKG,YACpB,sFACJ,OAAOZ,KAAQgB,EAAMR,SAAS,OAAM,IAAIQ,EAAMR,SAAmB,WAAII,EAAa,cAItFC,OAAOM,OAAM,WACX5B,KAAK2B,SAEL3B,KAAKE,KAAO2B,SAASC,cAAc,SACnC9B,KAAKG,KAAO0B,SAASC,cAAc,SAGnCD,SAASC,cAAc,aAAaC,iBAAiB,UAAQ,SAAEC,GAC7DA,EAAMC,oBAGRJ,SAASC,cAAc,aAAaC,iBAAiB,SAAO,SAAEC,GAC5DhC,KAAKI,GAAG,QAAS4B,EAAME,kBAGzBL,SAASC,cAAc,gBAAgBC,iBAAiB,SAAO,SAAEC,GAC/DhC,KAAKI,GAAG,WAAY4B,EAAME","file":"auth.js","sourcesContent":["/* global swal, axios */\n\nconst lsKeys = {\n token: 'token'\n}\n\nconst page = {\n // user token\n token: localStorage[lsKeys.token],\n\n // HTML elements\n user: null,\n pass: null\n}\n\npage.do = (dest, trigger) => {\n const user = page.user.value.trim()\n if (!user)\n return swal('An error occurred!', 'You need to specify a username.', 'error')\n\n const pass = page.pass.value.trim()\n if (!pass)\n return swal('An error occurred!', 'You need to specify a password.', 'error')\n\n trigger.classList.add('is-loading')\n axios.post(`api/${dest}`, {\n username: user,\n password: pass\n }).then(response => {\n if (response.data.success === false) {\n trigger.classList.remove('is-loading')\n return swal(`Unable to ${dest}!`, response.data.description, 'error')\n }\n\n localStorage.token = response.data.token\n window.location = 'dashboard'\n }).catch(error => {\n console.error(error)\n trigger.classList.remove('is-loading')\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.verify = () => {\n if (!page.token) return\n\n axios.post('api/tokens/verify', {\n token: page.token\n }).then(response => {\n if (response.data.success === false)\n return swal('An error occurred!', response.data.description, 'error')\n\n window.location = 'dashboard'\n }).catch(error => {\n console.error(error)\n const description = error.response.data && error.response.data.description\n ? error.response.data.description\n : 'There was an error with the request, please check the console for more information.'\n return swal(`${error.response.status} ${error.response.statusText}`, description, 'error')\n })\n}\n\nwindow.onload = () => {\n page.verify()\n\n page.user = document.querySelector('#user')\n page.pass = document.querySelector('#pass')\n\n // Prevent default form's submit action\n document.querySelector('#authForm').addEventListener('submit', event => {\n event.preventDefault()\n })\n\n document.querySelector('#loginBtn').addEventListener('click', event => {\n page.do('login', event.currentTarget)\n })\n\n document.querySelector('#registerBtn').addEventListener('click', event => {\n page.do('register', event.currentTarget)\n })\n}\n"]}
|
||||
{"version":3,"sources":["auth.js"],"names":["const","lsKeys","token","page","localStorage","user","pass","do","dest","trigger","value","trim","swal","classList","add","axios","post","username","password","then","response","data","success","remove","description","window","location","catch","error","console","verify","onload","document","querySelector","form","addEventListener","event","preventDefault","checkValidity","currentTarget"],"mappings":"AAEAA,IAAMC,OAAS,CACbC,MAAO,SAGHC,KAAO,CAEXD,MAAOE,aAAaH,OAAOC,OAG3BG,KAAM,KACNC,KAAM,KAGRC,GAAO,SAAIC,EAAMC,GACfT,IAAMK,EAAOF,KAAKE,KAAKK,MAAMC,OAC7B,IAAKN,EACH,OAAOO,KAAK,qBAAsB,kCAAmC,SAEvEZ,IAAMM,EAAOH,KAAKG,KAAKI,MAAMC,OAC7B,IAAKL,EACH,OAAOM,KAAK,qBAAsB,kCAAmC,SAEvEH,EAAQI,UAAUC,IAAI,cACtBC,MAAMC,KAAK,OAAOR,EAAQ,CACxBS,SAAUZ,EACVa,SAAUZ,IACTa,MAAI,SAACC,GACN,IAA8B,IAA1BA,EAASC,KAAKC,QAEhB,OADAb,EAAQI,UAAUU,OAAO,cAClBX,KAAK,aAAaJ,EAAI,IAAKY,EAASC,KAAKG,YAAa,SAG/DpB,aAAaF,MAAQkB,EAASC,KAAKnB,MACnCuB,OAAOC,SAAW,eACjBC,OAAK,SAACC,GAGP,OAFAC,QAAQD,MAAMA,GACdnB,EAAQI,UAAUU,OAAO,cAClBX,KAAK,qBAAsB,sFAAuF,aAI7HkB,OAAW,WACJ3B,KAAKD,OAEVa,MAAMC,KAAK,oBAAqB,CAC9Bd,MAAOC,KAAKD,QACXiB,MAAI,SAACC,GACN,IAA8B,IAA1BA,EAASC,KAAKC,QAChB,OAAOV,KAAK,qBAAsBQ,EAASC,KAAKG,YAAa,SAE/DC,OAAOC,SAAW,eACjBC,OAAK,SAACC,GACPC,QAAQD,MAAMA,GACd5B,IAAMwB,EAAcI,EAAMR,SAASC,MAAQO,EAAMR,SAASC,KAAKG,YAC3DI,EAAMR,SAASC,KAAKG,YACpB,sFACJ,OAAOZ,KAAQgB,EAAMR,SAAS,OAAM,IAAIQ,EAAMR,SAAmB,WAAII,EAAa,cAItFC,OAAOM,OAAM,WACX5B,KAAK2B,SAEL3B,KAAKE,KAAO2B,SAASC,cAAc,SACnC9B,KAAKG,KAAO0B,SAASC,cAAc,SAGnCjC,IAAMkC,EAAOF,SAASC,cAAc,aACpCC,EAAKC,iBAAiB,UAAQ,SAAEC,GAC9BA,EAAMC,oBAGRL,SAASC,cAAc,aAAaE,iBAAiB,SAAO,SAAEC,GACvDF,EAAKI,iBACVnC,KAAKI,GAAG,QAAS6B,EAAMG,kBAGzBP,SAASC,cAAc,gBAAgBE,iBAAiB,SAAO,SAAEC,GAC1DF,EAAKI,iBACVnC,KAAKI,GAAG,WAAY6B,EAAMG","file":"auth.js","sourcesContent":["/* global swal, axios */\n\nconst lsKeys = {\n token: 'token'\n}\n\nconst page = {\n // user token\n token: localStorage[lsKeys.token],\n\n // HTML elements\n user: null,\n pass: null\n}\n\npage.do = (dest, trigger) => {\n const user = page.user.value.trim()\n if (!user)\n return swal('An error occurred!', 'You need to specify a username.', 'error')\n\n const pass = page.pass.value.trim()\n if (!pass)\n return swal('An error occurred!', 'You need to specify a password.', 'error')\n\n trigger.classList.add('is-loading')\n axios.post(`api/${dest}`, {\n username: user,\n password: pass\n }).then(response => {\n if (response.data.success === false) {\n trigger.classList.remove('is-loading')\n return swal(`Unable to ${dest}!`, response.data.description, 'error')\n }\n\n localStorage.token = response.data.token\n window.location = 'dashboard'\n }).catch(error => {\n console.error(error)\n trigger.classList.remove('is-loading')\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.verify = () => {\n if (!page.token) return\n\n axios.post('api/tokens/verify', {\n token: page.token\n }).then(response => {\n if (response.data.success === false)\n return swal('An error occurred!', response.data.description, 'error')\n\n window.location = 'dashboard'\n }).catch(error => {\n console.error(error)\n const description = error.response.data && error.response.data.description\n ? error.response.data.description\n : 'There was an error with the request, please check the console for more information.'\n return swal(`${error.response.status} ${error.response.statusText}`, description, 'error')\n })\n}\n\nwindow.onload = () => {\n page.verify()\n\n page.user = document.querySelector('#user')\n page.pass = document.querySelector('#pass')\n\n // Prevent default form's submit action\n const form = document.querySelector('#authForm')\n form.addEventListener('submit', event => {\n event.preventDefault()\n })\n\n document.querySelector('#loginBtn').addEventListener('click', event => {\n if (!form.checkValidity()) return\n page.do('login', event.currentTarget)\n })\n\n document.querySelector('#registerBtn').addEventListener('click', event => {\n if (!form.checkValidity()) return\n page.do('register', event.currentTarget)\n })\n}\n"]}
|
2
dist/js/dashboard.js
vendored
2
dist/js/dashboard.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/dashboard.js.map
vendored
2
dist/js/dashboard.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/js/home.js
vendored
2
dist/js/home.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/home.js.map
vendored
2
dist/js/home.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/libs/fontello/fontello.css
vendored
2
dist/libs/fontello/fontello.css
vendored
@ -1,2 +1,2 @@
|
||||
@font-face{font-family:fontello;src:url(fontello.eot?fFS2CGH95j);src:url(fontello.eot?fFS2CGH95j#iefix) format("embedded-opentype"),url(fontello.woff2?fFS2CGH95j) format("woff2"),url(fontello.woff?fFS2CGH95j) format("woff"),url(fontello.ttf?fFS2CGH95j) format("truetype"),url(fontello.svg?fFS2CGH95j#fontello) format("svg");font-weight:400;font-style:normal}[class*=" icon-"]:before,[class^=icon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-feature-settings:normal;font-variant:normal;text-transform:none;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-2x:before{font-size:2rem}.icon-archive:before{content:"\e800"}.icon-sharex:before{content:"\e801"}.icon-picture:before{content:"\e802"}.icon-th-list:before{content:"\e803"}.icon-trash:before{content:"\e804"}.icon-cancel:before{content:"\e805"}.icon-arrows-cw:before{content:"\e806"}.icon-plus:before{content:"\e807"}.icon-clipboard:before{content:"\e808"}.icon-login:before{content:"\e809"}.icon-home:before{content:"\e80a"}.icon-gauge:before{content:"\e80b"}.icon-help-circled:before{content:"\e80d"}.icon-github-circled:before{content:"\e80e"}.icon-pencil:before{content:"\e80f"}.icon-terminal:before{content:"\e810"}.icon-hammer:before{content:"\e811"}.icon-block:before{content:"\e812"}.icon-link:before{content:"\e813"}.icon-cog-alt:before{content:"\e814"}.icon-floppy:before{content:"\e815"}.icon-user-plus:before{content:"\e816"}.icon-privatebin:before{content:"\e817"}.icon-upload-cloud:before{content:"\e819"}.icon-th-large:before{content:"\e81a"}.icon-download:before{content:"\e81b"}.icon-gatsby:before{content:"\e81c"}.icon-filter:before{content:"\f0b0"}.icon-docs:before{content:"\f0c5"}.icon-doc-inv:before{content:"\f15b"}.icon-paper-plane:before{content:"\f1d8"}.icon-chrome:before{content:"\f268"}.icon-firefox:before{content:"\f269"}
|
||||
@font-face{font-family:fontello;src:url(fontello.eot?iDzQ0dov5j);src:url(fontello.eot?iDzQ0dov5j#iefix) format("embedded-opentype"),url(fontello.woff2?iDzQ0dov5j) format("woff2"),url(fontello.woff?iDzQ0dov5j) format("woff"),url(fontello.ttf?iDzQ0dov5j) format("truetype"),url(fontello.svg?iDzQ0dov5j#fontello) format("svg");font-weight:400;font-style:normal}[class*=" icon-"]:before,[class^=icon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-feature-settings:normal;font-variant:normal;text-transform:none;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-2x:before{font-size:2rem}.icon-archive:before{content:"\e800"}.icon-sharex:before{content:"\e801"}.icon-picture:before{content:"\e802"}.icon-th-list:before{content:"\e803"}.icon-trash:before{content:"\e804"}.icon-cancel:before{content:"\e805"}.icon-arrows-cw:before{content:"\e806"}.icon-plus:before{content:"\e807"}.icon-clipboard:before{content:"\e808"}.icon-login:before{content:"\e809"}.icon-home:before{content:"\e80a"}.icon-gauge:before{content:"\e80b"}.icon-video:before{content:"\e80c"}.icon-help-circled:before{content:"\e80d"}.icon-github-circled:before{content:"\e80e"}.icon-pencil:before{content:"\e80f"}.icon-terminal:before{content:"\e810"}.icon-hammer:before{content:"\e811"}.icon-block:before{content:"\e812"}.icon-link:before{content:"\e813"}.icon-cog-alt:before{content:"\e814"}.icon-floppy:before{content:"\e815"}.icon-user-plus:before{content:"\e816"}.icon-privatebin:before{content:"\e817"}.icon-upload-cloud:before{content:"\e819"}.icon-th-large:before{content:"\e81a"}.icon-download:before{content:"\e81b"}.icon-gatsby:before{content:"\e81c"}.icon-filter:before{content:"\f0b0"}.icon-docs:before{content:"\f0c5"}.icon-doc-inv:before{content:"\f15b"}.icon-paper-plane:before{content:"\f1d8"}.icon-chrome:before{content:"\f268"}.icon-firefox:before{content:"\f269"}
|
||||
/*# sourceMappingURL=fontello.css.map */
|
||||
|
2
dist/libs/fontello/fontello.css.map
vendored
2
dist/libs/fontello/fontello.css.map
vendored
@ -1 +1 @@
|
||||
{"version":3,"sources":["libs/fontello/fontello.css"],"names":[],"mappings":"AAAA,WACE,oBAAuB,CACvB,gCAAmC,CACnC,kQAKuD,CACvD,eAAmB,CACnB,iBACF,CAaA,+CAEE,oBAAuB,CACvB,iBAAkB,CAClB,eAAmB,CACnB,UAAW,CACX,oBAAqB,CACrB,uBAAwB,CACxB,SAAU,CACV,iBAAmB,CACnB,iBAAkB,CAIlB,4BAAoB,CAApB,mBAAoB,CACpB,mBAAoB,CAOpB,gBAAkB,CAMlB,kCAAmC,CACnC,iCAIF,CAEA,gBACE,cACF,CAEA,qBAAwB,eAAiB,CACzC,oBAAuB,eAAiB,CACxC,qBAAwB,eAAiB,CACzC,qBAAwB,eAAiB,CACzC,mBAAsB,eAAiB,CACvC,oBAAuB,eAAiB,CACxC,uBAA0B,eAAiB,CAC3C,kBAAqB,eAAiB,CACtC,uBAA0B,eAAiB,CAC3C,mBAAsB,eAAiB,CACvC,kBAAqB,eAAiB,CACtC,mBAAsB,eAAiB,CACvC,0BAA6B,eAAiB,CAC9C,4BAA+B,eAAiB,CAChD,oBAAuB,eAAiB,CACxC,sBAAyB,eAAiB,CAC1C,oBAAuB,eAAiB,CACxC,mBAAsB,eAAiB,CACvC,kBAAqB,eAAiB,CACtC,qBAAwB,eAAiB,CACzC,oBAAuB,eAAiB,CACxC,uBAA0B,eAAiB,CAC3C,wBAA2B,eAAiB,CAC5C,0BAA6B,eAAiB,CAC9C,sBAAyB,eAAiB,CAC1C,sBAAyB,eAAiB,CAC1C,oBAAuB,eAAiB,CACxC,oBAAuB,eAAiB,CACxC,kBAAqB,eAAiB,CACtC,qBAAwB,eAAiB,CACzC,yBAA4B,eAAiB,CAC7C,oBAAuB,eAAiB,CACxC,qBAAwB,eAAiB","file":"fontello.css","sourcesContent":["@font-face {\n font-family: 'fontello';\n src: url('fontello.eot?fFS2CGH95j');\n src:\n url('fontello.eot?fFS2CGH95j#iefix') format('embedded-opentype'),\n url('fontello.woff2?fFS2CGH95j') format('woff2'),\n url('fontello.woff?fFS2CGH95j') format('woff'),\n url('fontello.ttf?fFS2CGH95j') format('truetype'),\n url('fontello.svg?fFS2CGH95j#fontello') format('svg');\n font-weight: normal;\n font-style: normal\n}\n\n/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */\n/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */\n/*\n@media screen and (-webkit-min-device-pixel-ratio:0) {\n @font-face {\n font-family: 'fontello';\n src: url('fontello.svg?fFS2CGH95j#fontello') format('svg');\n }\n}\n*/\n\n[class^=\"icon-\"]::before,\n[class*=\" icon-\"]::before {\n font-family: \"fontello\";\n font-style: normal;\n font-weight: normal;\n speak: none;\n display: inline-block;\n text-decoration: inherit;\n width: 1em;\n margin-right: 0.2em;\n text-align: center;\n /* opacity: .8; */\n\n /* For safety - reset parent styles, that can break glyph codes */\n font-variant: normal;\n text-transform: none;\n\n /* fix buttons height, for twitter bootstrap */\n /* line-height: 1em; */\n\n /* Animation center compensation - margins should be symmetric */\n /* remove if not needed */\n margin-left: 0.2em;\n\n /* you can be more comfortable with increased icons size */\n /* font-size: 120%; */\n\n /* Font smoothing. That was taken from TWBS */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* Uncomment for 3D effect */\n /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */\n}\n\n.icon-2x::before {\n font-size: 2rem\n}\n\n.icon-archive::before { content: '\\e800' } /* '' */\n.icon-sharex::before { content: '\\e801' } /* '' */\n.icon-picture::before { content: '\\e802' } /* '' */\n.icon-th-list::before { content: '\\e803' } /* '' */\n.icon-trash::before { content: '\\e804' } /* '' */\n.icon-cancel::before { content: '\\e805' } /* '' */\n.icon-arrows-cw::before { content: '\\e806' } /* '' */\n.icon-plus::before { content: '\\e807' } /* '' */\n.icon-clipboard::before { content: '\\e808' } /* '' */\n.icon-login::before { content: '\\e809' } /* '' */\n.icon-home::before { content: '\\e80a' } /* '' */\n.icon-gauge::before { content: '\\e80b' } /* '' */\n.icon-help-circled::before { content: '\\e80d' } /* '' */\n.icon-github-circled::before { content: '\\e80e' } /* '' */\n.icon-pencil::before { content: '\\e80f' } /* '' */\n.icon-terminal::before { content: '\\e810' } /* '' */\n.icon-hammer::before { content: '\\e811' } /* '' */\n.icon-block::before { content: '\\e812' } /* '' */\n.icon-link::before { content: '\\e813' } /* '' */\n.icon-cog-alt::before { content: '\\e814' } /* '' */\n.icon-floppy::before { content: '\\e815' } /* '' */\n.icon-user-plus::before { content: '\\e816' } /* '' */\n.icon-privatebin::before { content: '\\e817' } /* '' */\n.icon-upload-cloud::before { content: '\\e819' } /* '' */\n.icon-th-large::before { content: '\\e81a' } /* '' */\n.icon-download::before { content: '\\e81b' } /* '' */\n.icon-gatsby::before { content: '\\e81c' } /* '' */\n.icon-filter::before { content: '\\f0b0' } /* '' */\n.icon-docs::before { content: '\\f0c5' } /* '' */\n.icon-doc-inv::before { content: '\\f15b' } /* '' */\n.icon-paper-plane::before { content: '\\f1d8' } /* '' */\n.icon-chrome::before { content: '\\f268' } /* '' */\n.icon-firefox::before { content: '\\f269' } /* '' */\n"]}
|
||||
{"version":3,"sources":["libs/fontello/fontello.css"],"names":[],"mappings":"AAAA,WACE,oBAAuB,CACvB,gCAAmC,CACnC,kQAKuD,CACvD,eAAmB,CACnB,iBACF,CAaA,+CAEE,oBAAuB,CACvB,iBAAkB,CAClB,eAAmB,CACnB,UAAW,CACX,oBAAqB,CACrB,uBAAwB,CACxB,SAAU,CACV,iBAAmB,CACnB,iBAAkB,CAIlB,4BAAoB,CAApB,mBAAoB,CACpB,mBAAoB,CAOpB,gBAAkB,CAMlB,kCAAmC,CACnC,iCAIF,CAEA,gBACE,cACF,CAEA,qBAAwB,eAAiB,CACzC,oBAAuB,eAAiB,CACxC,qBAAwB,eAAiB,CACzC,qBAAwB,eAAiB,CACzC,mBAAsB,eAAiB,CACvC,oBAAuB,eAAiB,CACxC,uBAA0B,eAAiB,CAC3C,kBAAqB,eAAiB,CACtC,uBAA0B,eAAiB,CAC3C,mBAAsB,eAAiB,CACvC,kBAAqB,eAAiB,CACtC,mBAAsB,eAAiB,CACvC,mBAAqB,eAAkB,CACvC,0BAA6B,eAAiB,CAC9C,4BAA+B,eAAiB,CAChD,oBAAuB,eAAiB,CACxC,sBAAyB,eAAiB,CAC1C,oBAAuB,eAAiB,CACxC,mBAAsB,eAAiB,CACvC,kBAAqB,eAAiB,CACtC,qBAAwB,eAAiB,CACzC,oBAAuB,eAAiB,CACxC,uBAA0B,eAAiB,CAC3C,wBAA2B,eAAiB,CAC5C,0BAA6B,eAAiB,CAC9C,sBAAyB,eAAiB,CAC1C,sBAAyB,eAAiB,CAC1C,oBAAuB,eAAiB,CACxC,oBAAuB,eAAiB,CACxC,kBAAqB,eAAiB,CACtC,qBAAwB,eAAiB,CACzC,yBAA4B,eAAiB,CAC7C,oBAAuB,eAAiB,CACxC,qBAAwB,eAAiB","file":"fontello.css","sourcesContent":["@font-face {\n font-family: 'fontello';\n src: url('fontello.eot?iDzQ0dov5j');\n src:\n url('fontello.eot?iDzQ0dov5j#iefix') format('embedded-opentype'),\n url('fontello.woff2?iDzQ0dov5j') format('woff2'),\n url('fontello.woff?iDzQ0dov5j') format('woff'),\n url('fontello.ttf?iDzQ0dov5j') format('truetype'),\n url('fontello.svg?iDzQ0dov5j#fontello') format('svg');\n font-weight: normal;\n font-style: normal\n}\n\n/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */\n/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */\n/*\n@media screen and (-webkit-min-device-pixel-ratio:0) {\n @font-face {\n font-family: 'fontello';\n src: url('fontello.svg?iDzQ0dov5j#fontello') format('svg');\n }\n}\n*/\n\n[class^=\"icon-\"]::before,\n[class*=\" icon-\"]::before {\n font-family: \"fontello\";\n font-style: normal;\n font-weight: normal;\n speak: none;\n display: inline-block;\n text-decoration: inherit;\n width: 1em;\n margin-right: 0.2em;\n text-align: center;\n /* opacity: .8; */\n\n /* For safety - reset parent styles, that can break glyph codes */\n font-variant: normal;\n text-transform: none;\n\n /* fix buttons height, for twitter bootstrap */\n /* line-height: 1em; */\n\n /* Animation center compensation - margins should be symmetric */\n /* remove if not needed */\n margin-left: 0.2em;\n\n /* you can be more comfortable with increased icons size */\n /* font-size: 120%; */\n\n /* Font smoothing. That was taken from TWBS */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* Uncomment for 3D effect */\n /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */\n}\n\n.icon-2x::before {\n font-size: 2rem\n}\n\n.icon-archive::before { content: '\\e800' } /* '' */\n.icon-sharex::before { content: '\\e801' } /* '' */\n.icon-picture::before { content: '\\e802' } /* '' */\n.icon-th-list::before { content: '\\e803' } /* '' */\n.icon-trash::before { content: '\\e804' } /* '' */\n.icon-cancel::before { content: '\\e805' } /* '' */\n.icon-arrows-cw::before { content: '\\e806' } /* '' */\n.icon-plus::before { content: '\\e807' } /* '' */\n.icon-clipboard::before { content: '\\e808' } /* '' */\n.icon-login::before { content: '\\e809' } /* '' */\n.icon-home::before { content: '\\e80a' } /* '' */\n.icon-gauge::before { content: '\\e80b' } /* '' */\n.icon-video:before { content: '\\e80c'; } /* '' */\n.icon-help-circled::before { content: '\\e80d' } /* '' */\n.icon-github-circled::before { content: '\\e80e' } /* '' */\n.icon-pencil::before { content: '\\e80f' } /* '' */\n.icon-terminal::before { content: '\\e810' } /* '' */\n.icon-hammer::before { content: '\\e811' } /* '' */\n.icon-block::before { content: '\\e812' } /* '' */\n.icon-link::before { content: '\\e813' } /* '' */\n.icon-cog-alt::before { content: '\\e814' } /* '' */\n.icon-floppy::before { content: '\\e815' } /* '' */\n.icon-user-plus::before { content: '\\e816' } /* '' */\n.icon-privatebin::before { content: '\\e817' } /* '' */\n.icon-upload-cloud::before { content: '\\e819' } /* '' */\n.icon-th-large::before { content: '\\e81a' } /* '' */\n.icon-download::before { content: '\\e81b' } /* '' */\n.icon-gatsby::before { content: '\\e81c' } /* '' */\n.icon-filter::before { content: '\\f0b0' } /* '' */\n.icon-docs::before { content: '\\f0c5' } /* '' */\n.icon-doc-inv::before { content: '\\f15b' } /* '' */\n.icon-paper-plane::before { content: '\\f1d8' } /* '' */\n.icon-chrome::before { content: '\\f268' } /* '' */\n.icon-firefox::before { content: '\\f269' } /* '' */\n"]}
|
21
gulpfile.js
21
gulpfile.js
@ -11,6 +11,13 @@ const sourcemaps = require('gulp-sourcemaps')
|
||||
const stylelint = require('gulp-stylelint')
|
||||
const terser = require('gulp-terser')
|
||||
|
||||
// Put built files for development on a Git-ignored directory.
|
||||
// This will prevent IDE's Git from unnecessarily
|
||||
// building diff's during development.
|
||||
const dist = process.env.NODE_ENV === 'development'
|
||||
? './dist-dev'
|
||||
: './dist'
|
||||
|
||||
/** TASKS: LINT */
|
||||
|
||||
gulp.task('lint:js', () => {
|
||||
@ -34,21 +41,21 @@ gulp.task('lint', gulp.parallel('lint:js', 'lint:css'))
|
||||
|
||||
gulp.task('clean:css', () => {
|
||||
return del([
|
||||
'./dist/**/*.css',
|
||||
'./dist/**/*.css.map'
|
||||
`${dist}/**/*.css`,
|
||||
`${dist}/**/*.css.map`
|
||||
])
|
||||
})
|
||||
|
||||
gulp.task('clean:js', () => {
|
||||
return del([
|
||||
'./dist/**/*.js',
|
||||
'./dist/**/*.js.map'
|
||||
`${dist}/**/*.js`,
|
||||
`${dist}/**/*.js.map`
|
||||
])
|
||||
})
|
||||
|
||||
gulp.task('clean:rest', () => {
|
||||
return del([
|
||||
'./dist/*'
|
||||
`${dist}/*`
|
||||
])
|
||||
})
|
||||
|
||||
@ -69,7 +76,7 @@ gulp.task('build:css', () => {
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(postcss(plugins))
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest('./dist'))
|
||||
.pipe(gulp.dest(dist))
|
||||
})
|
||||
|
||||
gulp.task('build:js', () => {
|
||||
@ -79,7 +86,7 @@ gulp.task('build:js', () => {
|
||||
// Minify on production
|
||||
.pipe(gulpif(process.env.NODE_ENV !== 'development', terser()))
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest('./dist'))
|
||||
.pipe(gulp.dest(dist))
|
||||
})
|
||||
|
||||
gulp.task('build', gulp.parallel('build:css', 'build:js'))
|
||||
|
20
lolisafe.js
20
lolisafe.js
@ -117,25 +117,9 @@ safe.use('/api', api)
|
||||
if (!await paths.access(customPage).catch(() => true))
|
||||
safe.get(`/${page === 'home' ? '' : page}`, (req, res, next) => res.sendFile(customPage))
|
||||
else if (page === 'home')
|
||||
safe.get('/', (req, res, next) => res.render('home', {
|
||||
maxSize: parseInt(config.uploads.maxSize),
|
||||
urlMaxSize: parseInt(config.uploads.urlMaxSize),
|
||||
urlDisclaimerMessage: config.uploads.urlDisclaimerMessage,
|
||||
urlExtensionsFilterMode: config.uploads.urlExtensionsFilterMode,
|
||||
urlExtensionsFilter: config.uploads.urlExtensionsFilter,
|
||||
temporaryUploadAges: Array.isArray(config.uploads.temporaryUploadAges) &&
|
||||
config.uploads.temporaryUploadAges.length,
|
||||
gitHash: utils.gitHash
|
||||
}))
|
||||
else if (page === 'faq')
|
||||
safe.get('/faq', (req, res, next) => res.render('faq', {
|
||||
whitelist: config.extensionsFilterMode === 'whitelist',
|
||||
extensionsFilter: config.extensionsFilter,
|
||||
noJsMaxSize: parseInt(config.cloudflare.noJsMaxSize) < parseInt(config.uploads.maxSize),
|
||||
chunkSize: parseInt(config.uploads.chunkSize)
|
||||
}))
|
||||
safe.get('/', (req, res, next) => res.render(page, { config, gitHash: utils.gitHash }))
|
||||
else
|
||||
safe.get(`/${page}`, (req, res, next) => res.render(page))
|
||||
safe.get(`/${page}`, (req, res, next) => res.render(page, { config }))
|
||||
}
|
||||
|
||||
// Error pages
|
||||
|
@ -68,6 +68,6 @@
|
||||
"gulp-terser": "^1.2.0",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"stylelint": "^10.1.0",
|
||||
"stylelint-config-standard": "^18.3.0"
|
||||
"stylelint-config-standard": "^19.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -235,6 +235,12 @@
|
||||
"search": [
|
||||
"gatsby"
|
||||
]
|
||||
},
|
||||
{
|
||||
"uid": "31accb20e8819b200c297df608e68830",
|
||||
"css": "video",
|
||||
"code": 59404,
|
||||
"src": "elusive"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
@ -30,6 +30,8 @@
|
||||
|
||||
<glyph glyph-name="gauge" unicode="" d="M214 207q0 30-21 51t-50 21-51-21-21-51 21-50 51-21 50 21 21 50z m107 250q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m239-268l57 213q3 14-5 27t-21 16-27-3-17-22l-56-213q-33-3-60-25t-35-55q-11-43 11-81t66-50 81 11 50 66q9 33-4 65t-40 51z m369 18q0 30-21 51t-51 21-50-21-21-51 21-50 50-21 51 21 21 50z m-358 357q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m250-107q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m179-250q0-145-79-269-10-17-30-17h-782q-20 0-30 17-79 123-79 269 0 102 40 194t106 160 160 107 194 39 194-39 160-107 106-160 40-194z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="video" unicode="" d="M0-29l0 758 1000 0 0-758-1000 0z m123 123l754 0 0 512-754 0 0-512z m266 82l0 340 293-170z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="help-circled" unicode="" d="M500 82v107q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h107q8 0 13 5t5 13z m143 375q0 49-31 91t-77 65-95 23q-136 0-207-119-9-13 4-24l74-55q4-4 10-4 9 0 14 7 30 38 48 51 19 14 48 14 27 0 48-15t21-33q0-21-11-34t-38-25q-35-15-65-48t-29-70v-20q0-8 5-13t13-5h107q8 0 13 5t5 13q0 10 12 27t30 28q18 10 28 16t25 19 25 27 16 34 7 45z m214-107q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
|
||||
|
||||
<glyph glyph-name="github-circled" unicode="" d="M429 779q116 0 215-58t156-156 57-215q0-140-82-252t-211-155q-15-3-22 4t-7 17q0 1 0 43t0 75q0 54-29 79 32 3 57 10t53 22 45 37 30 58 11 84q0 67-44 115 21 51-4 114-16 5-46-6t-51-25l-21-13q-52 15-107 15t-108-15q-8 6-23 15t-47 22-47 7q-25-63-5-114-44-48-44-115 0-47 12-83t29-59 45-37 52-22 57-10q-21-20-27-58-12-5-25-8t-32-3-36 12-31 35q-11 18-27 29t-28 14l-11 1q-12 0-16-2t-3-7 5-8 7-6l4-3q12-6 24-21t18-29l6-13q7-21 24-34t37-17 39-3 31 1l13 3q0-22 0-50t1-30q0-10-8-17t-22-4q-129 43-211 155t-82 252q0 117 58 215t155 156 216 58z m-267-616q2 4-3 7-6 1-8-1-1-4 4-7 5-3 7 1z m18-19q4 3-1 9-6 5-9 2-4-3 1-9 5-6 9-2z m16-25q6 4 0 11-4 7-9 3-5-3 0-10t9-4z m24-23q4 4-2 10-7 7-11 2-5-5 2-11 6-6 11-1z m32-14q1 6-8 9-8 2-10-4t7-9q8-3 11 4z m35-3q0 7-10 6-9 0-9-6 0-7 10-6 9 0 9 6z m32 5q-1 7-10 5-9-1-8-8t10-4 8 7z" horiz-adv-x="857.1" />
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -5,8 +5,6 @@ const utils = require('./../controllers/utilsController')
|
||||
const config = require('./../config')
|
||||
const db = require('knex')(config.database)
|
||||
|
||||
const homeDomain = config.homeDomain || config.domain
|
||||
|
||||
routes.get('/a/:identifier', async (req, res, next) => {
|
||||
const identifier = req.params.identifier
|
||||
if (identifier === undefined)
|
||||
@ -20,6 +18,7 @@ routes.get('/a/:identifier', async (req, res, next) => {
|
||||
identifier,
|
||||
enabled: 1
|
||||
})
|
||||
.select('id', 'name', 'identifier', 'editedAt', 'download', 'public', 'description')
|
||||
.first()
|
||||
|
||||
if (!album)
|
||||
@ -30,44 +29,70 @@ routes.get('/a/:identifier', async (req, res, next) => {
|
||||
description: 'This album is not available for public.'
|
||||
})
|
||||
|
||||
const nojs = req.query.nojs !== undefined
|
||||
|
||||
// Cache ID - we initialize a separate cache for No-JS version
|
||||
const cacheid = nojs ? `${album.id}-nojs` : album.id
|
||||
|
||||
if (!utils.albumsCache[cacheid])
|
||||
utils.albumsCache[cacheid] = {
|
||||
cache: null,
|
||||
generating: false,
|
||||
// Cache will actually be deleted after the album has been updated,
|
||||
// so storing this timestamp may be redundant, but just in case.
|
||||
generatedAt: 0
|
||||
}
|
||||
|
||||
if (!utils.albumsCache[cacheid].cache && utils.albumsCache[cacheid].generating)
|
||||
return res.json({
|
||||
success: false,
|
||||
description: 'This album is still generating its public page.'
|
||||
})
|
||||
else if ((album.editedAt < utils.albumsCache[cacheid].generatedAt) || utils.albumsCache[cacheid].generating)
|
||||
return res.send(utils.albumsCache[cacheid].cache)
|
||||
|
||||
// Use current timestamp to make sure cache is invalidated
|
||||
// when an album is edited during this generation process.
|
||||
utils.albumsCache[cacheid].generating = true
|
||||
utils.albumsCache[cacheid].generatedAt = Math.floor(Date.now() / 1000)
|
||||
|
||||
const files = await db.table('files')
|
||||
.select('name', 'size')
|
||||
.where('albumid', album.id)
|
||||
.orderBy('id', 'DESC')
|
||||
|
||||
let thumb = ''
|
||||
const basedomain = config.domain
|
||||
album.thumb = ''
|
||||
album.totalSize = 0
|
||||
|
||||
let totalSize = 0
|
||||
for (const file of files) {
|
||||
file.file = `${basedomain}/${file.name}`
|
||||
file.extname = path.extname(file.name).toLowerCase()
|
||||
album.totalSize += parseInt(file.size)
|
||||
|
||||
file.extname = path.extname(file.name)
|
||||
if (utils.mayGenerateThumb(file.extname)) {
|
||||
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -file.extname.length)}.png`
|
||||
/*
|
||||
If thumbnail for album is still not set, set it to current file's full URL.
|
||||
A potential improvement would be to let the user set a specific image as an album cover.
|
||||
*/
|
||||
if (thumb === '') thumb = file.file
|
||||
file.thumb = `thumbs/${file.name.slice(0, -file.extname.length)}.png`
|
||||
// If thumbnail for album is still not set, set it to current file's full URL.
|
||||
// A potential improvement would be to let the user set a specific image as an album cover.
|
||||
if (!album.thumb) album.thumb = file.name
|
||||
}
|
||||
totalSize += parseInt(file.size)
|
||||
}
|
||||
|
||||
return res.render('album', {
|
||||
title: album.name,
|
||||
description: album.description ? album.description.replace(/\n/g, '<br>') : null,
|
||||
count: files.length,
|
||||
thumb,
|
||||
files,
|
||||
identifier,
|
||||
generateZips: config.uploads.generateZips,
|
||||
downloadLink: album.download === 0
|
||||
? null
|
||||
: `${homeDomain}/api/album/zip/${album.identifier}?v=${album.editedAt}`,
|
||||
editedAt: album.editedAt,
|
||||
url: `${homeDomain}/a/${album.identifier}`,
|
||||
totalSize,
|
||||
nojs: req.query.nojs !== undefined
|
||||
album.description = album.description
|
||||
? album.description.replace(/\n/g, '<br>')
|
||||
: null
|
||||
|
||||
album.downloadLink = album.download === 0
|
||||
? null
|
||||
: `api/album/zip/${album.identifier}?v=${album.editedAt}`
|
||||
|
||||
album.url = `a/${album.identifier}`
|
||||
|
||||
return res.render('album', { config, album, files, nojs }, (error, html) => {
|
||||
utils.albumsCache[cacheid].cache = error ? null : html
|
||||
utils.albumsCache[cacheid].generating = false
|
||||
|
||||
// Express should already send error to the next handler
|
||||
if (error) return
|
||||
return res.send(utils.albumsCache[cacheid].cache)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -3,39 +3,21 @@ const uploadController = require('./../controllers/uploadController')
|
||||
const utils = require('./../controllers/utilsController')
|
||||
const config = require('./../config')
|
||||
|
||||
const renderOptions = {
|
||||
uploadDisabled: false,
|
||||
maxFileSize: parseInt(config.cloudflare.noJsMaxSize || config.uploads.maxSize)
|
||||
}
|
||||
|
||||
if (config.private)
|
||||
if (config.enableUserAccounts) {
|
||||
renderOptions.uploadDisabled = 'Anonymous upload is disabled.'
|
||||
} else {
|
||||
renderOptions.uploadDisabled = 'Running in private mode.'
|
||||
}
|
||||
|
||||
routes.get('/nojs', async (req, res, next) => {
|
||||
const options = { renderOptions }
|
||||
options.gitHash = utils.gitHash
|
||||
|
||||
return res.render('nojs', options)
|
||||
return res.render('nojs', { config, gitHash: utils.gitHash })
|
||||
})
|
||||
|
||||
routes.post('/nojs', (req, res, next) => {
|
||||
res._json = res.json
|
||||
res.json = (...args) => {
|
||||
const result = args[0]
|
||||
|
||||
const options = { renderOptions }
|
||||
options.gitHash = utils.utils
|
||||
|
||||
options.errorMessage = result.success ? '' : (result.description || 'An unexpected error occurred.')
|
||||
options.files = result.files || [{}]
|
||||
|
||||
return res.render('nojs', options)
|
||||
return res.render('nojs', {
|
||||
config,
|
||||
gitHash: utils.gitHash,
|
||||
errorMessage: result.success ? '' : (result.description || 'An unexpected error occurred.'),
|
||||
files: result.files || [{}]
|
||||
})
|
||||
}
|
||||
|
||||
return uploadController.upload(req, res, next)
|
||||
})
|
||||
|
||||
|
@ -33,6 +33,21 @@ body {
|
||||
background: none
|
||||
}
|
||||
|
||||
.menu-list a.is-loading::after {
|
||||
animation: spinAround 0.5s infinite linear;
|
||||
border: 2px solid #dbdbdb;
|
||||
border-radius: 290486px;
|
||||
border-right-color: transparent;
|
||||
border-top-color: transparent;
|
||||
content: "";
|
||||
display: block;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
right: calc(0% + (1em / 2));
|
||||
top: calc(50% - (1em / 2));
|
||||
position: absolute !important
|
||||
}
|
||||
|
||||
ul#albumsContainer {
|
||||
border-left: 0;
|
||||
padding-left: 0
|
||||
@ -155,7 +170,7 @@ li[data-action="page-ellipsis"] {
|
||||
text-decoration: line-through
|
||||
}
|
||||
|
||||
#menu.is-loading li a {
|
||||
#menu.is-loading .menu-list a {
|
||||
cursor: progress
|
||||
}
|
||||
|
||||
|
@ -124,21 +124,6 @@ code,
|
||||
box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2)
|
||||
}
|
||||
|
||||
.menu-list a.is-loading::after {
|
||||
animation: spinAround 0.5s infinite linear;
|
||||
border: 2px solid #dbdbdb;
|
||||
border-radius: 290486px;
|
||||
border-right-color: transparent;
|
||||
border-top-color: transparent;
|
||||
content: "";
|
||||
display: block;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
right: calc(0% + (1em / 2));
|
||||
top: calc(50% - (1em / 2));
|
||||
position: absolute !important
|
||||
}
|
||||
|
||||
/* https://github.com/philipwalton/flexbugs#flexbug-3 */
|
||||
.hero.is-fullheight > .hero-body {
|
||||
min-height: 100vh;
|
||||
|
@ -1,8 +1,9 @@
|
||||
.image-container {
|
||||
display: flex;
|
||||
flex: none;
|
||||
position: relative;
|
||||
width: 224px;
|
||||
height: 224px;
|
||||
margin: 9px;
|
||||
margin: 0.75rem;
|
||||
padding: 12px;
|
||||
background-color: #31363b;
|
||||
overflow: hidden;
|
||||
|
@ -67,15 +67,18 @@ window.onload = () => {
|
||||
page.pass = document.querySelector('#pass')
|
||||
|
||||
// Prevent default form's submit action
|
||||
document.querySelector('#authForm').addEventListener('submit', event => {
|
||||
const form = document.querySelector('#authForm')
|
||||
form.addEventListener('submit', event => {
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
document.querySelector('#loginBtn').addEventListener('click', event => {
|
||||
if (!form.checkValidity()) return
|
||||
page.do('login', event.currentTarget)
|
||||
})
|
||||
|
||||
document.querySelector('#registerBtn').addEventListener('click', event => {
|
||||
if (!form.checkValidity()) return
|
||||
page.do('register', event.currentTarget)
|
||||
})
|
||||
}
|
||||
|
@ -84,7 +84,10 @@ const page = {
|
||||
videoExts: ['.webm', '.mp4', '.wmv', '.avi', '.mov', '.mkv'],
|
||||
|
||||
isTriggerLoading: null,
|
||||
fadingIn: null
|
||||
fadingIn: null,
|
||||
|
||||
albumTitleMaxLength: 280,
|
||||
albumDescMaxLength: 4000
|
||||
}
|
||||
|
||||
page.preparePage = () => {
|
||||
@ -270,8 +273,8 @@ page.domClick = event => {
|
||||
return page.deleteUpload(id)
|
||||
case 'bulk-delete-uploads':
|
||||
return page.bulkDeleteUploads()
|
||||
case 'display-thumbnail':
|
||||
return page.displayThumbnail(id)
|
||||
case 'display-preview':
|
||||
return page.displayPreview(id)
|
||||
case 'submit-album':
|
||||
return page.submitAlbum(element)
|
||||
case 'edit-album':
|
||||
@ -495,11 +498,21 @@ page.getUploads = (params = {}) => {
|
||||
if (files[i].thumb)
|
||||
files[i].thumb = `${basedomain}/${files[i].thumb}`
|
||||
|
||||
// Determine types
|
||||
files[i].type = 'other'
|
||||
const exec = /.[\w]+(\?|$)/.exec(files[i].file)
|
||||
const extname = exec && exec[0] ? exec[0].toLowerCase() : null
|
||||
if (page.imageExts.includes(extname))
|
||||
files[i].type = 'picture'
|
||||
else if (page.videoExts.includes(extname))
|
||||
files[i].type = 'video'
|
||||
|
||||
// Cache bare minimum data for thumbnails viewer
|
||||
page.cache.uploads[files[i].id] = {
|
||||
name: files[i].name,
|
||||
thumb: files[i].thumb,
|
||||
original: files[i].file
|
||||
original: files[i].file,
|
||||
type: files[i].type
|
||||
}
|
||||
|
||||
// Prettify
|
||||
@ -542,7 +555,7 @@ page.getUploads = (params = {}) => {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const upload = files[i]
|
||||
const div = document.createElement('div')
|
||||
div.className = 'image-container column is-narrow is-relative'
|
||||
div.className = 'image-container column'
|
||||
div.dataset.id = upload.id
|
||||
|
||||
if (upload.thumb !== undefined)
|
||||
@ -554,9 +567,9 @@ page.getUploads = (params = {}) => {
|
||||
<input type="checkbox" class="checkbox" title="Select" data-index="${i}" data-action="select"${upload.selected ? ' checked' : ''}>
|
||||
<div class="controls">
|
||||
${upload.thumb ? `
|
||||
<a class="button is-small is-primary" title="View thumbnail" data-action="display-thumbnail">
|
||||
<a class="button is-small is-primary" title="Display preview" data-action="display-preview">
|
||||
<span class="icon">
|
||||
<i class="icon-picture"></i>
|
||||
<i class="${upload.type !== 'other' ? `icon-${upload.type}` : 'icon-doc-inv'}"></i>
|
||||
</span>
|
||||
</a>` : ''}
|
||||
<a class="button is-small is-info clipboard-js" title="Copy link to clipboard" data-clipboard-text="${upload.file}">
|
||||
@ -576,7 +589,7 @@ page.getUploads = (params = {}) => {
|
||||
</a>
|
||||
</div>
|
||||
<div class="details">
|
||||
<p><span class="name" title="${upload.file}">${upload.name}</span></p>
|
||||
<p><span class="name">${upload.name}</span></p>
|
||||
<p>${upload.appendix ? `<span>${upload.appendix}</span> – ` : ''}${upload.prettyBytes}</p>
|
||||
${hasExpiryDateColumn && upload.prettyExpiryDate ? `
|
||||
<p class="expirydate">EXP: ${upload.prettyExpiryDate}</p>` : ''}
|
||||
@ -629,9 +642,9 @@ page.getUploads = (params = {}) => {
|
||||
<td>${upload.prettyDate}</td>
|
||||
${hasExpiryDateColumn ? `<td>${upload.prettyExpiryDate || '-'}</td>` : ''}
|
||||
<td class="controls has-text-right">
|
||||
<a class="button is-small is-primary" title="${upload.thumb ? 'View thumbnail' : 'File doesn\'t have thumbnail'}" data-action="display-thumbnail"${upload.thumb ? '' : ' disabled'}>
|
||||
<a class="button is-small is-primary" title="${upload.thumb ? 'Display preview' : 'File can\'t be previewed'}" data-action="display-preview"${upload.thumb ? '' : ' disabled'}>
|
||||
<span class="icon">
|
||||
<i class="icon-picture"></i>
|
||||
<i class="${upload.type !== 'other' ? `icon-${upload.type}` : 'icon-doc-inv'}"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="button is-small is-info clipboard-js" title="Copy link to clipboard" data-clipboard-text="${upload.file}">
|
||||
@ -688,7 +701,7 @@ page.setUploadsView = (view, element) => {
|
||||
}, page.views[page.currentView]))
|
||||
}
|
||||
|
||||
page.displayThumbnail = id => {
|
||||
page.displayPreview = id => {
|
||||
const file = page.cache.uploads[id]
|
||||
if (!file.thumb) return
|
||||
|
||||
@ -1254,13 +1267,15 @@ page.getAlbums = (params = {}) => {
|
||||
<form class="prevent-default">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input id="albumName" class="input" type="text" placeholder="Name">
|
||||
<input id="albumName" class="input" type="text" placeholder="Name" maxlength="${page.albumTitleMaxLength}">
|
||||
</div>
|
||||
<p class="help">Max length is ${page.albumTitleMaxLength} characters.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea id="albumDescription" class="textarea" placeholder="Description" rows="1"></textarea>
|
||||
<textarea id="albumDescription" class="textarea" placeholder="Description" rows="1" maxlength="${page.albumDescMaxLength}"></textarea>
|
||||
</div>
|
||||
<p class="help">Max length is ${page.albumDescMaxLength} characters.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
@ -1360,13 +1375,15 @@ page.editAlbum = id => {
|
||||
div.innerHTML = `
|
||||
<div class="field">
|
||||
<div class="controls">
|
||||
<input id="swalName" class="input" type="text" placeholder="Name" value="${album.name || ''}">
|
||||
<input id="swalName" class="input" type="text" placeholder="Name" maxlength="${page.albumTitleMaxLength}" value="${(album.name || '').substring(0, page.albumTitleMaxLength)}">
|
||||
</div>
|
||||
<p class="help">Max length is ${page.albumTitleMaxLength} characters.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea id="swalDescription" class="textarea" placeholder="Description" rows="2">${album.description || ''}</textarea>
|
||||
<textarea id="swalDescription" class="textarea" placeholder="Description" rows="2" maxlength="${page.albumDescMaxLength}">${(album.description || '').substring(0, page.albumDescMaxLength)}</textarea>
|
||||
</div>
|
||||
<p class="help">Max length is ${page.albumDescMaxLength} characters.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
@ -1488,8 +1505,8 @@ page.deleteAlbum = id => {
|
||||
page.submitAlbum = element => {
|
||||
page.updateTrigger(element, 'loading')
|
||||
axios.post('api/albums', {
|
||||
name: document.querySelector('#albumName').value,
|
||||
description: document.querySelector('#albumDescription').value
|
||||
name: document.querySelector('#albumName').value.trim(),
|
||||
description: document.querySelector('#albumDescription').value.trim()
|
||||
}).then(response => {
|
||||
if (!response) return
|
||||
|
||||
|
@ -5,6 +5,7 @@ const lsKeys = {
|
||||
chunkSize: 'chunkSize',
|
||||
parallelUploads: 'parallelUploads',
|
||||
uploadsHistoryOrder: 'uploadsHistoryOrder',
|
||||
previewImages: 'previewImages',
|
||||
fileLength: 'fileLength',
|
||||
uploadAge: 'uploadAge'
|
||||
}
|
||||
@ -25,7 +26,7 @@ const page = {
|
||||
album: null,
|
||||
|
||||
parallelUploads: null,
|
||||
uploadsHistoryOrder: null,
|
||||
previewImages: null,
|
||||
fileLength: null,
|
||||
uploadAge: null,
|
||||
|
||||
@ -42,7 +43,13 @@ const page = {
|
||||
clipboardJS: null,
|
||||
lazyLoad: null,
|
||||
|
||||
imageExtensions: ['.webp', '.jpg', '.jpeg', '.bmp', '.gif', '.png', '.svg']
|
||||
// Include BMP for uploads preview only, cause the real images will be used
|
||||
// Sharp isn't capable of making their thumbnails for dashboard and album public pages
|
||||
imageExts: ['.webp', '.jpg', '.jpeg', '.bmp', '.gif', '.png', '.tiff', '.tif', '.svg'],
|
||||
videoExts: ['.webm', '.mp4', '.wmv', '.avi', '.mov', '.mkv'],
|
||||
|
||||
albumTitleMaxLength: 280,
|
||||
albumDescMaxLength: 4000
|
||||
}
|
||||
|
||||
// Error handler for all API requests on init
|
||||
@ -471,25 +478,34 @@ page.updateTemplate = (file, response) => {
|
||||
clipboard.parentElement.classList.remove('is-hidden')
|
||||
|
||||
const exec = /.[\w]+(\?|$)/.exec(response.url)
|
||||
if (exec && exec[0] && page.imageExtensions.includes(exec[0].toLowerCase())) {
|
||||
const img = file.previewElement.querySelector('img')
|
||||
img.setAttribute('alt', response.name || '')
|
||||
img.dataset.src = response.url
|
||||
img.classList.remove('is-hidden')
|
||||
img.onerror = event => {
|
||||
// Hide image elements that fail to load
|
||||
// Consequently include WEBP in browsers that do not have WEBP support (e.i. IE)
|
||||
event.currentTarget.classList.add('is-hidden')
|
||||
const extname = exec && exec[0]
|
||||
? exec[0].toLowerCase()
|
||||
: null
|
||||
|
||||
if (page.imageExts.includes(extname))
|
||||
if (page.previewImages) {
|
||||
const img = file.previewElement.querySelector('img')
|
||||
img.setAttribute('alt', response.name || '')
|
||||
img.dataset.src = response.url
|
||||
img.classList.remove('is-hidden')
|
||||
img.onerror = event => {
|
||||
// Hide image elements that fail to load
|
||||
// Consequently include WEBP in browsers that do not have WEBP support (e.i. IE)
|
||||
event.currentTarget.classList.add('is-hidden')
|
||||
page.updateTemplateIcon(file.previewElement, 'icon-picture')
|
||||
}
|
||||
page.lazyLoad.update(file.previewElement.querySelectorAll('img'))
|
||||
} else {
|
||||
page.updateTemplateIcon(file.previewElement, 'icon-picture')
|
||||
}
|
||||
page.lazyLoad.update(file.previewElement.querySelectorAll('img'))
|
||||
} else {
|
||||
else if (page.videoExts.includes(extname))
|
||||
page.updateTemplateIcon(file.previewElement, 'icon-video')
|
||||
else
|
||||
page.updateTemplateIcon(file.previewElement, 'icon-doc-inv')
|
||||
}
|
||||
|
||||
if (response.expirydate) {
|
||||
const expiryDate = file.previewElement.querySelector('.expiry-date')
|
||||
expiryDate.innerHTML = `Expiry date: ${page.getPrettyDate(new Date(response.expirydate * 1000))}`
|
||||
expiryDate.innerHTML = `EXP: ${page.getPrettyDate(new Date(response.expirydate * 1000))}`
|
||||
expiryDate.classList.remove('is-hidden')
|
||||
}
|
||||
}
|
||||
@ -499,13 +515,15 @@ page.createAlbum = () => {
|
||||
div.innerHTML = `
|
||||
<div class="field">
|
||||
<div class="controls">
|
||||
<input id="swalName" class="input" type="text" placeholder="Name">
|
||||
<input id="swalName" class="input" type="text" placeholder="Name" maxlength="${page.albumTitleMaxLength}">
|
||||
</div>
|
||||
<p class="help">Max length is ${page.albumTitleMaxLength} characters.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea id="swalDescription" class="textarea" placeholder="Description" rows="2"></textarea>
|
||||
<textarea id="swalDescription" class="textarea" placeholder="Description" rows="2" maxlength="${page.albumDescMaxLength}"></textarea>
|
||||
</div>
|
||||
<p class="help">Max length is ${page.albumDescMaxLength} characters.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
@ -665,11 +683,13 @@ page.prepareUploadConfig = () => {
|
||||
uploadFields[i].classList.add('is-reversed')
|
||||
}
|
||||
|
||||
page.previewImages = localStorage[lsKeys.previewImages] !== '0'
|
||||
|
||||
document.querySelector('#saveConfig').addEventListener('click', () => {
|
||||
if (!form.checkValidity())
|
||||
return
|
||||
|
||||
const prefKeys = ['siBytes', 'uploadsHistoryOrder', 'uploadAge']
|
||||
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]])
|
||||
|
15
src/libs/fontello/fontello.css
vendored
15
src/libs/fontello/fontello.css
vendored
@ -1,12 +1,12 @@
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('fontello.eot?fFS2CGH95j');
|
||||
src: url('fontello.eot?iDzQ0dov5j');
|
||||
src:
|
||||
url('fontello.eot?fFS2CGH95j#iefix') format('embedded-opentype'),
|
||||
url('fontello.woff2?fFS2CGH95j') format('woff2'),
|
||||
url('fontello.woff?fFS2CGH95j') format('woff'),
|
||||
url('fontello.ttf?fFS2CGH95j') format('truetype'),
|
||||
url('fontello.svg?fFS2CGH95j#fontello') format('svg');
|
||||
url('fontello.eot?iDzQ0dov5j#iefix') format('embedded-opentype'),
|
||||
url('fontello.woff2?iDzQ0dov5j') format('woff2'),
|
||||
url('fontello.woff?iDzQ0dov5j') format('woff'),
|
||||
url('fontello.ttf?iDzQ0dov5j') format('truetype'),
|
||||
url('fontello.svg?iDzQ0dov5j#fontello') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal
|
||||
}
|
||||
@ -17,7 +17,7 @@
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('fontello.svg?fFS2CGH95j#fontello') format('svg');
|
||||
src: url('fontello.svg?iDzQ0dov5j#fontello') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -73,6 +73,7 @@
|
||||
.icon-login::before { content: '\e809' } /* '' */
|
||||
.icon-home::before { content: '\e80a' } /* '' */
|
||||
.icon-gauge::before { content: '\e80b' } /* '' */
|
||||
.icon-video:before { content: '\e80c'; } /* '' */
|
||||
.icon-help-circled::before { content: '\e80d' } /* '' */
|
||||
.icon-github-circled::before { content: '\e80e' } /* '' */
|
||||
.icon-pencil::before { content: '\e80f' } /* '' */
|
||||
|
2
todo.md
2
todo.md
@ -2,7 +2,7 @@
|
||||
|
||||
Normal priority:
|
||||
|
||||
* [ ] Improve performance of album public pages, and maybe paginate them.
|
||||
* [x] Improve performance of album public pages, ~~and maybe paginate them~~.
|
||||
* [x] Use [native lazy-load tag](https://web.dev/native-lazy-loading) on nojs album pages.
|
||||
* [ ] Use incremental version numbering instead of randomized strings.
|
||||
* [ ] Use versioning in APIs, somehow.
|
||||
|
@ -1,5 +1,4 @@
|
||||
{% set name = "safe.fiery.me" %}
|
||||
{% set root = "https://safe.fiery.me" %}
|
||||
{% set motto = "A small safe worth protecting." %}
|
||||
{% set description = "A pomf-like file uploading service that doesn't suck." %}
|
||||
{% set keywords = "upload,lolisafe,file,images,hosting,bobby,fiery" %}
|
||||
@ -16,9 +15,9 @@
|
||||
v3: CSS and JS files (libs such as bulma, lazyload, etc).
|
||||
v4: Renders in /public/render/* directories (to be used by render.js).
|
||||
#}
|
||||
{% set v1 = "GqfmYYUziT" %}
|
||||
{% set v1 = "iDzQ0dov5j" %}
|
||||
{% set v2 = "hiboQUzAzp" %}
|
||||
{% set v3 = "GqfmYYUziT" %}
|
||||
{% set v3 = "iDzQ0dov5j" %}
|
||||
{% set v4 = "S3TAWpPeFS" %}
|
||||
|
||||
{#
|
||||
|
@ -1,4 +1,8 @@
|
||||
{% import '_globals.njk' as globals %}
|
||||
|
||||
{# Set root domain here to inherit values from config file #}
|
||||
{% set root = config.homeDomain or config.domain %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@ -8,7 +12,11 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
||||
<title>{{ title | default(globals.name + ' – ' + globals.motto) | safe }}</title>
|
||||
{% if title -%}
|
||||
<title>{{ title + ' | ' + globals.name }}</title>
|
||||
{%- else -%}
|
||||
<title>{{ globals.name + ' – ' + globals.motto }}</title>
|
||||
{%- endif %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<!-- Stylesheets -->
|
||||
@ -18,36 +26,36 @@
|
||||
|
||||
{% block opengraph %}
|
||||
<!-- Open Graph tags -->
|
||||
<meta property="og:url" content="{{ globals.root }}" />
|
||||
<meta property="og:url" content="{{ root }}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="{{ globals.name }} – {{ globals.motto }}" />
|
||||
<meta property="og:title" content="{{ globals.name }} – {{ globals.motto }}" />
|
||||
<meta property="og:description" content="{{ globals.description }}" />
|
||||
<meta property="og:image" content="{{ globals.root }}/icons/600px.png?v={{ globals.v2 }}" />
|
||||
<meta property="og:image" content="{{ root }}/icons/600px.png?v={{ globals.v2 }}" />
|
||||
<meta property="og:image:width" content="600" />
|
||||
<meta property="og:image:height" content="600" />
|
||||
<meta property="og:image" content="{{ globals.root }}/images/fb_share.png?v={{ globals.v2 }}" />
|
||||
<meta property="og:image" content="{{ root }}/images/fb_share.png?v={{ globals.v2 }}" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
|
||||
<!-- Twitter Card tags -->
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="{{ globals.name }} – {{ globals.motto }}">
|
||||
<meta name="twitter:title" content="{{ globals.name }} – {{ globals.motto }}">
|
||||
<meta name="twitter:description" content="{{ globals.description }}">
|
||||
<meta name="twitter:image" content="{{ globals.root }}/icons/600px.png?v={{ globals.v2 }}">
|
||||
<meta name="twitter:image" content="{{ root }}/icons/600px.png?v={{ globals.v2 }}">
|
||||
{% endblock %}
|
||||
|
||||
<!-- Icons, configs, etcetera -->
|
||||
<link rel="icon" href="{{ globals.root }}/icons/32pxr.png?v={{ globals.v2 }}" sizes="32x32">
|
||||
<link rel="icon" href="{{ globals.root }}/icons/96pxr.png?v={{ globals.v2 }}" sizes="96x96">
|
||||
<link rel="apple-touch-icon" href="{{ globals.root }}/icons/120px.png?v={{ globals.v2 }}" sizes="120x120">
|
||||
<link rel="apple-touch-icon" href="{{ globals.root }}/icons/152px.png?v={{ globals.v2 }}" sizes="152x152">
|
||||
<link rel="apple-touch-icon" href="{{ globals.root }}/icons/167px.png?v={{ globals.v2 }}" sizes="167x167">
|
||||
<link rel="apple-touch-icon" href="{{ globals.root }}/icons/180px.png?v={{ globals.v2 }}" sizes="180x180">
|
||||
<link rel="manifest" href="{{ globals.root }}/icons/manifest.json?v={{ globals.v2 }}">
|
||||
<link rel="icon" href="{{ root }}/icons/32pxr.png?v={{ globals.v2 }}" sizes="32x32">
|
||||
<link rel="icon" href="{{ root }}/icons/96pxr.png?v={{ globals.v2 }}" sizes="96x96">
|
||||
<link rel="apple-touch-icon" href="{{ root }}/icons/120px.png?v={{ globals.v2 }}" sizes="120x120">
|
||||
<link rel="apple-touch-icon" href="{{ root }}/icons/152px.png?v={{ globals.v2 }}" sizes="152x152">
|
||||
<link rel="apple-touch-icon" href="{{ root }}/icons/167px.png?v={{ globals.v2 }}" sizes="167x167">
|
||||
<link rel="apple-touch-icon" href="{{ root }}/icons/180px.png?v={{ globals.v2 }}" sizes="180x180">
|
||||
<link rel="manifest" href="{{ root }}/icons/manifest.json?v={{ globals.v2 }}">
|
||||
<meta name="apple-mobile-web-app-title" content="{{ globals.name }}">
|
||||
<meta name="application-name" content="{{ globals.name }}">
|
||||
<meta name="msapplication-config" content="{{ globals.root }}/icons/browserconfig.xml?v={{ globals.v2 }}">
|
||||
<meta name="msapplication-config" content="{{ root }}/icons/browserconfig.xml?v={{ globals.v2 }}">
|
||||
<meta name="theme-color" content="#232629">
|
||||
{% block endmeta %}{% endblock %}
|
||||
</head>
|
||||
|
@ -1,5 +1,10 @@
|
||||
{% set title = album.name %}
|
||||
{% extends "_layout.njk" %}
|
||||
|
||||
{% set fileRoot = config.domain %}
|
||||
{% set generateZips = config.uploads.generateZips %}
|
||||
{% set usingCdn = config.cloudflare and config.cloudflare.purgeCache %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<!-- Stylesheets -->
|
||||
<link rel="stylesheet" href="../libs/bulma/bulma.min.css?v={{ globals.v3 }}">
|
||||
@ -20,17 +25,17 @@
|
||||
{% block opengraph %}
|
||||
<!-- Open Graph tags -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="{{ title | safe }} – {{ count }} files" />
|
||||
<meta property="og:url" content="{{ url }}" />
|
||||
<meta property="og:description" content="{{ description | safe }}" />
|
||||
<meta property="og:image" content="{{ thumb }}" />
|
||||
<meta property="og:title" content="{{ album.name | safe }} – {{ files.length }} files" />
|
||||
<meta property="og:url" content="{{ root }}/{{ album.url }}" />
|
||||
<meta property="og:description" content="{{ album.description }}" />
|
||||
<meta property="og:image" content="{{ fileRoot }}/{{ album.thumb }}" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
|
||||
<!-- Twitter Card tags -->
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="{{ title | safe }} – {{ count }} files">
|
||||
<meta name="twitter:description" content="{{ description | safe }}">
|
||||
<meta name="twitter:image" content="{{ thumb }}">
|
||||
<meta name="twitter:title" content="{{ album.name | safe }} – {{ files.length }} files">
|
||||
<meta name="twitter:description" content="{{ album.description }}">
|
||||
<meta name="twitter:image" content="{{ fileRoot }}/{{ album.thumb }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@ -41,21 +46,27 @@
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 id="title" class="title">
|
||||
{{ title | safe }}
|
||||
{{ album.name | safe }}
|
||||
</h1>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
<h1 id="count" class="subtitle">
|
||||
{{ count }} files (<span class="file-size">{{ totalSize }} B</span>)
|
||||
{{ files.length }} files (<span class="file-size">{{ album.totalSize }} B</span>)
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if generateZips and files.length -%}
|
||||
{% if generateZips -%}
|
||||
<div class="level-right">
|
||||
<p class="level-item">
|
||||
{% if downloadLink -%}
|
||||
<a class="button is-primary is-outlined" title="Be aware that album archive may be cached by CDN" href="{{ downloadLink }}">Download album</a>
|
||||
{% if not files.length -%}
|
||||
<a class="button is-primary is-outlined" title="There are no files in the album" disabled>Download album</a>
|
||||
{%- elif album.downloadLink -%}
|
||||
{%- if usingCDN -%}
|
||||
<a class="button is-primary is-outlined" title="Be aware that album archive may be cached by CDN" href="../{{ album.downloadLink }}">Download album</a>
|
||||
{%- else -%}
|
||||
<a class="button is-primary is-outlined" href="../{{ album.downloadLink }}">Download album</a>
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
<a class="button is-primary is-outlined" title="The album's owner has chosen to disable download" disabled>Download disabled</a>
|
||||
{%- endif %}
|
||||
@ -64,9 +75,9 @@
|
||||
{%- endif %}
|
||||
</nav>
|
||||
|
||||
{% if description -%}
|
||||
{% if album.description -%}
|
||||
<h2 class="subtitle description">
|
||||
{{ description | safe }}
|
||||
{{ album.description | safe }}
|
||||
</h2>
|
||||
{%- endif %}
|
||||
<hr>
|
||||
@ -75,7 +86,7 @@
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
<p>You are viewing No-JS version of this album, so file size will be displayed in bytes.</p>
|
||||
<p>Please <a href="{{ url }}">click here</a> if you want to view its regular version.</p>
|
||||
<p>Please <a href="../{{ album.url }}">click here</a> if you want to view its regular version.</p>
|
||||
</div>
|
||||
</article>
|
||||
{%- endif %}
|
||||
@ -83,20 +94,20 @@
|
||||
{% if files.length -%}
|
||||
<div id="table" class="columns is-multiline is-mobile is-centered has-text-centered">
|
||||
{% for file in files %}
|
||||
<div class="image-container column is-narrow is-relative">
|
||||
<a class="image" href="{{ file.file }}" target="_blank" rel="noopener">
|
||||
<div class="image-container column">
|
||||
<a class="image" href="{{ fileRoot }}/{{ file.name }}" target="_blank" rel="noopener">
|
||||
{% if file.thumb -%}
|
||||
{% if nojs -%}
|
||||
<img alt="{{ file.name }}" src="{{ file.thumb }}" width="200" height="200" loading="lazy">
|
||||
<img alt="{{ file.name }}" src="{{ fileRoot }}/{{ file.thumb }}" width="200" height="200" loading="lazy">
|
||||
{%- else -%}
|
||||
<img alt="{{ file.name }}" data-src="{{ file.thumb }}">
|
||||
<img alt="{{ file.name }}" data-src="{{ fileRoot }}/{{ file.thumb }}">
|
||||
{%- endif %}
|
||||
{%- else -%}
|
||||
<h1 class="title">{{ file.extname | default('N/A') }}</h1>
|
||||
{%- endif %}
|
||||
</a>
|
||||
<div class="details">
|
||||
<p><span class="name" title="{{ file.file }}">{{ file.name }}</span></p>
|
||||
<p><span class="name">{{ file.name }}</span></p>
|
||||
<p class="file-size">{{ file.size }} B</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -119,7 +130,7 @@
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<p>You have JavaScript disabled, but this page requires JavaScript to function.</p>
|
||||
<p>Please <a href="{{ url }}?nojs">click here</a> if you want to view its No-JS version.</p>
|
||||
<p>Please <a href="../{{ album.url }}?nojs">click here</a> if you want to view its No-JS version.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -1,3 +1,4 @@
|
||||
{% set title = "Auth" %}
|
||||
{% extends "_layout.njk" %}
|
||||
|
||||
{% block stylesheets %}
|
||||
@ -30,12 +31,12 @@
|
||||
<form id="authForm">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input id="user" name="user" class="input" type="text" placeholder="Your username">
|
||||
<input id="user" name="user" class="input" type="text" placeholder="Your username" minlength="4" maxlength="32">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input id="pass" name="pass" class="input" type="password" placeholder="Your password">
|
||||
<input id="pass" name="pass" class="input" type="password" placeholder="Your password" minlength="6" maxlength="64">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-grouped is-grouped-right">
|
||||
|
@ -1,3 +1,4 @@
|
||||
{% set title = "Dashboard" %}
|
||||
{% extends "_layout.njk" %}
|
||||
|
||||
{% block stylesheets %}
|
||||
|
@ -1,5 +1,11 @@
|
||||
{% set title = "FAQ" %}
|
||||
{% extends "_layout.njk" %}
|
||||
|
||||
{% set noJsMaxSize = config.cloudflare.noJsMaxSize | int %}
|
||||
{% set chunkSize = config.uploads.chunkSize | int %}
|
||||
{% set extensionsFilterMode = config.extensionsFilterMode %}
|
||||
{% set extensionsFilter = config.extensionsFilter %}
|
||||
|
||||
{% macro extensions(obj) %}
|
||||
{% set space = joiner(' ') %}
|
||||
{% for id, val in obj -%}
|
||||
@ -114,7 +120,7 @@
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
{% if extensionsFilter.length -%}
|
||||
{%- if whitelist -%}
|
||||
{%- if extensionsFilterMode === 'whitelist' -%}
|
||||
We only support the following extensions:
|
||||
{%- else -%}
|
||||
We support any file extensions, except the following:
|
||||
|
@ -1,5 +1,12 @@
|
||||
{% extends "_layout.njk" %}
|
||||
|
||||
{% set maxSizeInt = config.maxSize | int %}
|
||||
{% set urlMaxSizeInt = config.urlMaxSize | int %}
|
||||
{% set urlDisclaimerMessage = config.uploads.urlDisclaimerMessage %}
|
||||
{% set urlExtensionsFilterMode = config.uploads.urlExtensionsFilterMode %}
|
||||
{% set urlExtensionsFilter = config.uploads.urlExtensionsFilter %}
|
||||
{% set temporaryUploadAges = config.uploads.temporaryUploadAges %}
|
||||
|
||||
{% block endmeta %}
|
||||
{{ super() }}
|
||||
{% if globals.google_site_verification %}
|
||||
@ -39,7 +46,7 @@
|
||||
<h2 class="subtitle">{{ globals.home_subtitle | safe }}</h2>
|
||||
|
||||
<h3 id="maxSize" class="subtitle">
|
||||
Maximum upload size per file is <span>{{ maxSize }} MB</span>
|
||||
Maximum upload size per file is <span>{{ maxSizeInt }} MB</span>
|
||||
</h3>
|
||||
|
||||
<div class="columns is-gapless">
|
||||
@ -95,8 +102,8 @@
|
||||
<textarea id="urls" class="textarea" rows="2"></textarea>
|
||||
</div>
|
||||
<p class="help">
|
||||
{% if urlMaxSize !== maxSize -%}
|
||||
Maximum file size per URL is <span id="urlMaxSize">{{ urlMaxSize }} MB</span>.
|
||||
{% if urlMaxSizeInt !== maxSizeInt -%}
|
||||
Maximum file size per URL is <span id="urlMaxSize">{{ urlMaxSizeInt }} MB</span>.
|
||||
{%- endif %}
|
||||
|
||||
{% if urlExtensionsFilter.length and (urlExtensionsFilterMode === 'blacklist') -%}
|
||||
@ -144,7 +151,7 @@
|
||||
</div>
|
||||
<p class="help"></p>
|
||||
</div>
|
||||
{%- if temporaryUploadAges %}
|
||||
{%- if temporaryUploadAges and temporaryUploadAges.length %}
|
||||
<div id="uploadAgeDiv" class="field is-hidden">
|
||||
<label class="label">Upload age</label>
|
||||
<div class="control">
|
||||
@ -179,7 +186,19 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help">Newer files on top only works in <a href="https://caniuse.com/#feat=mdn-css_properties_flex-direction" target="_blank" rel="noopener">these browsers</a>.</p>
|
||||
<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">
|
||||
@ -205,7 +224,7 @@
|
||||
<div class="field">
|
||||
<i class="icon is-hidden"></i>
|
||||
<img class="is-unselectable is-hidden">
|
||||
<p class="name is-unselectable"></p>
|
||||
<p class="name"></p>
|
||||
<progress class="progress is-small is-danger" max="100" value="0"></progress>
|
||||
<p class="error"></p>
|
||||
<p class="link">
|
||||
|
@ -1,5 +1,17 @@
|
||||
{% set title = "No-JS uploader" %}
|
||||
{% extends "_layout.njk" %}
|
||||
|
||||
{% set private = config.private %}
|
||||
{% set disabledMessage -%}
|
||||
{%- if config.enableUserAccounts -%}
|
||||
Anonymous upload is disabled.
|
||||
{%- else -%}
|
||||
Running in private mode.
|
||||
{%- endif %}
|
||||
{%- endset %}
|
||||
{% set maxSizeInt = config.maxSize | int %}
|
||||
{% set noJsMaxSizeInt = config.cloudflare.noJsMaxSize | int %}
|
||||
|
||||
{% block stylesheets %}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" href="css/home.css?v={{ globals.v1 }}">
|
||||
@ -17,15 +29,15 @@
|
||||
<h2 class="subtitle">{{ globals.home_subtitle | safe }}</h2>
|
||||
|
||||
<h3 class="subtitle" id="maxSize">
|
||||
Maximum total size per upload attempt is {{ renderOptions.maxFileSize }} MB
|
||||
Maximum total size per upload attempt is {{ noJsMaxSizeInt or maxSizeInt }} MB
|
||||
</h3>
|
||||
|
||||
<div class="columns is-gapless">
|
||||
<div class="column is-hidden-mobile"></div>
|
||||
<div class="column">
|
||||
{% if renderOptions.uploadDisabled -%}
|
||||
{% if config.private -%}
|
||||
<a class="button is-danger is-flex" href="auth">
|
||||
{{ renderOptions.uploadDisabled }}
|
||||
{{ disabledMessage }}
|
||||
</a>
|
||||
{%- else -%}
|
||||
<form id="form" class="field" action="" method="post" enctype="multipart/form-data">
|
||||
|
52
yarn.lock
52
yarn.lock
@ -915,9 +915,9 @@ caniuse-api@^3.0.0:
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-db@^1.0.30000977:
|
||||
version "1.0.30000994"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000994.tgz#891d94864a8b4a49cae58a9b4a93c5b538667794"
|
||||
integrity sha512-7KjfAAhO0qJOs92z8lMWkcRA2ig7Ewv5SQSAy+dik8MFQCDSua+j4RbPFnGrXuOSFe/3RhmGr+68DxKZrbJQGg==
|
||||
version "1.0.30000995"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000995.tgz#8e0557e822dab88fbbb21358d3ed395cb8efc21d"
|
||||
integrity sha512-25ew/vPIVU0g/OjeZay2IfcljWAmNVy1TSmeoozFrJzEOqnka0ZSusJFS+4iGZKVIJ4RHOZB4NyilpwNcsh8tA==
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989:
|
||||
version "1.0.30000989"
|
||||
@ -1808,9 +1808,9 @@ ee-first@1.1.1:
|
||||
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||
|
||||
electron-to-chromium@^1.3.247:
|
||||
version "1.3.258"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.258.tgz#829b03be37424099b91aefb6815e8801bf30b509"
|
||||
integrity sha512-rkPYrgFU7k/8ngjHYvzOZ44OQQ1GeIRIQnhGv00RkSlQXEnJKsGonQppbEEWHuuxZegpMao+WZmYraWQJQJMMg==
|
||||
version "1.3.260"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.260.tgz#ffd686b4810bab0e1a428e7af5f08c21fe7c1fa2"
|
||||
integrity sha512-wGt+OivF1C1MPwaSv3LJ96ebNbLAWlx3HndivDDWqwIVSQxmhL17Y/YmwUdEMtS/bPyommELt47Dct0/VZNQBQ==
|
||||
|
||||
emoji-regex@^7.0.1:
|
||||
version "7.0.3"
|
||||
@ -2518,11 +2518,11 @@ fs-constants@^1.0.0:
|
||||
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||
|
||||
fs-minipass@^1.2.5:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
|
||||
integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
|
||||
integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
|
||||
dependencies:
|
||||
minipass "^2.2.1"
|
||||
minipass "^2.6.0"
|
||||
|
||||
fs-mkdirp-stream@^1.0.0:
|
||||
version "1.0.0"
|
||||
@ -4218,10 +4218,10 @@ minimist@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
minipass@^2.2.1, minipass@^2.3.5:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.5.1.tgz#cf435a9bf9408796ca3a3525a8b851464279c9b8"
|
||||
integrity sha512-dmpSnLJtNQioZFI5HfQ55Ad0DzzsMAb+HfokwRTNXwEQjepbTkl5mtIlSVxGIkOkxlpX7wIn5ET/oAd9fZ/Y/Q==
|
||||
minipass@^2.2.1, minipass@^2.3.5, minipass@^2.6.0:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.6.2.tgz#c3075a22680b3b1479bae5915904cb1eba50f5c0"
|
||||
integrity sha512-38Jwdc8AttUDaQAIRX8Iaw3QoCDWjAwKMGeGDF9JUi9QCPMjH5qAQg/hdO8o1nC7Nmh1/CqzMg5FQPEKuKwznQ==
|
||||
dependencies:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.0"
|
||||
@ -4398,9 +4398,9 @@ node-pre-gyp@^0.11.0:
|
||||
tar "^4"
|
||||
|
||||
node-releases@^1.1.29:
|
||||
version "1.1.30"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.30.tgz#35eebf129c63baeb6d8ddeda3c35b05abfd37f7f"
|
||||
integrity sha512-BHcr1g6NeUH12IL+X3Flvs4IOnl1TL0JczUhEZjDE+FXXPQcVCNr8NEPb01zqGxzhTpdyJL5GXemaCW7aw6Khw==
|
||||
version "1.1.32"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.32.tgz#485b35c1bf9b4d8baa105d782f8ca731e518276e"
|
||||
integrity sha512-VhVknkitq8dqtWoluagsGPn3dxTvN9fwgR59fV3D7sLBHe0JfDramsMI8n8mY//ccq/Kkrf8ZRHRpsyVZ3qw1A==
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
@ -6681,17 +6681,17 @@ stylehacks@^4.0.0:
|
||||
postcss "^7.0.0"
|
||||
postcss-selector-parser "^3.0.0"
|
||||
|
||||
stylelint-config-recommended@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-2.2.0.tgz#46ab139db4a0e7151fd5f94af155512886c96d3f"
|
||||
integrity sha512-bZ+d4RiNEfmoR74KZtCKmsABdBJr4iXRiCso+6LtMJPw5rd/KnxUWTxht7TbafrTJK1YRjNgnN0iVZaJfc3xJA==
|
||||
stylelint-config-recommended@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-3.0.0.tgz#e0e547434016c5539fe2650afd58049a2fd1d657"
|
||||
integrity sha512-F6yTRuc06xr1h5Qw/ykb2LuFynJ2IxkKfCMf+1xqPffkxh0S09Zc902XCffcsw/XMFq/OzQ1w54fLIDtmRNHnQ==
|
||||
|
||||
stylelint-config-standard@^18.3.0:
|
||||
version "18.3.0"
|
||||
resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-18.3.0.tgz#a2a1b788d2cf876c013feaff8ae276117a1befa7"
|
||||
integrity sha512-Tdc/TFeddjjy64LvjPau9SsfVRexmTFqUhnMBrzz07J4p2dVQtmpncRF/o8yZn8ugA3Ut43E6o1GtjX80TFytw==
|
||||
stylelint-config-standard@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-19.0.0.tgz#66f0cf13f33b8a9e34965881493b38fc1313693a"
|
||||
integrity sha512-VvcODsL1PryzpYteWZo2YaA5vU/pWfjqBpOvmeA8iB2MteZ/ZhI1O4hnrWMidsS4vmEJpKtjdhLdfGJmmZm6Cg==
|
||||
dependencies:
|
||||
stylelint-config-recommended "^2.2.0"
|
||||
stylelint-config-recommended "^3.0.0"
|
||||
|
||||
stylelint@^10.1.0:
|
||||
version "10.1.0"
|
||||
|
Loading…
Reference in New Issue
Block a user