vault backup: 2025-07-16 16:23:44
This commit is contained in:
1 parent
fff34bbbb5
commit
6a8e9ed259
11 files changed
+6969
-10
No files matched your search
+970
@@ -0,0 +1,970 @@
|
||||
'use strict';
|
||||
|
||||
var obsidian = require('obsidian');
|
||||
|
||||
/******************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
|
||||
function __awaiter(thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
}
|
||||
|
||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||
var e = new Error(message);
|
||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||
};
|
||||
|
||||
// 'path' module extracted from Node.js v8.11.1 (only the posix part)
|
||||
|
||||
function assertPath(path) {
|
||||
if (typeof path !== 'string') {
|
||||
throw new TypeError('Path must be a string. Received ' + JSON.stringify(path));
|
||||
}
|
||||
}
|
||||
|
||||
// Resolves . and .. elements in a path with directory names
|
||||
function normalizeStringPosix(path, allowAboveRoot) {
|
||||
var res = '';
|
||||
var lastSegmentLength = 0;
|
||||
var lastSlash = -1;
|
||||
var dots = 0;
|
||||
var code;
|
||||
for (var i = 0; i <= path.length; ++i) {
|
||||
if (i < path.length)
|
||||
code = path.charCodeAt(i);
|
||||
else if (code === 47 /*/*/)
|
||||
break;
|
||||
else
|
||||
code = 47 /*/*/;
|
||||
if (code === 47 /*/*/) {
|
||||
if (lastSlash === i - 1 || dots === 1) ; else if (lastSlash !== i - 1 && dots === 2) {
|
||||
if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) {
|
||||
if (res.length > 2) {
|
||||
var lastSlashIndex = res.lastIndexOf('/');
|
||||
if (lastSlashIndex !== res.length - 1) {
|
||||
if (lastSlashIndex === -1) {
|
||||
res = '';
|
||||
lastSegmentLength = 0;
|
||||
} else {
|
||||
res = res.slice(0, lastSlashIndex);
|
||||
lastSegmentLength = res.length - 1 - res.lastIndexOf('/');
|
||||
}
|
||||
lastSlash = i;
|
||||
dots = 0;
|
||||
continue;
|
||||
}
|
||||
} else if (res.length === 2 || res.length === 1) {
|
||||
res = '';
|
||||
lastSegmentLength = 0;
|
||||
lastSlash = i;
|
||||
dots = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (allowAboveRoot) {
|
||||
if (res.length > 0)
|
||||
res += '/..';
|
||||
else
|
||||
res = '..';
|
||||
lastSegmentLength = 2;
|
||||
}
|
||||
} else {
|
||||
if (res.length > 0)
|
||||
res += '/' + path.slice(lastSlash + 1, i);
|
||||
else
|
||||
res = path.slice(lastSlash + 1, i);
|
||||
lastSegmentLength = i - lastSlash - 1;
|
||||
}
|
||||
lastSlash = i;
|
||||
dots = 0;
|
||||
} else if (code === 46 /*.*/ && dots !== -1) {
|
||||
++dots;
|
||||
} else {
|
||||
dots = -1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function _format(sep, pathObject) {
|
||||
var dir = pathObject.dir || pathObject.root;
|
||||
var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || '');
|
||||
if (!dir) {
|
||||
return base;
|
||||
}
|
||||
if (dir === pathObject.root) {
|
||||
return dir + base;
|
||||
}
|
||||
return dir + sep + base;
|
||||
}
|
||||
|
||||
var posix = {
|
||||
// path.resolve([from ...], to)
|
||||
resolve: function resolve() {
|
||||
var resolvedPath = '';
|
||||
var resolvedAbsolute = false;
|
||||
var cwd;
|
||||
|
||||
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
|
||||
var path;
|
||||
if (i >= 0)
|
||||
path = arguments[i];
|
||||
else {
|
||||
if (cwd === undefined)
|
||||
cwd = process.cwd();
|
||||
path = cwd;
|
||||
}
|
||||
|
||||
assertPath(path);
|
||||
|
||||
// Skip empty entries
|
||||
if (path.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
resolvedPath = path + '/' + resolvedPath;
|
||||
resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/;
|
||||
}
|
||||
|
||||
// At this point the path should be resolved to a full absolute path, but
|
||||
// handle relative paths to be safe (might happen when process.cwd() fails)
|
||||
|
||||
// Normalize the path
|
||||
resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);
|
||||
|
||||
if (resolvedAbsolute) {
|
||||
if (resolvedPath.length > 0)
|
||||
return '/' + resolvedPath;
|
||||
else
|
||||
return '/';
|
||||
} else if (resolvedPath.length > 0) {
|
||||
return resolvedPath;
|
||||
} else {
|
||||
return '.';
|
||||
}
|
||||
},
|
||||
|
||||
normalize: function normalize(path) {
|
||||
assertPath(path);
|
||||
|
||||
if (path.length === 0) return '.';
|
||||
|
||||
var isAbsolute = path.charCodeAt(0) === 47 /*/*/;
|
||||
var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/;
|
||||
|
||||
// Normalize the path
|
||||
path = normalizeStringPosix(path, !isAbsolute);
|
||||
|
||||
if (path.length === 0 && !isAbsolute) path = '.';
|
||||
if (path.length > 0 && trailingSeparator) path += '/';
|
||||
|
||||
if (isAbsolute) return '/' + path;
|
||||
return path;
|
||||
},
|
||||
|
||||
isAbsolute: function isAbsolute(path) {
|
||||
assertPath(path);
|
||||
return path.length > 0 && path.charCodeAt(0) === 47 /*/*/;
|
||||
},
|
||||
|
||||
join: function join() {
|
||||
if (arguments.length === 0)
|
||||
return '.';
|
||||
var joined;
|
||||
for (var i = 0; i < arguments.length; ++i) {
|
||||
var arg = arguments[i];
|
||||
assertPath(arg);
|
||||
if (arg.length > 0) {
|
||||
if (joined === undefined)
|
||||
joined = arg;
|
||||
else
|
||||
joined += '/' + arg;
|
||||
}
|
||||
}
|
||||
if (joined === undefined)
|
||||
return '.';
|
||||
return posix.normalize(joined);
|
||||
},
|
||||
|
||||
relative: function relative(from, to) {
|
||||
assertPath(from);
|
||||
assertPath(to);
|
||||
|
||||
if (from === to) return '';
|
||||
|
||||
from = posix.resolve(from);
|
||||
to = posix.resolve(to);
|
||||
|
||||
if (from === to) return '';
|
||||
|
||||
// Trim any leading backslashes
|
||||
var fromStart = 1;
|
||||
for (; fromStart < from.length; ++fromStart) {
|
||||
if (from.charCodeAt(fromStart) !== 47 /*/*/)
|
||||
break;
|
||||
}
|
||||
var fromEnd = from.length;
|
||||
var fromLen = fromEnd - fromStart;
|
||||
|
||||
// Trim any leading backslashes
|
||||
var toStart = 1;
|
||||
for (; toStart < to.length; ++toStart) {
|
||||
if (to.charCodeAt(toStart) !== 47 /*/*/)
|
||||
break;
|
||||
}
|
||||
var toEnd = to.length;
|
||||
var toLen = toEnd - toStart;
|
||||
|
||||
// Compare paths to find the longest common path from root
|
||||
var length = fromLen < toLen ? fromLen : toLen;
|
||||
var lastCommonSep = -1;
|
||||
var i = 0;
|
||||
for (; i <= length; ++i) {
|
||||
if (i === length) {
|
||||
if (toLen > length) {
|
||||
if (to.charCodeAt(toStart + i) === 47 /*/*/) {
|
||||
// We get here if `from` is the exact base path for `to`.
|
||||
// For example: from='/foo/bar'; to='/foo/bar/baz'
|
||||
return to.slice(toStart + i + 1);
|
||||
} else if (i === 0) {
|
||||
// We get here if `from` is the root
|
||||
// For example: from='/'; to='/foo'
|
||||
return to.slice(toStart + i);
|
||||
}
|
||||
} else if (fromLen > length) {
|
||||
if (from.charCodeAt(fromStart + i) === 47 /*/*/) {
|
||||
// We get here if `to` is the exact base path for `from`.
|
||||
// For example: from='/foo/bar/baz'; to='/foo/bar'
|
||||
lastCommonSep = i;
|
||||
} else if (i === 0) {
|
||||
// We get here if `to` is the root.
|
||||
// For example: from='/foo'; to='/'
|
||||
lastCommonSep = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
var fromCode = from.charCodeAt(fromStart + i);
|
||||
var toCode = to.charCodeAt(toStart + i);
|
||||
if (fromCode !== toCode)
|
||||
break;
|
||||
else if (fromCode === 47 /*/*/)
|
||||
lastCommonSep = i;
|
||||
}
|
||||
|
||||
var out = '';
|
||||
// Generate the relative path based on the path difference between `to`
|
||||
// and `from`
|
||||
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
|
||||
if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) {
|
||||
if (out.length === 0)
|
||||
out += '..';
|
||||
else
|
||||
out += '/..';
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly, append the rest of the destination (`to`) path that comes after
|
||||
// the common path parts
|
||||
if (out.length > 0)
|
||||
return out + to.slice(toStart + lastCommonSep);
|
||||
else {
|
||||
toStart += lastCommonSep;
|
||||
if (to.charCodeAt(toStart) === 47 /*/*/)
|
||||
++toStart;
|
||||
return to.slice(toStart);
|
||||
}
|
||||
},
|
||||
|
||||
_makeLong: function _makeLong(path) {
|
||||
return path;
|
||||
},
|
||||
|
||||
dirname: function dirname(path) {
|
||||
assertPath(path);
|
||||
if (path.length === 0) return '.';
|
||||
var code = path.charCodeAt(0);
|
||||
var hasRoot = code === 47 /*/*/;
|
||||
var end = -1;
|
||||
var matchedSlash = true;
|
||||
for (var i = path.length - 1; i >= 1; --i) {
|
||||
code = path.charCodeAt(i);
|
||||
if (code === 47 /*/*/) {
|
||||
if (!matchedSlash) {
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// We saw the first non-path separator
|
||||
matchedSlash = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (end === -1) return hasRoot ? '/' : '.';
|
||||
if (hasRoot && end === 1) return '//';
|
||||
return path.slice(0, end);
|
||||
},
|
||||
|
||||
basename: function basename(path, ext) {
|
||||
if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string');
|
||||
assertPath(path);
|
||||
|
||||
var start = 0;
|
||||
var end = -1;
|
||||
var matchedSlash = true;
|
||||
var i;
|
||||
|
||||
if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
|
||||
if (ext.length === path.length && ext === path) return '';
|
||||
var extIdx = ext.length - 1;
|
||||
var firstNonSlashEnd = -1;
|
||||
for (i = path.length - 1; i >= 0; --i) {
|
||||
var code = path.charCodeAt(i);
|
||||
if (code === 47 /*/*/) {
|
||||
// If we reached a path separator that was not part of a set of path
|
||||
// separators at the end of the string, stop now
|
||||
if (!matchedSlash) {
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (firstNonSlashEnd === -1) {
|
||||
// We saw the first non-path separator, remember this index in case
|
||||
// we need it if the extension ends up not matching
|
||||
matchedSlash = false;
|
||||
firstNonSlashEnd = i + 1;
|
||||
}
|
||||
if (extIdx >= 0) {
|
||||
// Try to match the explicit extension
|
||||
if (code === ext.charCodeAt(extIdx)) {
|
||||
if (--extIdx === -1) {
|
||||
// We matched the extension, so mark this as the end of our path
|
||||
// component
|
||||
end = i;
|
||||
}
|
||||
} else {
|
||||
// Extension does not match, so our result is the entire path
|
||||
// component
|
||||
extIdx = -1;
|
||||
end = firstNonSlashEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length;
|
||||
return path.slice(start, end);
|
||||
} else {
|
||||
for (i = path.length - 1; i >= 0; --i) {
|
||||
if (path.charCodeAt(i) === 47 /*/*/) {
|
||||
// If we reached a path separator that was not part of a set of path
|
||||
// separators at the end of the string, stop now
|
||||
if (!matchedSlash) {
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
} else if (end === -1) {
|
||||
// We saw the first non-path separator, mark this as the end of our
|
||||
// path component
|
||||
matchedSlash = false;
|
||||
end = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (end === -1) return '';
|
||||
return path.slice(start, end);
|
||||
}
|
||||
},
|
||||
|
||||
extname: function extname(path) {
|
||||
assertPath(path);
|
||||
var startDot = -1;
|
||||
var startPart = 0;
|
||||
var end = -1;
|
||||
var matchedSlash = true;
|
||||
// Track the state of characters (if any) we see before our first dot and
|
||||
// after any path separator we find
|
||||
var preDotState = 0;
|
||||
for (var i = path.length - 1; i >= 0; --i) {
|
||||
var code = path.charCodeAt(i);
|
||||
if (code === 47 /*/*/) {
|
||||
// If we reached a path separator that was not part of a set of path
|
||||
// separators at the end of the string, stop now
|
||||
if (!matchedSlash) {
|
||||
startPart = i + 1;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (end === -1) {
|
||||
// We saw the first non-path separator, mark this as the end of our
|
||||
// extension
|
||||
matchedSlash = false;
|
||||
end = i + 1;
|
||||
}
|
||||
if (code === 46 /*.*/) {
|
||||
// If this is our first dot, mark it as the start of our extension
|
||||
if (startDot === -1)
|
||||
startDot = i;
|
||||
else if (preDotState !== 1)
|
||||
preDotState = 1;
|
||||
} else if (startDot !== -1) {
|
||||
// We saw a non-dot and non-path separator before our dot, so we should
|
||||
// have a good chance at having a non-empty extension
|
||||
preDotState = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (startDot === -1 || end === -1 ||
|
||||
// We saw a non-dot character immediately before the dot
|
||||
preDotState === 0 ||
|
||||
// The (right-most) trimmed path component is exactly '..'
|
||||
preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
|
||||
return '';
|
||||
}
|
||||
return path.slice(startDot, end);
|
||||
},
|
||||
|
||||
format: function format(pathObject) {
|
||||
if (pathObject === null || typeof pathObject !== 'object') {
|
||||
throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject);
|
||||
}
|
||||
return _format('/', pathObject);
|
||||
},
|
||||
|
||||
parse: function parse(path) {
|
||||
assertPath(path);
|
||||
|
||||
var ret = { root: '', dir: '', base: '', ext: '', name: '' };
|
||||
if (path.length === 0) return ret;
|
||||
var code = path.charCodeAt(0);
|
||||
var isAbsolute = code === 47 /*/*/;
|
||||
var start;
|
||||
if (isAbsolute) {
|
||||
ret.root = '/';
|
||||
start = 1;
|
||||
} else {
|
||||
start = 0;
|
||||
}
|
||||
var startDot = -1;
|
||||
var startPart = 0;
|
||||
var end = -1;
|
||||
var matchedSlash = true;
|
||||
var i = path.length - 1;
|
||||
|
||||
// Track the state of characters (if any) we see before our first dot and
|
||||
// after any path separator we find
|
||||
var preDotState = 0;
|
||||
|
||||
// Get non-dir info
|
||||
for (; i >= start; --i) {
|
||||
code = path.charCodeAt(i);
|
||||
if (code === 47 /*/*/) {
|
||||
// If we reached a path separator that was not part of a set of path
|
||||
// separators at the end of the string, stop now
|
||||
if (!matchedSlash) {
|
||||
startPart = i + 1;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (end === -1) {
|
||||
// We saw the first non-path separator, mark this as the end of our
|
||||
// extension
|
||||
matchedSlash = false;
|
||||
end = i + 1;
|
||||
}
|
||||
if (code === 46 /*.*/) {
|
||||
// If this is our first dot, mark it as the start of our extension
|
||||
if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1;
|
||||
} else if (startDot !== -1) {
|
||||
// We saw a non-dot and non-path separator before our dot, so we should
|
||||
// have a good chance at having a non-empty extension
|
||||
preDotState = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (startDot === -1 || end === -1 ||
|
||||
// We saw a non-dot character immediately before the dot
|
||||
preDotState === 0 ||
|
||||
// The (right-most) trimmed path component is exactly '..'
|
||||
preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
|
||||
if (end !== -1) {
|
||||
if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end);
|
||||
}
|
||||
} else {
|
||||
if (startPart === 0 && isAbsolute) {
|
||||
ret.name = path.slice(1, startDot);
|
||||
ret.base = path.slice(1, end);
|
||||
} else {
|
||||
ret.name = path.slice(startPart, startDot);
|
||||
ret.base = path.slice(startPart, end);
|
||||
}
|
||||
ret.ext = path.slice(startDot, end);
|
||||
}
|
||||
|
||||
if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/';
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
sep: '/',
|
||||
delimiter: ':',
|
||||
win32: null,
|
||||
posix: null
|
||||
};
|
||||
|
||||
posix.posix = posix;
|
||||
|
||||
var pathBrowserify = posix;
|
||||
|
||||
const withSubfolderClass = 'oz-with-subfolder';
|
||||
const showAllNumbersClass = 'oz-show-all-num';
|
||||
const isFolder = (item) => item.file instanceof obsidian.TFolder;
|
||||
const iterateItems = (items, callback) => {
|
||||
for (const key in items) {
|
||||
if (!Object.prototype.hasOwnProperty.call(items, key))
|
||||
continue;
|
||||
callback(items[key]);
|
||||
}
|
||||
};
|
||||
const getParentPath = (src) => {
|
||||
if (src === '/')
|
||||
return null;
|
||||
const path = pathBrowserify.dirname(src);
|
||||
if (path === '.')
|
||||
return '/';
|
||||
else
|
||||
return path;
|
||||
};
|
||||
const equals = (arr1, arr2) => {
|
||||
// if the other array is a falsy value, return
|
||||
if (!Array.isArray(arr1) || !Array.isArray(arr2))
|
||||
return false;
|
||||
// compare lengths - can save a lot of time
|
||||
if (arr1.length != arr2.length)
|
||||
return false;
|
||||
return arr1.every((v, i) => v === arr2[i]);
|
||||
};
|
||||
const isParent = (parent, child) => {
|
||||
if (child === parent)
|
||||
return false;
|
||||
if (parent === '/')
|
||||
parent = '';
|
||||
if (child === '/')
|
||||
child = '';
|
||||
const parentTokens = parent.split('/').filter((i) => i.length);
|
||||
return parentTokens.every((t, i) => child.split('/')[i] === t);
|
||||
};
|
||||
// Helper to play with the File Explorer (if exists)
|
||||
const doWithFileExplorer = (plugin, callback) => {
|
||||
let leaves;
|
||||
let count = 0;
|
||||
const tryGetView = () => {
|
||||
leaves = plugin.app.workspace.getLeavesOfType('file-explorer');
|
||||
if (leaves.length === 0) {
|
||||
if (count++ > 5)
|
||||
console.error('failed to get file-explorer');
|
||||
else {
|
||||
console.log('file-explorer not found, retrying...');
|
||||
setTimeout(tryGetView, 500);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (leaves.length > 1)
|
||||
console.warn('more then one file-explorer');
|
||||
callback(leaves[0].view);
|
||||
}
|
||||
};
|
||||
tryGetView();
|
||||
};
|
||||
|
||||
function around(obj, factories) {
|
||||
const removers = Object.keys(factories).map(key => around1(obj, key, factories[key]));
|
||||
return removers.length === 1 ? removers[0] : function () { removers.forEach(r => r()); };
|
||||
}
|
||||
function around1(obj, method, createWrapper) {
|
||||
const original = obj[method], hadOwn = obj.hasOwnProperty(method);
|
||||
let current = createWrapper(original);
|
||||
// Let our wrapper inherit static props from the wrapping method,
|
||||
// and the wrapping method, props from the original method
|
||||
if (original)
|
||||
Object.setPrototypeOf(current, original);
|
||||
Object.setPrototypeOf(wrapper, current);
|
||||
obj[method] = wrapper;
|
||||
// Return a callback to allow safe removal
|
||||
return remove;
|
||||
function wrapper(...args) {
|
||||
// If we have been deactivated and are no longer wrapped, remove ourselves
|
||||
if (current === original && obj[method] === wrapper)
|
||||
remove();
|
||||
return current.apply(this, args);
|
||||
}
|
||||
function remove() {
|
||||
// If no other patches, just do a direct removal
|
||||
if (obj[method] === wrapper) {
|
||||
if (hadOwn)
|
||||
obj[method] = original;
|
||||
else
|
||||
delete obj[method];
|
||||
}
|
||||
if (current === original)
|
||||
return;
|
||||
// Else pass future calls through, and remove wrapper from the prototype chain
|
||||
current = original;
|
||||
Object.setPrototypeOf(wrapper, original || Function);
|
||||
}
|
||||
}
|
||||
|
||||
const countFolderChildren = (folder, filter) => {
|
||||
let count = 0;
|
||||
for (const af of folder.children) {
|
||||
if (filter(af))
|
||||
count++;
|
||||
if (af instanceof obsidian.TFolder)
|
||||
count += countFolderChildren(af, filter);
|
||||
}
|
||||
return count;
|
||||
};
|
||||
/** filter out all path that is the parent of existing path */
|
||||
const filterParent = (pathList) => {
|
||||
const list = Array.from(pathList);
|
||||
list.sort();
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (i < list.length - 1 && (list[i] === list[i + 1] || isParent(list[i], list[i + 1]))) {
|
||||
list.shift();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return new Set(list);
|
||||
};
|
||||
/** get all parents and add to set if not exist */
|
||||
const getAllParents = (path, set) => {
|
||||
let parent = getParentPath(path);
|
||||
while (parent && !set.has(parent)) {
|
||||
set.add(parent);
|
||||
parent = getParentPath(parent);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Update folder count of target's parent
|
||||
*/
|
||||
const updateCount = (targetList, plugin) => {
|
||||
const set = filterParent(targetList);
|
||||
for (const path of targetList) {
|
||||
getAllParents(path, set);
|
||||
}
|
||||
// set count of path
|
||||
const { fileExplorer, fileFilter } = plugin;
|
||||
if (!fileExplorer) {
|
||||
console.error('fileExplorer missing');
|
||||
return;
|
||||
}
|
||||
for (const path of set) {
|
||||
// check if path available
|
||||
if (!fileExplorer.fileItems[path])
|
||||
continue;
|
||||
setCount(fileExplorer.fileItems[path], fileFilter);
|
||||
}
|
||||
// Update root separately
|
||||
if (plugin.rootFolderEl && plugin.settings.addRootFolder) {
|
||||
setupRootCount(plugin);
|
||||
}
|
||||
// empty waitingList
|
||||
targetList.length = 0;
|
||||
};
|
||||
const setupRootCount = (plugin) => {
|
||||
if (plugin.rootFolderEl) {
|
||||
let rootFolderElChildren = plugin.rootFolderEl.children;
|
||||
if (rootFolderElChildren && rootFolderElChildren.length > 0) {
|
||||
let totalCount = countFolderChildren(plugin.app.vault.getAbstractFileByPath('/'), plugin.fileFilter);
|
||||
rootFolderElChildren[0].setAttr('data-count', totalCount.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
const setupCount = (plugin, revert = false) => {
|
||||
if (!plugin.fileExplorer)
|
||||
throw new Error('fileExplorer not found');
|
||||
// For each setup, first setup the root folder
|
||||
plugin.setupRootFolder();
|
||||
setupRootCount(plugin);
|
||||
// Iterate other items and include new counts
|
||||
iterateItems(plugin.fileExplorer.fileItems, (item) => {
|
||||
if (!isFolder(item))
|
||||
return;
|
||||
if (revert)
|
||||
removeCount(item);
|
||||
else
|
||||
setCount(item, plugin.fileFilter);
|
||||
});
|
||||
};
|
||||
const setCount = (item, filter) => {
|
||||
// if (item.file.isRoot()) return;
|
||||
const count = countFolderChildren(item.file, filter);
|
||||
item.selfEl.dataset['count'] = count.toString();
|
||||
item.selfEl.toggleClass(withSubfolderClass, Array.isArray(item.file.children) && item.file.children.some((af) => af instanceof obsidian.TFolder));
|
||||
};
|
||||
const removeCount = (item) => {
|
||||
if (item.selfEl.dataset['count'])
|
||||
delete item.selfEl.dataset['count'];
|
||||
item.selfEl.removeClass(withSubfolderClass);
|
||||
};
|
||||
|
||||
class VaultHandler {
|
||||
get app() {
|
||||
return this.plugin.app;
|
||||
}
|
||||
get vault() {
|
||||
return this.plugin.app.vault;
|
||||
}
|
||||
constructor(plugin) {
|
||||
this.waitingList = [];
|
||||
this.update = obsidian.debounce(() => updateCount(this.waitingList, this.plugin), 500, true);
|
||||
this.handler = (...args) => {
|
||||
var _a;
|
||||
for (const arg of args) {
|
||||
const path = arg instanceof obsidian.TAbstractFile ? arg.path : arg;
|
||||
this.waitingList.push((_a = getParentPath(path)) !== null && _a !== void 0 ? _a : '/');
|
||||
}
|
||||
this.update();
|
||||
};
|
||||
this.registerVaultEvent = () => {
|
||||
this.plugin.registerEvent(this.vault.on('create', this.handler));
|
||||
this.plugin.registerEvent(this.vault.on('rename', this.handler));
|
||||
this.plugin.registerEvent(this.vault.on('delete', this.handler));
|
||||
};
|
||||
this.plugin = plugin;
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS = {
|
||||
showAllNumbers: false,
|
||||
filterList: ['md'],
|
||||
blacklist: false,
|
||||
addRootFolder: false,
|
||||
};
|
||||
class FENoteCountSettingTab extends obsidian.PluginSettingTab {
|
||||
constructor(app, plugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
get showOnlyNoteValue() {
|
||||
const { settings } = this.plugin;
|
||||
return settings.blacklist === DEFAULT_SETTINGS.blacklist && equals(settings.filterList, DEFAULT_SETTINGS.filterList);
|
||||
}
|
||||
set showOnlyNoteValue(value) {
|
||||
const { blacklist, filterList } = DEFAULT_SETTINGS;
|
||||
this.plugin.settings.blacklist = blacklist;
|
||||
if (value) {
|
||||
// do deep copy
|
||||
this.plugin.settings.filterList = Array.from(filterList);
|
||||
}
|
||||
else {
|
||||
this.plugin.settings.filterList.length = 0;
|
||||
}
|
||||
}
|
||||
display() {
|
||||
let { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.createEl('h2', {
|
||||
text: 'File Explorer Note Count Settings',
|
||||
});
|
||||
new obsidian.Setting(containerEl)
|
||||
.setName('Show All Numbers')
|
||||
.setDesc('Turn on this option if you want to see the number of notes even after you expand the collapsed folders')
|
||||
.addToggle((toggle) => toggle.setValue(this.plugin.settings.showAllNumbers).onChange((value) => {
|
||||
document.body.toggleClass('oz-show-all-num', value);
|
||||
this.plugin.settings.showAllNumbers = value;
|
||||
this.plugin.saveSettings();
|
||||
}));
|
||||
new obsidian.Setting(containerEl)
|
||||
.setName('Add Root Folder')
|
||||
.setDesc('By default, there is no root folder provided by Obsidian. It is moved to drop-down menu to switch between vaults. ' +
|
||||
'Enable this option if you want to see root folder and its count in the file explorer')
|
||||
.addToggle((toggle) => toggle.setValue(this.plugin.settings.addRootFolder).onChange((value) => {
|
||||
this.plugin.settings.addRootFolder = value;
|
||||
this.plugin.saveSettings();
|
||||
this.plugin.reloadCount();
|
||||
}));
|
||||
this.filterOpt();
|
||||
}
|
||||
filterOpt() {
|
||||
new obsidian.Setting(this.containerEl)
|
||||
.setName('Show Only Markdown Notes')
|
||||
.setDesc('Turn off this option to choose file that should be counted')
|
||||
.addToggle((toggle) => toggle.setValue(this.showOnlyNoteValue).onChange((value) => {
|
||||
this.showOnlyNoteValue = value;
|
||||
this.plugin.reloadCount();
|
||||
this.plugin.saveSettings();
|
||||
this.display();
|
||||
}));
|
||||
if (!this.showOnlyNoteValue) {
|
||||
new obsidian.Setting(this.containerEl)
|
||||
.setName('Filter List')
|
||||
.setDesc(createFragment((descEl) => {
|
||||
descEl.appendText('Extension list to include/exclude file during counting');
|
||||
descEl.appendChild(document.createElement('br'));
|
||||
descEl.appendText('Separated by comma');
|
||||
}))
|
||||
.addTextArea((text) => {
|
||||
const onChange = (value) => __awaiter(this, void 0, void 0, function* () {
|
||||
const list = value.split(',').map((v) => v.trim());
|
||||
this.plugin.settings.filterList = list;
|
||||
this.plugin.reloadCount();
|
||||
yield this.plugin.saveSettings();
|
||||
});
|
||||
text.setPlaceholder('Leave it empty to count all types of files');
|
||||
text.setValue(this.plugin.settings.filterList.join(', ')).onChange(obsidian.debounce(onChange, 500, true));
|
||||
text.inputEl.rows = 2;
|
||||
text.inputEl.cols = 25;
|
||||
});
|
||||
new obsidian.Setting(this.containerEl)
|
||||
.setName('Enable Blacklist')
|
||||
.setDesc('Turn on this option to use Filter List to exclude files')
|
||||
.addToggle((toggle) => toggle.setValue(this.plugin.settings.blacklist).onChange((value) => {
|
||||
this.plugin.settings.blacklist = value;
|
||||
this.plugin.reloadCount();
|
||||
this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FileExplorerNoteCount extends obsidian.Plugin {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.settings = DEFAULT_SETTINGS;
|
||||
this.vaultHandler = new VaultHandler(this);
|
||||
this.rootFolderEl = null;
|
||||
this.explorerNavHeaderSelector = '.workspace-leaf-content[data-type="file-explorer"] .nav-header';
|
||||
this.rootFolderClassName = 'oz-explorer-root-folder';
|
||||
this.initialize = (revert = false) => {
|
||||
let plugin = this;
|
||||
// First Check if the root folder exists
|
||||
let explorerHeaderEl = document.querySelector(`${this.explorerNavHeaderSelector} .${this.rootFolderClassName}`);
|
||||
if (explorerHeaderEl)
|
||||
this.rootFolderEl = explorerHeaderEl;
|
||||
const getViewHandler = (revert) => (view) => {
|
||||
this.fileExplorer = view;
|
||||
setupCount(this, revert);
|
||||
this.setupRootFolder(revert);
|
||||
if (!revert) {
|
||||
this.registerEvent(this.app.workspace.on('css-change', this.setupRootFolder));
|
||||
this.vaultHandler.registerVaultEvent();
|
||||
if (this.settings.showAllNumbers)
|
||||
document.body.addClass('oz-show-all-num');
|
||||
}
|
||||
else {
|
||||
for (const el of document.getElementsByClassName(withSubfolderClass)) {
|
||||
el.removeClass(withSubfolderClass);
|
||||
}
|
||||
document.body.removeClass(showAllNumbersClass);
|
||||
}
|
||||
if (!revert) {
|
||||
// when file explorer is closed (workspace changed)
|
||||
// try to update fehanlder with new file explorer instance
|
||||
this.register(around(view, {
|
||||
onClose: (next) => function () {
|
||||
setTimeout(() => doWithFileExplorer(plugin, getViewHandler(false)), 1e3);
|
||||
return next.apply(this);
|
||||
},
|
||||
}));
|
||||
}
|
||||
};
|
||||
doWithFileExplorer(plugin, getViewHandler(revert));
|
||||
};
|
||||
this.setupRootFolder = (revert = false) => {
|
||||
var _a, _b, _c;
|
||||
if (!this.fileExplorer) {
|
||||
console.error('file-explorer not found');
|
||||
return;
|
||||
}
|
||||
if (this.rootFolderEl && !this.settings.addRootFolder) {
|
||||
this.rootFolderEl.remove();
|
||||
this.rootFolderEl = null;
|
||||
}
|
||||
// Check if root is provided by Obsidian (it shouldn't be in the new releases)
|
||||
const root = (_c = (_b = (_a = this.fileExplorer) === null || _a === void 0 ? void 0 : _a.fileItems) === null || _b === void 0 ? void 0 : _b['/']) !== null && _c !== void 0 ? _c : null;
|
||||
if (!root) {
|
||||
// Get the Nav Header
|
||||
let explorerHeaderEl = document.querySelector(this.explorerNavHeaderSelector);
|
||||
if (!explorerHeaderEl)
|
||||
return;
|
||||
if (!this.rootFolderEl && this.settings.addRootFolder) {
|
||||
this.rootFolderEl = explorerHeaderEl.createEl('div', {
|
||||
cls: ['tree-item', 'nav-folder', this.rootFolderClassName],
|
||||
});
|
||||
this.rootFolderEl.innerHTML = `
|
||||
<div class="oz-explorer-root-nav-folder-title" data-path="/">
|
||||
<div class="tree-item-inner nav-folder-title-content">${this.app.vault.getName()}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
onload() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log('loading FileExplorerNoteCount');
|
||||
this.addSettingTab(new FENoteCountSettingTab(this.app, this));
|
||||
yield this.loadSettings();
|
||||
this.app.workspace.onLayoutReady(this.initialize);
|
||||
});
|
||||
}
|
||||
onunload() {
|
||||
console.log('unloading FileExplorerNoteCount');
|
||||
this.initialize(true);
|
||||
}
|
||||
loadSettings() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
this.settings = Object.assign(Object.assign({}, this.settings), (yield this.loadData()));
|
||||
});
|
||||
}
|
||||
saveSettings() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield this.saveData(this.settings);
|
||||
});
|
||||
}
|
||||
reloadCount() {
|
||||
setupCount(this);
|
||||
}
|
||||
get fileFilter() {
|
||||
let list = this.settings.filterList;
|
||||
return (af) => {
|
||||
if (af instanceof obsidian.TFile) {
|
||||
const { extension: target } = af;
|
||||
// if list is empty, filter nothing
|
||||
if (list.length === 0)
|
||||
return true;
|
||||
else if (this.settings.blacklist)
|
||||
return !list.includes(target);
|
||||
else
|
||||
return list.includes(target);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FileExplorerNoteCount;
|
||||
|
||||
/* nosourcemap */
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "file-explorer-note-count",
|
||||
"name": "File Explorer Note Count",
|
||||
"version": "1.2.3",
|
||||
"minAppVersion": "1.2.0",
|
||||
"description": "The plugin helps you to see the number of notes under each folder within the file explorer.",
|
||||
"author": "Ozan Tellioglu",
|
||||
"authorUrl": "https://www.ozan.pl",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
.nav-folder-title[data-count]::after {
|
||||
content: attr(data-count);
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
font-size: calc(100% * 0.8);
|
||||
margin-right: 4px;
|
||||
/* border-radius: 3px; */
|
||||
padding: 2px 0;
|
||||
/* background-color: var(--background-secondary-alt); */
|
||||
transition: opacity 100ms ease-in-out;
|
||||
}
|
||||
|
||||
.oz-explorer-root-nav-folder-title {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.oz-explorer-root-nav-folder-title[data-count]::after {
|
||||
content: attr(data-count);
|
||||
margin-right: 4px;
|
||||
font-size: calc(100% * 0.8);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
body:not(.oz-show-all-num) .nav-folder:not(.is-collapsed) > .nav-folder-title.oz-with-subfolder[data-count]:not([data-path='/'])::after {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.nav-folder-title-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.oz-explorer-root-folder {
|
||||
margin-top: 15px;
|
||||
}
|
||||
@@ -522,6 +522,51 @@
|
||||
"id": "f9f2be1c-e32c-4769-928b-c0323ba09c8e",
|
||||
"createdAt": 1752564654889,
|
||||
"updatedAt": 1752564654889
|
||||
},
|
||||
{
|
||||
"isEncrypted": 1,
|
||||
"EncryptedData": "3ec36d499393360ecde54768ccbb6792:e3ce75b759f99fe9056295375b4e4392fe0dd6f19d596aa2b3f3d4cca0baca5af3715e535fabe7826a3e60667ff995c816071f6b2ba92ce6b224190855bd79405c281d6d35618f9ac1170104eb9293d5dd5374116c6d81801b12f2d3003b1f00d1a06abe0639e993e62148f3feb4a96d15f5a8a2897c0d4c918e81e7bb9174a423232c4ff3393e8915aa95dad4647f2b44f27452049881cdbc9a96755cb541c42b9fe99d81c350809d0c0a39ef8b92f5ee15fca8a1dd1fc52033f1f67803a3c509ff59b819fb08293cbb33c175dde85058cf922b6e5fa26d0fec0068671b96a9ab7849856036adb76bef84af743c2a111badc78f90073e416f01575d1a3f720ed8fdc39ef2012b8e3449cca2edaf5958d6f7640d56cbdcedcfc2b6506b0e76b7ba157f749e825e9f76307e8b32489b49a6fc06b94829b88bc2d2a4565dd6e873b3815c53b80f51437d8424f5c538600188b73652ecd3866cf7a24dd58680944052fcea58a1cbbba9ade98c028f7bbe007ec215ed7e72a985c2f1f4f92aeae5916eb561ea990f0641ab6f8c7a53048d7c530f6d4f27d18eefa6309050f7de420a4fd12b2902931eba0b6477d2ffa5b2b02dccb6aa945bd0c5cf9c786a2ef0cc6c0a6da9d189abe3a2d697ea8813eeac6bfad73f6235f6b6099e0714a1f674c701c814bf3e2a926244d49fea46e0185c22bb7dcbff956cb8481632afb6a7992b22c934206e4708a6961e2314b954e3a54ae9d0749b4935d7bf4bac583808c6f302f7c80e2ce0c35fe0c56e4858a7c6edb173b580c9e6b6e7a4b152709af14693ee0b812c0483d2b33f2c5944998588ac188a76e5655cf0981a678008f5fbed5f7719c2db7ec362968ef4cc4c5f300d985b776c3671b67cdd54a51e03c3741807a8156dcf54c73f22955cbc443f209a5ac6",
|
||||
"fileName": "image.png",
|
||||
"width": 1120,
|
||||
"height": 630,
|
||||
"extname": ".png",
|
||||
"imgUrl": "https://joyimg.cpolar.top/i/2025/07/16/687760805338c.png",
|
||||
"hash": "21C34v",
|
||||
"type": "lskyplist",
|
||||
"shortUrl": "https://joyimg.cpolar.top/i/2025/07/16/687760805338c.png",
|
||||
"id": "df0b4c93-8756-42bf-9e5b-e4321cde8e34",
|
||||
"createdAt": 1752653953003,
|
||||
"updatedAt": 1752653953003
|
||||
},
|
||||
{
|
||||
"isEncrypted": 1,
|
||||
"EncryptedData": "147ae87f11c9e002274c0b34476f6d9f:ae0deaadafb525f18e80e1c7261158ea36b7675c388ec65a1b877da20a2b885f5585f8ce8b0fd9a571f28d7a48f16428c21a5f3701351da1fc8d2888979796d9cfb7d8c117af83c223a07babe9f0a581f339fea00da07f7f5931859d43a2306e2dca3dbacc5449d266ecee08f441202ce50a41e5ab274b17fa2a9fb37d05fb9e652a73fb7efc9ac9e2bcaaf279cbaef6a5bc561119a2fddf8e52c25e006b3b432147b09c8151ac7dd857299aeec28fdf17479ddcb87a30e8ba125e6237ebdd5c35d5c2c72fff4125434480342b59786129fda39d719aebae0a069270d638a608119c5406c0ba804727fa195e98c890b727530b9905b139112cfdb2658485f9a12fad39b6c334fb14bd22f24fb553aefb884ea5b3426cb460706ade2ce9cd58666381b70726971ae26374a497f511d94fa1cff92a48c03ddae6abee30b1a37af6c45b617d0708af433126b3e784a6e2c3f4cd2ead2dd10e819564d2c9e8f0c47a50f033adc2f5b77e8bc44d5d85b8d9e858df9f8818044f535ac9864efce42c4f29fe28cafeb790a640e0e172e2da2537f7aba3adb2b365c8240bfe1565fe202c6efdd4533a58e2a2f0a20d94a88bec8048f6e22493356d9904baa4689ac779d3bafa065b5342b4ad2ea67fc9a2ebdd93924e89afed19d62f489974a4f0f7a3ad67cc9e4be66f1d6560f77e4933f6d6a3a50b507df46b46799be761af37981226b6df22ecfe69bd9043938e007e0dc8b81a5abba6e1e48af6e01153782187aa5cb611043b1ad6b492e7604c465d831349e7ca062c30049b25ca2bfd5dac80f2de315fc3d01c5a416a7e7ca12dc10b6304cd5b67b94d5ada3bbb1d589de099f1f527e879d3b9e9dfa9154d4f339ff33ce8222f56dc821c7781266cb649914a1520c522f3cd65cc2c2c5175bd810a3fa74c",
|
||||
"fileName": "image.png",
|
||||
"width": 1120,
|
||||
"height": 630,
|
||||
"extname": ".png",
|
||||
"imgUrl": "https://joyimg.cpolar.top/i/2025/07/16/68776125c62a9.png",
|
||||
"hash": "GeOZ5g",
|
||||
"type": "lskyplist",
|
||||
"shortUrl": "https://joyimg.cpolar.top/i/2025/07/16/68776125c62a9.png",
|
||||
"id": "ba308be8-84f4-4191-9716-b13525b3747b",
|
||||
"createdAt": 1752654118042,
|
||||
"updatedAt": 1752654118042
|
||||
},
|
||||
{
|
||||
"isEncrypted": 1,
|
||||
"EncryptedData": "2779fc31da4419fe6c12b1632a814bf5:d3d26a8da370bf19b15f6ad3a4474f110e45e3ccedf5c6a9a54d104034f5823b5e3708617178374174e9faa43ea9cebc4e56da938fbfd39a6be034693205de82f1b15aeea8b189ed422c4a3036f4c7febf755c649dcc866d0771f10bcee7686e111d5d2e6497bf167cb86f7623ac90e5be23fbb33921313ec7a77bca6fb9ece181004be624a034cdd4e0a7c7665f6f95310d53f121bdf8912b6ddcea63601eaaa82ee313bdda41c81d28b8dc4fabb82668909688e8c863d7c65bbbaa8402817ae59fad00d219704b43fffdfc0f81abad8ef048e9f0c446d6092c78687c7b4ce0b4c959f204aa2d4d74b390c3be5990ba167b7f160024eda010b1e716b279128f0fd3be23e1cb6315dcfc41e155867ab449949ebfdd69616423304aee172a7c08b616ec8638a1099c5e490ab533f6fa53ecfe762bdb5f12e7d938f00965102edf3508855f7fac64b71dd25f8aaf89abd0acf3b1ecf63c093808c32bffd960bf9a159673f21cb07ceee9a51138dbd73f78a43a514102211455d2ecdce691b18535341c2a469346fa3e0a5dad030d220d3f484756f84c596f0cad3b2a6b604f5c40a49bac6e41c2043fbc9ff6a6bb5337fc5dce17233f52f0f4aff81ebad6cd8b833f2737d9b9c2333d7742eddc95f64e637e03c3ad24ceba001c0614ee28c7fd79bc84d43f67348ca704deb864bf904611755ad2fb9c2f7ecf7ff59ebaed6a75e1c56fa49795a37c4614b295d50b0890acc10643f36ee58206948241d8899680bd654fd9bd7a7751e63886a6ae1606ea6a80c90c6cffb8a0943f392b43477f29b50120131de856ac80d56ff80d933e2b553778153cea425f4e9dfec9defb948d83cd5c5afb52ba865c80d4ef8cfc054e97566602fdaabcc4c6828419a22b8adee2b5a367ac211ad71fc3a92ca72bdb78f0",
|
||||
"fileName": "image.png",
|
||||
"width": 1120,
|
||||
"height": 630,
|
||||
"extname": ".png",
|
||||
"imgUrl": "https://joyimg.cpolar.top/i/2025/07/16/68776157496e8.png",
|
||||
"hash": "FQLSU0",
|
||||
"type": "lskyplist",
|
||||
"shortUrl": "https://joyimg.cpolar.top/i/2025/07/16/68776157496e8.png",
|
||||
"id": "afab77dd-b8ff-4476-abca-54551cfc0e24",
|
||||
"createdAt": 1752654167605,
|
||||
"updatedAt": 1752654167605
|
||||
}
|
||||
]
|
||||
}
|
||||
+3425
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "obsidian-image-toolkit",
|
||||
"name": "Image Toolkit",
|
||||
"version": "1.4.2",
|
||||
"minAppVersion": "1.0.0",
|
||||
"description": "This plugin provides some image viewing toolkit.",
|
||||
"author": "Xiangru",
|
||||
"authorUrl": "https://github.com/sissilab",
|
||||
"isDesktopOnly": true
|
||||
}
|
||||
+747
@@ -0,0 +1,747 @@
|
||||
body {
|
||||
--layer-image-toolkit-popup: 1024;
|
||||
--layer-image-toolkit-player: 1025;
|
||||
--layer-image-toolkit-notice: 1026;
|
||||
--layer-menu: 1027;
|
||||
}
|
||||
|
||||
.menu {
|
||||
z-index: var(--layer-menu);
|
||||
}
|
||||
|
||||
.notice-container {
|
||||
z-index: var(--layer-image-toolkit-notice);
|
||||
}
|
||||
|
||||
.oit li::before {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.image-toolkit-img-invert {
|
||||
filter: invert(1) hue-rotate(180deg);
|
||||
mix-blend-mode: screen;
|
||||
}
|
||||
|
||||
.oit-normal {
|
||||
position: fixed;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, .6);
|
||||
z-index: var(--layer-image-toolkit-popup);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.oit-pin {
|
||||
position: fixed;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
z-index: var(--layer-image-toolkit-popup);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.oit .oit-img-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.oit .oit-img-container .oit-img-view {
|
||||
max-height: none;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.oit-pin .oit-img-container .oit-img-view {
|
||||
position: fixed;
|
||||
pointer-events: auto;
|
||||
box-shadow: 0 0 5px;
|
||||
}
|
||||
|
||||
.oit-pin .oit-img-container .oit-img-view:hover {
|
||||
box-shadow: 0 0 6px #55acc6;
|
||||
}
|
||||
|
||||
.oit .img-default-background {
|
||||
background-position: 0 0, 5px 5px !important;
|
||||
background-size: 10px 10px !important;
|
||||
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee 100%), linear-gradient(45deg, #eee 25%, #fff 25%, #fff 75%, #eee 75%, #eee 100%) !important;
|
||||
}
|
||||
|
||||
.oit .oit-img-container .oit-img-view:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.oit-normal .img-close {
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.oit .oit-img-tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
background-color: rgba(0, 0, 0, .4);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/*region img-player*/
|
||||
.oit .img-player {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
cursor: none;
|
||||
background-color: #000;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.oit .img-player > img {
|
||||
display: inline;
|
||||
float: none;
|
||||
padding: 0;
|
||||
max-height: none;
|
||||
transform: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
/*endregion*/
|
||||
|
||||
.oit-normal .oit-img-footer {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
bottom: 5px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/*region oit-img-title*/
|
||||
.oit-normal .oit-img-footer .oit-img-title {
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
max-width: 90%;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
margin: 5px;
|
||||
opacity: .8;
|
||||
color: #fff;
|
||||
/* filter: alpha(opacity=80) */
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-title:hover {
|
||||
/* opacity: 1; */
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
background-color: rgba(0, 0, 0, .3);
|
||||
border-radius: 8px;
|
||||
line-height: 1.5;
|
||||
/* filter: alpha(opacity=100) */
|
||||
}
|
||||
/*endregion*/
|
||||
|
||||
/*region toolbar*/
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar {
|
||||
width: 385px;
|
||||
height: 30px;
|
||||
margin: 0 auto 5px;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar:hover {
|
||||
background-color: rgba(0, 0, 0, .3);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar > li {
|
||||
float: left;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin: 0 5px;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar > li:hover {
|
||||
animation: bounce .5s cubic-bezier(0.51, 0.23, 0.02, 0.96)
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0% {
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(0.85, 1.1) translateY(-5px);
|
||||
}
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_zoom_to_100::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_zoom_in::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_zoom_out::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_full_screen::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_refresh::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_rotate_left::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_rotate_right::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_scale_x::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_scale_y::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_invert_color::before,
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_copy::before {
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
display: block;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
color: transparent;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARMAAAAZCAYAAAASRcpqAAAAAXNSR0IArs4c6QAADgJJREFUeF7tXHnQftUc/3z+YJC9KVuWsZOlIiopTYakZZpIJSUiS6JkLKGFYkJJRJsKpUVEhYpItiZFUtknJGQXmRHzMZ/H97xz3vuce++5z3ufX696z8wz77zPc+75nnPu93zO57ucQ6yUlRlYmYGVGRhhBjhCG7e7JiQd2Bw0yanv2iZmqc/f7iZ8ZcBznwFJDwPwopKgWt3uBBNJ6wJYH8DjADwFwFMBfAPAtwB8H8B5JP+01JFKenkM5EEA/HH73wXwVZJnLrV9Pz+WjACCAwp9WpvkNX19lfR8AGcU6h1U89IkPQHAzgAeCuCxANYGcHl8rgZwLckL+/rR97uk7QA8EYDl+bO63weAryd5JG/qa6f0u6S7A9gwPhvE399Gu1cBuIbkZ2dp+9Z8RtKTALwXwNFj6W3L/J1BcoexxirpwwBe0dHegSQP6pPXCiaS3gng9QDuFI3cEkDyNAB3iO9+AsCL4JQ+QS2T4oX1RgB+CW3FC+RTNQttVchogImB7mjLJemFVlUkPSMqvgqA58ClE0wkPQDA3gBeA+DOPYLeRtLvb6EEmB4DYE+Sx0o6DID7sQvJH6eKku4N4H0AXtwj45cA3k3SilhdJG0D4HAA3gm7yknWv3yzkvQQAF+JTWb3aqGroGK8048BeGCI22EegCLJG5F15swxACVrz93erKnHkhTzvVnfNBbBRJJ32MckJQfwNQCXkLxFkoHk6fFJ1P4Ukrv0CWso90cBJIXwznqld6TYnbzjPh7ARrEr+tFjSe55a8vIwMRAMvNLzZUi2mkFE0meDyuRWYjLFwGcDMC7uYt3ei+0TQBsH999Mhbjb/x/1u+JHElelAaTBQWStHEsdLNRl8sCLK+L/+8K4MkAzCaeHd+ZnW5V814kHQrgzVH3gmC3Zrp/ie/uB8AsNYGt5e9L0mzIY/D3CUx6lbumT2PUkeTxfwLAPRrtjQoojYVvUUsClKw9sw6z7XHBRNKXAGwO4DsAduui7vFyzUruD2Avkh+qeTmNSZnslKXnJHkHPhHAC+L3k0hW7UjzkpEtSitzYhaDXmoDSMxsvECKYNIAEpt/R3TteJK82K0cW8Zi3Z3kFX1gImnXAI7VAFwK4F1dpoYkA/tbwiw1M+szmb3DubjtI0ka7IpF0rYBOjar/2GAIXnqMgaTNLap8fTNS816CSBNjMT/psU/M6A0gMSs2jo4HphIsgPGVO0sks8bMNBfAVjLNjZJ+1JaS24m1E60JO+C3o1dvDhMgW8VGTmYmBIOpZ3N+tkCmQKTYIHfBrDe0F0o6+cvALwMgM1T7z5TzASAfWM2PZKiHkryX33vvwF0Bh+Dy1SRdC6A5wL4Msln9rUbi+eOAVbJP2Wb/kfLlJkkJuW/kzkO/9Ig87dtXhobo30lZqi5327WzSzpQmJ8rWAC4PyMjeZdvS5t8Au7STj2TCfvZqZBckKPa0o4aq8AcAHJRH9LSmUaa8ZjJvMRkq/MK0nybvqGMGkW7VySPHk2q0y51yP55xbF7ZTRA0K1MjYleXFqqxZQ2upJWofk95p9k7Rv+C+qTYnGfL4HwH4A/gjggy1g8nYABycgGeqbagDKtiQ/1+iD37HZ1w8AbE0ymUw1qpWbZ67/VgD2Bdkxv2zMnEwPrJ8LgF01wJ5KTSAxK20JAlQBiqTjAbw01tKCDvcwk9TLkl/QQDQBpRxMXh0KVxVVKCh+msh1SwsjdpvEfK4kuU5HG6Vd+i4RSfAuuiPJ01vApFNGD5hUyWiR2+kYqwWcTDHvA8CsxL6Q7Ul+ehblzDz1Zhre7ZvMJDU703uP92rH8JEAfhbs1KaJgcDzeW2YQq8l+YEZx5BAfkGpbw9gIin3Ky74XzoiiieSfEnbHAfwO6DRVhZFJLPIo58xG2pjLlNgkhBrK5LnhTKYJWzZfHGS7LE2Xd01/SbpheGEajVDJB0B4HUlVhLyOpFd0gkAPFknkNyjZVF3yuhT5hoZHS/LgLIWSTuOFxVJZmQ/r/XAz+ofCEXbtNDHRMVLYFLacezwbvVr5O1Lulc40K0XG5I0CBpM7L+xE9VmsE3gIpsszFViqM2f0hiKzCQcoeeUlL5nE0k0f0H3+/SkRfdGYyaSdgSQ5n+RI7cDTNytnUie1tO/Equ7iaQDIZPSAJK9epjLFJjYTHEEZbVkL0tyRMcx/wmDsYCgWemlHpCBiXMRHJF5P8l9WgaTIgivJjkJqUraCcCjsvrJ5kxfnZpCl5IcqnYcv5XmZlGKLhnN7g2SMYuizfJMAMqNNfkrmRLYCW7HcFvZg+QJkuzY7gr/7kfSIeKqIsmOeOe/2Fl6XLzbxBKrHefxnPvl/rWVs0k6D2ahxFydHRGVqR20axAZcP8VwDYkHb0cXJpO7sENxAMRnrcJ4vyuKV9UD5jYnLQZPpX/lZ7r81U2gMQ+mjWHgkkxnuw4cwYm3nltm9luc77APjlr6YtJt4QjE8C0zf0CcNTs1qtCxqxKsiqek2SfUQ7Oi8TmeQRZvkupa5eRnJgrNUXSm6z4AI4iabPHG4WB3xvAIBNHkv12rblHhVwI1/1MluPRm2BVGFNyaDp/ZjtHwGrG3QC0UZhJxkqcuLkJyb+3yGnrYpGd1IBJE0i8kWXrrtrMsfPVWa5mJk5Qm5QcTBoDcj6Dw8ETypTZY87+s/9lqlSyhhVmMlSLl0H9EtCXgH0eXc3kjNX8TA7eEZlJAqXjSDrvZlHpYSau25ZmMGm3jZlIWgOA/SM3OlG0IbYrD2XKzEme/81JXhTK4QQ1JxctQqT4zenVtqXckEOkKU28dReSZPprX8dUJCcAqdZnsj9JJ0CVAKtTRp+2ZT6TVhl9bSz19x7GcDXJ3y9VxtjPZyZoiZksmJxjyw29aTIT61Ep78Xsuy0fZjkxEyfA2QdZnLcKMCkmkfYxE0lmlmaYpWJ/inFg0RGKsEamwCTZt5M8/FDo3SIU63j5AnWMMK29uxPPcNRPQODwn/MKSgs91XEuygYk/5lX6kJ2SfcMu81RoPVJ2qE5WEaXMtfKmMeCSG1KsoPaTuS2cg5Jm5hVJRjjml3p/n7XQ44DtMx7co6XfCbFzaNqAFGpr4+3MZ9JyssprqUKMCmmElSAycTl0OdTaaxZA/QUmPhMhr3wj5jBG24q5nMfl5O0B79Ywp5PeSank7THeqFIemS0Yyehw4z5b0lZO1P3+2T0gEmVjI7x2ae0RilsKembAK7vi+Y0FKUUZbl4SC5In6kxBjWPELDNZIftS9Ec2/4bk7x5CIBkAFvli7itRHMkHRIJe53mSsdcOulw/+bvqwxMLDgL795A0gfLqkpQHdfduS+c2FgsW5B0Zl1naTzTezp3VcgovKhR8kyyvqe8kJNJ9h26awPvFPL078V5k/QcAJ8H4IXuBe+FP6hkfe7KM5kpjyUSIg1UzllxmsIXBnVuFVYeA5hjHaZo1vkkt2gDhY6hFdMzVimYxECSvXZ9hMlalStzuvnRaqeVJOexOJfAxebTYaVdK1jGqdnBr3/7FDPJ//TpyDxlNDNWaxPSOjJgFzJqc4WMU8LO4Wh1anfNgyQf47dJdBpJh+DbQCe98856pYcbi70rA3YmsJLkXAsz2MGHSft0ZOzfRwQTH5+wlWCf5dTx/x4zx8ETuxCmolHZc10n3Jdu5uQTKyllw6bF7qsGrvK5m0i7dz6KzaHktHLnvAueS3LrmpckKTl8Xd2A5U/z1LBPsTrW7pKy8P4A4OEknRPQWeYhY95ncxpg4oQvH/F3MtignT0DrptJ+vBea5HkA3WTRDNnQZP0NQe9JTYTn5N6cCkfIjWQnc1xKr0THS/pbfx/TNmmc4pmeIH4kOCyK5nDfLSzOZKc4+PjFC6rN65iSGZfaS4OJ+lwfLFIcgjd/se2Mi6YWEqAhhf8szoEG0Rsn10oyZmHPopdvbtFwpoH3nWfiamzj60bTNIx/J+Go+jXfZo1towcTOZxari5u8VC96lqJwXaHHFor+h8jvfmqJqTBn35kMtGJH3auLM0Lm3y5Uq+E6V18UryQVCnezsnZMip4b85i5nkWR0K7ysQ0n0rrjbqUf6+uRj6e2bmTz06xJnZfFiSr5jwsQoX3zszuTeog5n8juR9h/Y/1U/+tSF9LkZzOl6soyf++NYt//VCNlP5YeFQV6Kkx5P0SdWqEhf3uG2fPJ4oZ9zV4Vj3RSkNu3GozDTOPhqfJO0tY8nIXuRc7jMpUeUw97xTJVPFC9EOXe/0KdPRZ3h8gMtszsXAY0f2kAObzVvgDCYe50KadYCaI3/J0V59CLFxn4kzNb04EiNyn31vi/uQMqyXPZDE4vaJaI9l9PtMJPk0d8oo9+bptefs2OZtf76aIjGZ3vVQqjB3MBnaqyyXZGbHYZfMBqBMpVUP7W/LpOaXES2S0dgVRr9pLWMIU7uxJJ+afUfPGG8A4FybQ/Lkw9p5CSZkM8d5Dl1l3jeteXE6Z2VZmjbNiZHki6k+nu53GZNNSbIT1qe7E9vMxZt1HkwyXdFR+6qn6i07MAmkth3tHBXfVZkuNpp5kIUX58Xu8JlPH1df5DykAwFaUzI6KKZtzfxId1Fcx8nNKp+IJJud6V7WdEerTUD7m/w5ZggbaZuTiPLYSe7U/EcHY5znHbBmWO6/d15HMZZt1KZjzuw4NYOcyx2wcWbH/i1/DLKXjnEHcxqPpOSIH7JUXHdvkkfN7XZ6Sb4iwMlSy+7eiaEzVQCzldvplzqJK88vyxmIzXJI35yRPbn0fW5gMqQ3K3VXZmBlBv7/Z+C/kQ6WkguncSQAAAAASUVORK5CYII=);
|
||||
background-repeat: no-repeat
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_zoom_to_100::before {
|
||||
content: 'Zoom to Actual Size';
|
||||
background-position: 0 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_zoom_in::before {
|
||||
content: 'Zoom In';
|
||||
background-position: -25px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_zoom_out::before {
|
||||
content: 'Zoom Out';
|
||||
background-position: -50px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_full_screen::before {
|
||||
content: 'Full Screen';
|
||||
background-position: -75px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_refresh::before {
|
||||
content: 'Refresh';
|
||||
background-position: -100px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_rotate_left::before {
|
||||
content: 'Rotate Left';
|
||||
background-position: -125px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_rotate_right::before {
|
||||
content: 'Rotate Right';
|
||||
background-position: -150px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_scale_x::before {
|
||||
content: 'Scale x';
|
||||
background-position: -175px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_scale_y::before {
|
||||
content: 'Scale y';
|
||||
background-position: -200px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_invert_color::before {
|
||||
content: 'Invert color';
|
||||
background-position: -225px 0
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .oit-img-toolbar .toolbar_copy::before {
|
||||
content: 'Copy';
|
||||
background-position: -250px 0
|
||||
}
|
||||
/*endregion*/
|
||||
|
||||
/*region gallery-navbar*/
|
||||
.oit-normal .oit-img-footer .gallery-navbar {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
margin-top: 20px;
|
||||
background-color: rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .gallery-navbar:hover {
|
||||
background-color: rgba(0, 0, 0, .8);
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .gallery-navbar .gallery-list {
|
||||
display: flex;
|
||||
transform: translateX(0px);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .gallery-navbar .gallery-list .gallery-active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .gallery-navbar .gallery-list .img-border-active {
|
||||
margin-top: 1px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .gallery-navbar .gallery-list > li {
|
||||
width: 48px;
|
||||
height: 58px;
|
||||
opacity: .3;
|
||||
color: transparent;
|
||||
margin: 2px 1px;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
/* transition: all 100ms linear; */
|
||||
}
|
||||
|
||||
.oit-normal .oit-img-footer .gallery-navbar .gallery-list img {
|
||||
width: 46px;
|
||||
height: 56px;
|
||||
}
|
||||
/*endregion*/
|
||||
|
||||
.hotkeys-settings-plus {
|
||||
margin: 0 10px;
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
/*region pickr*/
|
||||
.pcr-app .pcr-swatches > button {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*! Pickr 1.8.2 MIT | https://github.com/Simonwep/pickr */
|
||||
.pickr {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
transform: translateY(0)
|
||||
}
|
||||
|
||||
.pickr * {
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
border: none;
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
.pickr .pcr-button {
|
||||
position: relative;
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
padding: 0.5em;
|
||||
cursor: pointer;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif;
|
||||
border-radius: .15em;
|
||||
background: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" stroke="%2342445A" stroke-width="5px" stroke-linecap="round"><path d="M45,45L5,5"></path><path d="M45,5L5,45"></path></svg>') no-repeat center;
|
||||
background-size: 0;
|
||||
transition: all 0.3s
|
||||
}
|
||||
|
||||
.pickr .pcr-button::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="white" d="M1,0H2V1H1V0ZM0,1H1V2H0V1Z"/><path fill="gray" d="M0,0H1V1H0V0ZM1,1H2V2H1V1Z"/></svg>');
|
||||
background-size: .5em;
|
||||
border-radius: .15em;
|
||||
z-index: -1
|
||||
}
|
||||
|
||||
.pickr .pcr-button::before {
|
||||
z-index: initial
|
||||
}
|
||||
|
||||
.pickr .pcr-button::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transition: background 0.3s;
|
||||
background: var(--pcr-color);
|
||||
border-radius: .15em
|
||||
}
|
||||
|
||||
.pickr .pcr-button.clear {
|
||||
background-size: 70%
|
||||
}
|
||||
|
||||
.pickr .pcr-button.clear::before {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.pickr .pcr-button.clear:focus {
|
||||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85), 0 0 0 3px var(--pcr-color)
|
||||
}
|
||||
|
||||
.pickr .pcr-button.disabled {
|
||||
cursor: not-allowed
|
||||
}
|
||||
|
||||
.pickr *, .pcr-app * {
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
border: none;
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
.pickr input:focus, .pickr input.pcr-active, .pickr button:focus, .pickr button.pcr-active, .pcr-app input:focus, .pcr-app input.pcr-active, .pcr-app button:focus, .pcr-app button.pcr-active {
|
||||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85), 0 0 0 3px var(--pcr-color)
|
||||
}
|
||||
|
||||
.pickr .pcr-palette, .pickr .pcr-slider, .pcr-app .pcr-palette, .pcr-app .pcr-slider {
|
||||
transition: box-shadow 0.3s
|
||||
}
|
||||
|
||||
.pickr .pcr-palette:focus, .pickr .pcr-slider:focus, .pcr-app .pcr-palette:focus, .pcr-app .pcr-slider:focus {
|
||||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85), 0 0 0 3px rgba(0, 0, 0, 0.25)
|
||||
}
|
||||
|
||||
.pcr-app {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 10000;
|
||||
border-radius: 0.1em;
|
||||
background: #fff;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.3s, visibility 0s 0.3s;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif;
|
||||
box-shadow: 0 0.15em 1.5em 0 rgba(0, 0, 0, 0.1), 0 0 1em 0 rgba(0, 0, 0, 0.03);
|
||||
left: 0;
|
||||
top: 0
|
||||
}
|
||||
|
||||
.pcr-app.visible {
|
||||
transition: opacity 0.3s;
|
||||
visibility: visible;
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
.pcr-app .pcr-swatches {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.75em
|
||||
}
|
||||
|
||||
.pcr-app .pcr-swatches.pcr-last {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
@supports (display: grid) {
|
||||
.pcr-app .pcr-swatches {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: repeat(auto-fit, 1.75em)
|
||||
}
|
||||
}
|
||||
|
||||
.pcr-app .pcr-swatches > button {
|
||||
font-size: 1em;
|
||||
position: relative;
|
||||
width: calc(1.75em - 10px);
|
||||
height: calc(1.75em - 10px);
|
||||
border-radius: 0.15em;
|
||||
cursor: pointer;
|
||||
margin: 2.5px;
|
||||
flex-shrink: 0;
|
||||
justify-self: center;
|
||||
transition: all 0.15s;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
z-index: 1
|
||||
}
|
||||
|
||||
.pcr-app .pcr-swatches > button::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="white" d="M1,0H2V1H1V0ZM0,1H1V2H0V1Z"/><path fill="gray" d="M0,0H1V1H0V0ZM1,1H2V2H1V1Z"/></svg>');
|
||||
background-size: 6px;
|
||||
border-radius: .15em;
|
||||
z-index: -1
|
||||
}
|
||||
|
||||
.pcr-app .pcr-swatches > button::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--pcr-color);
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
border-radius: 0.15em;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
.pcr-app .pcr-swatches > button:hover {
|
||||
filter: brightness(1.05)
|
||||
}
|
||||
|
||||
.pcr-app .pcr-swatches > button:not(.pcr-active) {
|
||||
box-shadow: none
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin: 0 -0.2em 0 -0.2em
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction > * {
|
||||
margin: 0 0.2em
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction input {
|
||||
letter-spacing: 0.07em;
|
||||
font-size: 0.75em;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
color: #75797e;
|
||||
background: #f1f3f4;
|
||||
border-radius: .15em;
|
||||
transition: all 0.15s;
|
||||
padding: 0.45em 0.5em;
|
||||
margin-top: 0.75em
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction input:hover {
|
||||
filter: brightness(0.975)
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction input:focus {
|
||||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85), 0 0 0 3px rgba(66, 133, 244, 0.75)
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-result {
|
||||
color: #75797e;
|
||||
text-align: left;
|
||||
flex: 1 1 8em;
|
||||
min-width: 8em;
|
||||
transition: all 0.2s;
|
||||
border-radius: .15em;
|
||||
background: #f1f3f4;
|
||||
cursor: text
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-result::-moz-selection {
|
||||
background: #4285f4;
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-result::selection {
|
||||
background: #4285f4;
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-type.active {
|
||||
color: #fff;
|
||||
background: #4285f4
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-save, .pcr-app .pcr-interaction .pcr-cancel, .pcr-app .pcr-interaction .pcr-clear {
|
||||
color: #fff;
|
||||
width: auto
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-save, .pcr-app .pcr-interaction .pcr-cancel, .pcr-app .pcr-interaction .pcr-clear {
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-save:hover, .pcr-app .pcr-interaction .pcr-cancel:hover, .pcr-app .pcr-interaction .pcr-clear:hover {
|
||||
filter: brightness(0.925)
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-save {
|
||||
background: #4285f4
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-clear, .pcr-app .pcr-interaction .pcr-cancel {
|
||||
background: #f44250
|
||||
}
|
||||
|
||||
.pcr-app .pcr-interaction .pcr-clear:focus, .pcr-app .pcr-interaction .pcr-cancel:focus {
|
||||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85), 0 0 0 3px rgba(244, 66, 80, 0.75)
|
||||
}
|
||||
|
||||
.pcr-app .pcr-selection .pcr-picker {
|
||||
position: absolute;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
border: 2px solid #fff;
|
||||
border-radius: 100%;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none
|
||||
}
|
||||
|
||||
.pcr-app .pcr-selection .pcr-color-palette, .pcr-app .pcr-selection .pcr-color-chooser, .pcr-app .pcr-selection .pcr-color-opacity {
|
||||
position: relative;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
cursor: grab;
|
||||
cursor: -webkit-grab
|
||||
}
|
||||
|
||||
.pcr-app .pcr-selection .pcr-color-palette:active, .pcr-app .pcr-selection .pcr-color-chooser:active, .pcr-app .pcr-selection .pcr-color-opacity:active {
|
||||
cursor: grabbing;
|
||||
cursor: -webkit-grabbing
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] {
|
||||
width: 14.25em;
|
||||
max-width: 95vw
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-swatches {
|
||||
margin-top: .6em;
|
||||
padding: 0 .6em
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-interaction {
|
||||
padding: 0 .6em .6em .6em
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection {
|
||||
display: grid;
|
||||
grid-gap: .6em;
|
||||
grid-template-columns: 1fr 4fr;
|
||||
grid-template-rows: 5fr auto auto;
|
||||
align-items: center;
|
||||
height: 10.5em;
|
||||
width: 100%;
|
||||
align-self: flex-start
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-preview {
|
||||
grid-area: 2 / 1 / 4 / 1;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
margin-left: .6em
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-preview .pcr-last-color {
|
||||
display: none
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-preview .pcr-current-color {
|
||||
position: relative;
|
||||
background: var(--pcr-color);
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
border-radius: 50em;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-preview .pcr-current-color::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="white" d="M1,0H2V1H1V0ZM0,1H1V2H0V1Z"/><path fill="gray" d="M0,0H1V1H0V0ZM1,1H2V2H1V1Z"/></svg>');
|
||||
background-size: .5em;
|
||||
border-radius: .15em;
|
||||
z-index: -1
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-palette {
|
||||
grid-area: 1 / 1 / 2 / 3;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-palette .pcr-palette {
|
||||
border-radius: .15em;
|
||||
width: 100%;
|
||||
height: 100%
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-palette .pcr-palette::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="white" d="M1,0H2V1H1V0ZM0,1H1V2H0V1Z"/><path fill="gray" d="M0,0H1V1H0V0ZM1,1H2V2H1V1Z"/></svg>');
|
||||
background-size: .5em;
|
||||
border-radius: .15em;
|
||||
z-index: -1
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-chooser {
|
||||
grid-area: 2 / 2 / 2 / 2
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-opacity {
|
||||
grid-area: 3 / 2 / 3 / 2
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-chooser, .pcr-app[data-theme='nano'] .pcr-selection .pcr-color-opacity {
|
||||
height: 0.5em;
|
||||
margin: 0 .6em
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-chooser .pcr-picker, .pcr-app[data-theme='nano'] .pcr-selection .pcr-color-opacity .pcr-picker {
|
||||
top: 50%;
|
||||
transform: translateY(-50%)
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-chooser .pcr-slider, .pcr-app[data-theme='nano'] .pcr-selection .pcr-color-opacity .pcr-slider {
|
||||
flex-grow: 1;
|
||||
border-radius: 50em
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-chooser .pcr-slider {
|
||||
background: linear-gradient(to right, red, #ff0, lime, cyan, blue, #f0f, red)
|
||||
}
|
||||
|
||||
.pcr-app[data-theme='nano'] .pcr-selection .pcr-color-opacity .pcr-slider {
|
||||
background: linear-gradient(to right, transparent, black), url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="white" d="M1,0H2V1H1V0ZM0,1H1V2H0V1Z"/><path fill="gray" d="M0,0H1V1H0V0ZM1,1H2V2H1V1Z"/></svg>');
|
||||
background-size: 100%, 0.25em
|
||||
}
|
||||
/*endregion*/
|
||||
Reference in new issue
Block a user