mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 15:15:44 -03:00
feat: implement various UI helpers including clipboard, toasts, theme toggling, and Civitai integration, and add RecipeModal component.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Recipe Modal Component
|
||||
import { showToast, copyToClipboard, sendModelPathToWorkflow } from '../utils/uiHelpers.js';
|
||||
import { showToast, copyToClipboard, sendModelPathToWorkflow, openCivitaiByMetadata } from '../utils/uiHelpers.js';
|
||||
import { translate } from '../utils/i18nHelpers.js';
|
||||
import { state } from '../state/index.js';
|
||||
import { setSessionItem, removeSessionItem } from '../utils/storageHelpers.js';
|
||||
@@ -221,8 +221,8 @@ class RecipeModal {
|
||||
if (modalImage) {
|
||||
// Ensure file_url exists, fallback to file_path if needed
|
||||
const imageUrl = recipe.file_url ||
|
||||
(recipe.file_path ? `/loras_static/root1/preview/${recipe.file_path.split('/').pop()}` :
|
||||
'/loras_static/images/no-preview.png');
|
||||
(recipe.file_path ? `/loras_static/root1/preview/${recipe.file_path.split('/').pop()}` :
|
||||
'/loras_static/images/no-preview.png');
|
||||
|
||||
// Check if the file is a video (mp4)
|
||||
const isVideo = imageUrl.toLowerCase().endsWith('.mp4');
|
||||
@@ -261,9 +261,8 @@ class RecipeModal {
|
||||
sourceUrlContainer.innerHTML = `
|
||||
<div class="source-url-content">
|
||||
<span class="source-url-icon"><i class="fas fa-link"></i></span>
|
||||
<span class="source-url-text" title="${isValidUrl ? 'Click to open source URL' : 'No valid URL'}">${
|
||||
hasSourceUrl ? sourceUrl : 'No source URL'
|
||||
}</span>
|
||||
<span class="source-url-text" title="${isValidUrl ? 'Click to open source URL' : 'No valid URL'}">${hasSourceUrl ? sourceUrl : 'No source URL'
|
||||
}</span>
|
||||
</div>
|
||||
<button class="source-url-edit-btn" title="Edit source URL">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
@@ -743,8 +742,8 @@ class RecipeModal {
|
||||
// Update source URL in the UI
|
||||
sourceUrlText.textContent = newSourceUrl || 'No source URL';
|
||||
sourceUrlText.title = newSourceUrl && (newSourceUrl.startsWith('http://') ||
|
||||
newSourceUrl.startsWith('https://')) ?
|
||||
'Click to open source URL' : 'No valid URL';
|
||||
newSourceUrl.startsWith('https://')) ?
|
||||
'Click to open source URL' : 'No valid URL';
|
||||
|
||||
// Update the current recipe object
|
||||
this.currentRecipe.source_path = newSourceUrl;
|
||||
@@ -1249,6 +1248,17 @@ class RecipeModal {
|
||||
}
|
||||
|
||||
navigateToCheckpointPage(checkpoint) {
|
||||
if (!checkpoint.inLibrary) {
|
||||
const modelId = checkpoint.modelId || checkpoint.modelID || checkpoint.model_id;
|
||||
const versionId = checkpoint.id || checkpoint.modelVersionId;
|
||||
const modelName = checkpoint.name || checkpoint.modelName || checkpoint.file_name;
|
||||
|
||||
if (modelId || modelName) {
|
||||
openCivitaiByMetadata(modelId, versionId, modelName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const checkpointHash = this._getCheckpointHash(checkpoint);
|
||||
|
||||
if (!checkpointHash) {
|
||||
@@ -1296,6 +1306,18 @@ class RecipeModal {
|
||||
if (specificLoraIndex !== null) {
|
||||
// If a specific LoRA index is provided, navigate to view just that one LoRA
|
||||
const lora = this.currentRecipe.loras[specificLoraIndex];
|
||||
|
||||
if (lora && !lora.inLibrary) {
|
||||
const modelId = lora.modelId || lora.modelID || lora.model_id;
|
||||
const versionId = lora.id || lora.modelVersionId;
|
||||
const modelName = lora.modelName || lora.name || lora.file_name;
|
||||
|
||||
if (modelId || modelName) {
|
||||
openCivitaiByMetadata(modelId, versionId, modelName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (lora && lora.hash) {
|
||||
// Set session storage to open the LoRA modal directly
|
||||
setSessionItem('recipe_to_lora_filterLoraHash', lora.hash.toLowerCase());
|
||||
|
||||
@@ -16,192 +16,196 @@ import { eventManager } from './EventManager.js';
|
||||
* @returns {Promise<boolean>} - Promise that resolves to true if copy was successful
|
||||
*/
|
||||
export async function copyToClipboard(text, successMessage = null) {
|
||||
const defaultSuccessMessage = successMessage || translate('uiHelpers.clipboard.copied', {}, 'Copied to clipboard');
|
||||
const defaultSuccessMessage = successMessage || translate('uiHelpers.clipboard.copied', {}, 'Copied to clipboard');
|
||||
|
||||
try {
|
||||
// Modern clipboard API
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
} else {
|
||||
// Fallback for older browsers
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.style.position = 'absolute';
|
||||
textarea.style.left = '-99999px';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
|
||||
if (defaultSuccessMessage) {
|
||||
showToast('uiHelpers.clipboard.copied', {}, 'success');
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error('Copy failed:', err);
|
||||
showToast('uiHelpers.clipboard.copyFailed', {}, 'error');
|
||||
return false;
|
||||
try {
|
||||
// Modern clipboard API
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
} else {
|
||||
// Fallback for older browsers
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.style.position = 'absolute';
|
||||
textarea.style.left = '-99999px';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
|
||||
if (defaultSuccessMessage) {
|
||||
showToast('uiHelpers.clipboard.copied', {}, 'success');
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error('Copy failed:', err);
|
||||
showToast('uiHelpers.clipboard.copyFailed', {}, 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function showToast(key, params = {}, type = 'info', fallback = null) {
|
||||
const message = translate(key, params, fallback);
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
const message = translate(key, params, fallback);
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
// Get or create toast container
|
||||
let toastContainer = document.querySelector('.toast-container');
|
||||
if (!toastContainer) {
|
||||
toastContainer = document.createElement('div');
|
||||
toastContainer.className = 'toast-container';
|
||||
document.body.append(toastContainer);
|
||||
// Get or create toast container
|
||||
let toastContainer = document.querySelector('.toast-container');
|
||||
if (!toastContainer) {
|
||||
toastContainer = document.createElement('div');
|
||||
toastContainer.className = 'toast-container';
|
||||
document.body.append(toastContainer);
|
||||
}
|
||||
|
||||
toastContainer.append(toast);
|
||||
|
||||
// Calculate vertical position for stacked toasts
|
||||
const existingToasts = Array.from(toastContainer.querySelectorAll('.toast'));
|
||||
const toastIndex = existingToasts.indexOf(toast);
|
||||
const topOffset = 20; // Base offset from top
|
||||
const spacing = 10; // Space between toasts
|
||||
|
||||
// Set position based on existing toasts
|
||||
toast.style.top = `${topOffset + (toastIndex * (toast.offsetHeight || 60 + spacing))}px`;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
toast.classList.add('show');
|
||||
|
||||
// Set timeout based on type
|
||||
let timeout = 2000; // Default (info)
|
||||
if (type === 'warning' || type === 'error') {
|
||||
timeout = 5000;
|
||||
}
|
||||
|
||||
toastContainer.append(toast);
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
toast.addEventListener('transitionend', () => {
|
||||
toast.remove();
|
||||
|
||||
// Calculate vertical position for stacked toasts
|
||||
const existingToasts = Array.from(toastContainer.querySelectorAll('.toast'));
|
||||
const toastIndex = existingToasts.indexOf(toast);
|
||||
const topOffset = 20; // Base offset from top
|
||||
const spacing = 10; // Space between toasts
|
||||
// Reposition remaining toasts
|
||||
if (toastContainer) {
|
||||
const remainingToasts = Array.from(toastContainer.querySelectorAll('.toast'));
|
||||
remainingToasts.forEach((t, index) => {
|
||||
t.style.top = `${topOffset + (index * (t.offsetHeight || 60 + spacing))}px`;
|
||||
});
|
||||
|
||||
// Set position based on existing toasts
|
||||
toast.style.top = `${topOffset + (toastIndex * (toast.offsetHeight || 60 + spacing))}px`;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
toast.classList.add('show');
|
||||
|
||||
// Set timeout based on type
|
||||
let timeout = 2000; // Default (info)
|
||||
if (type === 'warning' || type === 'error') {
|
||||
timeout = 5000;
|
||||
// Remove container if empty
|
||||
if (remainingToasts.length === 0) {
|
||||
toastContainer.remove();
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
toast.addEventListener('transitionend', () => {
|
||||
toast.remove();
|
||||
|
||||
// Reposition remaining toasts
|
||||
if (toastContainer) {
|
||||
const remainingToasts = Array.from(toastContainer.querySelectorAll('.toast'));
|
||||
remainingToasts.forEach((t, index) => {
|
||||
t.style.top = `${topOffset + (index * (t.offsetHeight || 60 + spacing))}px`;
|
||||
});
|
||||
|
||||
// Remove container if empty
|
||||
if (remainingToasts.length === 0) {
|
||||
toastContainer.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}, timeout);
|
||||
});
|
||||
});
|
||||
}, timeout);
|
||||
});
|
||||
}
|
||||
|
||||
export function restoreFolderFilter() {
|
||||
const activeFolder = getStorageItem('activeFolder');
|
||||
const folderTag = activeFolder && document.querySelector(`.tag[data-folder="${activeFolder}"]`);
|
||||
if (folderTag) {
|
||||
folderTag.classList.add('active');
|
||||
filterByFolder(activeFolder);
|
||||
}
|
||||
const activeFolder = getStorageItem('activeFolder');
|
||||
const folderTag = activeFolder && document.querySelector(`.tag[data-folder="${activeFolder}"]`);
|
||||
if (folderTag) {
|
||||
folderTag.classList.add('active');
|
||||
filterByFolder(activeFolder);
|
||||
}
|
||||
}
|
||||
|
||||
export function initTheme() {
|
||||
const savedTheme = getStorageItem('theme') || 'auto';
|
||||
applyTheme(savedTheme);
|
||||
const savedTheme = getStorageItem('theme') || 'auto';
|
||||
applyTheme(savedTheme);
|
||||
|
||||
// Update theme when system preference changes (for 'auto' mode)
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
const currentTheme = getStorageItem('theme') || 'auto';
|
||||
if (currentTheme === 'auto') {
|
||||
applyTheme('auto');
|
||||
}
|
||||
});
|
||||
// Update theme when system preference changes (for 'auto' mode)
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
const currentTheme = getStorageItem('theme') || 'auto';
|
||||
if (currentTheme === 'auto') {
|
||||
applyTheme('auto');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function toggleTheme() {
|
||||
const currentTheme = getStorageItem('theme') || 'auto';
|
||||
let newTheme;
|
||||
const currentTheme = getStorageItem('theme') || 'auto';
|
||||
let newTheme;
|
||||
|
||||
if (currentTheme === 'light') {
|
||||
newTheme = 'dark';
|
||||
} else {
|
||||
newTheme = 'light';
|
||||
}
|
||||
if (currentTheme === 'light') {
|
||||
newTheme = 'dark';
|
||||
} else {
|
||||
newTheme = 'light';
|
||||
}
|
||||
|
||||
setStorageItem('theme', newTheme);
|
||||
applyTheme(newTheme);
|
||||
setStorageItem('theme', newTheme);
|
||||
applyTheme(newTheme);
|
||||
|
||||
// Force a repaint to ensure theme changes are applied immediately
|
||||
document.body.style.display = 'none';
|
||||
document.body.offsetHeight; // Trigger a reflow
|
||||
document.body.style.display = '';
|
||||
// Force a repaint to ensure theme changes are applied immediately
|
||||
document.body.style.display = 'none';
|
||||
document.body.offsetHeight; // Trigger a reflow
|
||||
document.body.style.display = '';
|
||||
|
||||
return newTheme;
|
||||
return newTheme;
|
||||
}
|
||||
|
||||
// Add a new helper function to apply the theme
|
||||
function applyTheme(theme) {
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const htmlElement = document.documentElement;
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const htmlElement = document.documentElement;
|
||||
|
||||
// Remove any existing theme attributes
|
||||
htmlElement.removeAttribute('data-theme');
|
||||
// Remove any existing theme attributes
|
||||
htmlElement.removeAttribute('data-theme');
|
||||
|
||||
// Apply the appropriate theme
|
||||
if (theme === 'dark' || (theme === 'auto' && prefersDark)) {
|
||||
htmlElement.setAttribute('data-theme', 'dark');
|
||||
document.body.dataset.theme = 'dark';
|
||||
} else {
|
||||
htmlElement.setAttribute('data-theme', 'light');
|
||||
document.body.dataset.theme = 'light';
|
||||
}
|
||||
// Apply the appropriate theme
|
||||
if (theme === 'dark' || (theme === 'auto' && prefersDark)) {
|
||||
htmlElement.setAttribute('data-theme', 'dark');
|
||||
document.body.dataset.theme = 'dark';
|
||||
} else {
|
||||
htmlElement.setAttribute('data-theme', 'light');
|
||||
document.body.dataset.theme = 'light';
|
||||
}
|
||||
|
||||
// Update the theme-toggle icon state
|
||||
updateThemeToggleIcons(theme);
|
||||
// Update the theme-toggle icon state
|
||||
updateThemeToggleIcons(theme);
|
||||
}
|
||||
|
||||
// New function to update theme toggle icons
|
||||
function updateThemeToggleIcons(theme) {
|
||||
const themeToggle = document.querySelector('.theme-toggle');
|
||||
if (!themeToggle) return;
|
||||
const themeToggle = document.querySelector('.theme-toggle');
|
||||
if (!themeToggle) return;
|
||||
|
||||
// Remove any existing active classes
|
||||
themeToggle.classList.remove('theme-light', 'theme-dark', 'theme-auto');
|
||||
// Remove any existing active classes
|
||||
themeToggle.classList.remove('theme-light', 'theme-dark', 'theme-auto');
|
||||
|
||||
// Add the appropriate class based on current theme
|
||||
themeToggle.classList.add(`theme-${theme}`);
|
||||
// Add the appropriate class based on current theme
|
||||
themeToggle.classList.add(`theme-${theme}`);
|
||||
}
|
||||
|
||||
function filterByFolder(folderPath) {
|
||||
document.querySelectorAll('.model-card').forEach(card => {
|
||||
card.style.display = card.dataset.folder === folderPath ? '' : 'none';
|
||||
});
|
||||
document.querySelectorAll('.model-card').forEach(card => {
|
||||
card.style.display = card.dataset.folder === folderPath ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
export function openCivitaiByMetadata(civitaiId, versionId, modelName = null) {
|
||||
if (civitaiId) {
|
||||
let url = `https://civitai.com/models/${civitaiId}`;
|
||||
if (versionId) {
|
||||
url += `?modelVersionId=${versionId}`;
|
||||
}
|
||||
window.open(url, '_blank');
|
||||
} else if (modelName) {
|
||||
// 如果没有ID,尝试使用名称搜索
|
||||
window.open(`https://civitai.com/models?query=${encodeURIComponent(modelName)}`, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
export function openCivitai(filePath) {
|
||||
const loraCard = document.querySelector(`.model-card[data-filepath="${filePath}"]`);
|
||||
if (!loraCard) return;
|
||||
const loraCard = document.querySelector(`.model-card[data-filepath="${filePath}"]`);
|
||||
if (!loraCard) return;
|
||||
|
||||
const metaData = JSON.parse(loraCard.dataset.meta);
|
||||
const civitaiId = metaData.modelId;
|
||||
const versionId = metaData.id;
|
||||
const metaData = JSON.parse(loraCard.dataset.meta);
|
||||
const civitaiId = metaData.modelId;
|
||||
const versionId = metaData.id;
|
||||
const modelName = loraCard.dataset.name;
|
||||
|
||||
if (civitaiId) {
|
||||
let url = `https://civitai.com/models/${civitaiId}`;
|
||||
if (versionId) {
|
||||
url += `?modelVersionId=${versionId}`;
|
||||
}
|
||||
window.open(url, '_blank');
|
||||
} else {
|
||||
// 如果没有ID,尝试使用名称搜索
|
||||
const modelName = loraCard.dataset.name;
|
||||
window.open(`https://civitai.com/models?query=${encodeURIComponent(modelName)}`, '_blank');
|
||||
}
|
||||
openCivitaiByMetadata(civitaiId, versionId, modelName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,90 +213,90 @@ export function openCivitai(filePath) {
|
||||
* based on the current layout and folder tags container height
|
||||
*/
|
||||
export function updatePanelPositions() {
|
||||
const searchOptionsPanel = document.getElementById('searchOptionsPanel');
|
||||
const filterPanel = document.getElementById('filterPanel');
|
||||
const searchOptionsPanel = document.getElementById('searchOptionsPanel');
|
||||
const filterPanel = document.getElementById('filterPanel');
|
||||
|
||||
if (!searchOptionsPanel && !filterPanel) return;
|
||||
if (!searchOptionsPanel && !filterPanel) return;
|
||||
|
||||
// Get the header element
|
||||
const header = document.querySelector('.app-header');
|
||||
if (!header) return;
|
||||
// Get the header element
|
||||
const header = document.querySelector('.app-header');
|
||||
if (!header) return;
|
||||
|
||||
// Calculate the position based on the bottom of the header
|
||||
const headerRect = header.getBoundingClientRect();
|
||||
const topPosition = headerRect.bottom + 5; // Add 5px padding
|
||||
// Calculate the position based on the bottom of the header
|
||||
const headerRect = header.getBoundingClientRect();
|
||||
const topPosition = headerRect.bottom + 5; // Add 5px padding
|
||||
|
||||
// Set the positions
|
||||
// Set the positions
|
||||
if (searchOptionsPanel) {
|
||||
searchOptionsPanel.style.top = `${topPosition}px`;
|
||||
}
|
||||
|
||||
if (filterPanel) {
|
||||
filterPanel.style.top = `${topPosition}px`;
|
||||
}
|
||||
|
||||
// Adjust panel horizontal position based on the search container
|
||||
const searchContainer = document.querySelector('.header-search');
|
||||
if (searchContainer) {
|
||||
const searchRect = searchContainer.getBoundingClientRect();
|
||||
|
||||
// Position the search options panel aligned with the search container
|
||||
if (searchOptionsPanel) {
|
||||
searchOptionsPanel.style.top = `${topPosition}px`;
|
||||
searchOptionsPanel.style.right = `${window.innerWidth - searchRect.right}px`;
|
||||
}
|
||||
|
||||
// Position the filter panel aligned with the filter button
|
||||
if (filterPanel) {
|
||||
filterPanel.style.top = `${topPosition}px`;
|
||||
}
|
||||
|
||||
// Adjust panel horizontal position based on the search container
|
||||
const searchContainer = document.querySelector('.header-search');
|
||||
if (searchContainer) {
|
||||
const searchRect = searchContainer.getBoundingClientRect();
|
||||
|
||||
// Position the search options panel aligned with the search container
|
||||
if (searchOptionsPanel) {
|
||||
searchOptionsPanel.style.right = `${window.innerWidth - searchRect.right}px`;
|
||||
}
|
||||
|
||||
// Position the filter panel aligned with the filter button
|
||||
if (filterPanel) {
|
||||
const filterButton = document.getElementById('filterButton');
|
||||
if (filterButton) {
|
||||
const filterRect = filterButton.getBoundingClientRect();
|
||||
filterPanel.style.right = `${window.innerWidth - filterRect.right}px`;
|
||||
}
|
||||
const filterButton = document.getElementById('filterButton');
|
||||
if (filterButton) {
|
||||
const filterRect = filterButton.getBoundingClientRect();
|
||||
filterPanel.style.right = `${window.innerWidth - filterRect.right}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function initBackToTop() {
|
||||
const button = document.getElementById('backToTopBtn');
|
||||
if (!button) return;
|
||||
const button = document.getElementById('backToTopBtn');
|
||||
if (!button) return;
|
||||
|
||||
// Get the scrollable container
|
||||
const scrollContainer = document.querySelector('.page-content');
|
||||
// Get the scrollable container
|
||||
const scrollContainer = document.querySelector('.page-content');
|
||||
|
||||
// Show/hide button based on scroll position
|
||||
const toggleBackToTop = () => {
|
||||
const scrollThreshold = window.innerHeight * 0.3;
|
||||
if (scrollContainer.scrollTop > scrollThreshold) {
|
||||
button.classList.add('visible');
|
||||
} else {
|
||||
button.classList.remove('visible');
|
||||
}
|
||||
};
|
||||
// Show/hide button based on scroll position
|
||||
const toggleBackToTop = () => {
|
||||
const scrollThreshold = window.innerHeight * 0.3;
|
||||
if (scrollContainer.scrollTop > scrollThreshold) {
|
||||
button.classList.add('visible');
|
||||
} else {
|
||||
button.classList.remove('visible');
|
||||
}
|
||||
};
|
||||
|
||||
// Smooth scroll to top
|
||||
button.addEventListener('click', () => {
|
||||
scrollContainer.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
// Smooth scroll to top
|
||||
button.addEventListener('click', () => {
|
||||
scrollContainer.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
});
|
||||
|
||||
// Listen for scroll events on the scrollable container
|
||||
scrollContainer.addEventListener('scroll', toggleBackToTop);
|
||||
// Listen for scroll events on the scrollable container
|
||||
scrollContainer.addEventListener('scroll', toggleBackToTop);
|
||||
|
||||
// Initial check
|
||||
toggleBackToTop();
|
||||
// Initial check
|
||||
toggleBackToTop();
|
||||
}
|
||||
|
||||
export function getNSFWLevelName(level) {
|
||||
if (level === 0) return 'Unknown';
|
||||
if (level >= 32) return 'Blocked';
|
||||
if (level >= 16) return 'XXX';
|
||||
if (level >= 8) return 'X';
|
||||
if (level >= 4) return 'R';
|
||||
if (level >= 2) return 'PG13';
|
||||
if (level >= 1) return 'PG';
|
||||
return 'Unknown';
|
||||
if (level === 0) return 'Unknown';
|
||||
if (level >= 32) return 'Blocked';
|
||||
if (level >= 16) return 'XXX';
|
||||
if (level >= 8) return 'X';
|
||||
if (level >= 4) return 'R';
|
||||
if (level >= 2) return 'PG13';
|
||||
if (level >= 1) return 'PG';
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
function parseUsageTipNumber(value) {
|
||||
|
||||
Reference in New Issue
Block a user