Add in safetensors metadata (trained words, base model file). For #223
This commit is contained in:
+20
-5
@@ -8,8 +8,7 @@ import asyncio
|
||||
from datetime import datetime
|
||||
|
||||
from .utils_server import get_param
|
||||
from .utils import get_dict_value, load_json_file, is_dict_value_falsy, save_json_file
|
||||
from .utils_info import get_model_info, get_sha256_hash, set_model_info_partial
|
||||
from .utils_info import delete_all_model_info, get_model_info, set_model_info_partial
|
||||
|
||||
from server import PromptServer
|
||||
from aiohttp import web
|
||||
@@ -104,18 +103,33 @@ async def api_get_loras(request):
|
||||
@routes.get('/rgthree/api/loras/info')
|
||||
async def api_get_loras_info(request):
|
||||
""" Returns a list loras info; either all or a single if provided a 'file' param. """
|
||||
api_response = await get_loras_info_response(request)
|
||||
api_response = await get_loras_info_response(request, maybe_fetch_metadata=True)
|
||||
return web.json_response(api_response)
|
||||
|
||||
|
||||
@routes.get('/rgthree/api/loras/info/clear')
|
||||
async def delete_lora_info(request):
|
||||
"""Clears lora info from the filesystem for the provided file."""
|
||||
api_response = {'status': 200}
|
||||
lora_file = get_param(request, 'file')
|
||||
if lora_file is None:
|
||||
api_response['status'] = '404'
|
||||
api_response['error'] = 'No Lora found at path'
|
||||
else:
|
||||
await delete_all_model_info(lora_file)
|
||||
return web.json_response(api_response)
|
||||
|
||||
|
||||
@routes.get('/rgthree/api/loras/info/refresh')
|
||||
async def refresh_get_loras_info(request):
|
||||
""" Refreshes lora info; either all or a single if provided a 'file' param. """
|
||||
api_response = await get_loras_info_response(request, maybe_fetch_civitai=True)
|
||||
api_response = await get_loras_info_response(request,
|
||||
maybe_fetch_civitai=True,
|
||||
maybe_fetch_metadata=True)
|
||||
return web.json_response(api_response)
|
||||
|
||||
|
||||
async def get_loras_info_response(request, maybe_fetch_civitai=False):
|
||||
async def get_loras_info_response(request, maybe_fetch_civitai=False, maybe_fetch_metadata=False):
|
||||
"""Gets lora info for all or a single lora"""
|
||||
api_response = {'status': 200}
|
||||
lora_file = get_param(request, 'file')
|
||||
@@ -124,6 +138,7 @@ async def get_loras_info_response(request, maybe_fetch_civitai=False):
|
||||
if lora_file is not None:
|
||||
info_data = await get_model_info(lora_file,
|
||||
maybe_fetch_civitai=maybe_fetch_civitai,
|
||||
maybe_fetch_metadata=maybe_fetch_metadata,
|
||||
abandon_if_no_file=light)
|
||||
if info_data is None:
|
||||
api_response['status'] = '404'
|
||||
|
||||
+295
-110
@@ -8,24 +8,39 @@ import copy
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from .utils import get_dict_value, is_dict_value_falsy, load_json_file, save_json_file
|
||||
from .utils_userdata import read_userdata_json, save_userdata_json
|
||||
from .utils import get_dict_value, load_json_file, save_json_file
|
||||
from .utils_userdata import read_userdata_json, save_userdata_json, delete_userdata_file
|
||||
|
||||
import folder_paths
|
||||
from server import PromptServer
|
||||
|
||||
|
||||
async def delete_all_model_info(file: str, model_type="loras"):
|
||||
"""Delete the info json, and the civitai & metadata caches."""
|
||||
file_path = get_folder_path(file, model_type)
|
||||
if file_path is None:
|
||||
return
|
||||
try_info_path = f'{file_path}.rgthree-info.json'
|
||||
if os.path.isfile(try_info_path):
|
||||
os.remove(try_info_path)
|
||||
file_hash = _get_sha256_hash(file_path)
|
||||
json_file_path = f'civitai/{file_hash}.json'
|
||||
delete_userdata_file(json_file_path)
|
||||
json_file_path = f'metadata/{file_hash}.json'
|
||||
delete_userdata_file(json_file_path)
|
||||
|
||||
|
||||
async def get_model_info(file: str,
|
||||
model_type="loras",
|
||||
default=None,
|
||||
maybe_fetch_civitai=False,
|
||||
force_fetch_civitai=False,
|
||||
maybe_fetch_metadata=False,
|
||||
force_fetch_metadata=False,
|
||||
abandon_if_no_file=False):
|
||||
|
||||
file_path = folder_paths.get_full_path(model_type, file)
|
||||
if not os.path.exists(file_path):
|
||||
file_path = os.path.abspath(file_path)
|
||||
if not os.path.exists(file_path):
|
||||
file_path = get_folder_path(file, model_type)
|
||||
if file_path is None:
|
||||
return default
|
||||
|
||||
info_data = {}
|
||||
@@ -67,136 +82,226 @@ async def get_model_info(file: str,
|
||||
info_data['raw'] = {}
|
||||
should_save = True
|
||||
|
||||
if force_fetch_civitai is True or (maybe_fetch_civitai is True and
|
||||
'civitai' not in info_data['raw']):
|
||||
data_civitai = get_model_civitai_data(file,
|
||||
model_type=model_type,
|
||||
default={},
|
||||
refresh=force_fetch_civitai)
|
||||
should_save = _update_data(info_data) or should_save
|
||||
|
||||
if 'name' not in info_data:
|
||||
info_data['name'] = get_dict_value(data_civitai, 'model.name', '')
|
||||
should_fetch_civitai = force_fetch_civitai is True or (maybe_fetch_civitai is True and
|
||||
'civitai' not in info_data['raw'])
|
||||
should_fetch_metadata = force_fetch_metadata is True or (maybe_fetch_metadata is True and
|
||||
'metadata' not in info_data['raw'])
|
||||
|
||||
if should_fetch_metadata:
|
||||
data_meta = _get_model_metadata(file,
|
||||
model_type=model_type,
|
||||
default={},
|
||||
refresh=force_fetch_metadata)
|
||||
should_save = _merge_metadata(info_data, data_meta) or should_save
|
||||
|
||||
if should_fetch_civitai:
|
||||
data_civitai = _get_model_civitai_data(file,
|
||||
model_type=model_type,
|
||||
default={},
|
||||
refresh=force_fetch_civitai)
|
||||
should_save = _merge_civitai_data(info_data, data_civitai) or should_save
|
||||
|
||||
if 'sha256' not in info_data:
|
||||
file_hash = _get_sha256_hash(file_path)
|
||||
if file_hash is not None:
|
||||
info_data['sha256'] = file_hash
|
||||
should_save = True
|
||||
version_name = get_dict_value(data_civitai, 'name')
|
||||
if version_name is not None:
|
||||
info_data['name'] += f' - {version_name}'
|
||||
|
||||
if 'type' not in info_data:
|
||||
info_data['type'] = get_dict_value(data_civitai, 'model.type')
|
||||
should_save = True
|
||||
if 'baseModel' not in info_data:
|
||||
info_data['baseModel'] = get_dict_value(data_civitai, 'baseModel')
|
||||
should_save = True
|
||||
|
||||
if 'triggerWords' not in info_data:
|
||||
if 'triggerWords' in data_civitai:
|
||||
info_data['triggerWords'] = get_dict_value(data_civitai, 'triggerWords')
|
||||
should_save = True
|
||||
if is_dict_value_falsy(data_civitai, 'triggerWords') and 'trainedWords' in data_civitai:
|
||||
info_data['triggerWords'] = get_dict_value(data_civitai, 'trainedWords')
|
||||
if not is_dict_value_falsy(data_civitai,
|
||||
'triggerWords') and ',' in info_data['triggerWords'][0]:
|
||||
trigger_words = re.sub(r"^,", "", info_data['triggerWords'][0])
|
||||
trigger_words = re.sub(r",$", "", trigger_words)
|
||||
trigger_words = re.sub(r"\s*,\s*", ",", trigger_words)
|
||||
info_data['triggerWords'] = trigger_words.split(',')
|
||||
should_save = True
|
||||
|
||||
if 'sha256' not in info_data:
|
||||
info_data['sha256'] = data_civitai['_sha256']
|
||||
should_save = True
|
||||
|
||||
if 'modelId' in data_civitai:
|
||||
info_data['links'] = info_data['links'] if 'links' in info_data else []
|
||||
civitai_link = f'https://civitai.com/models/{get_dict_value(data_civitai, "modelId")}'
|
||||
if get_dict_value(data_civitai, "id"):
|
||||
civitai_link += f'?modelVersionId={get_dict_value(data_civitai, "id")}'
|
||||
info_data['links'].append(civitai_link)
|
||||
info_data['links'].append(data_civitai['_civitai_api'])
|
||||
should_save = True
|
||||
|
||||
# Take images from civitai
|
||||
if 'images' in data_civitai:
|
||||
info_data_image_urls = list(
|
||||
map(lambda i: i['url'] if 'url' in i else None, info_data['images']))
|
||||
for img in data_civitai['images']:
|
||||
img_url = get_dict_value(img, 'url')
|
||||
if img_url is not None and img_url not in info_data_image_urls:
|
||||
img_id = os.path.splitext(os.path.basename(img_url))[0] if img_url is not None else None
|
||||
img_data = {
|
||||
'url': img_url,
|
||||
'civitaiUrl': f'https://civitai.com/images/{img_id}' if img_id is not None else None,
|
||||
'width': get_dict_value(img, 'width'),
|
||||
'height': get_dict_value(img, 'height'),
|
||||
'type': get_dict_value(img, 'type'),
|
||||
'nsfwLevel': get_dict_value(img, 'nsfwLevel'),
|
||||
'seed': get_dict_value(img, 'meta.seed'),
|
||||
'positive': get_dict_value(img, 'meta.prompt'),
|
||||
'negative': get_dict_value(img, 'meta.negativePrompt'),
|
||||
'steps': get_dict_value(img, 'meta.steps'),
|
||||
'sampler': get_dict_value(img, 'meta.sampler'),
|
||||
'cfg': get_dict_value(img, 'meta.cfgScale'),
|
||||
'model': get_dict_value(img, 'meta.Model'),
|
||||
'resources': get_dict_value(img, 'meta.resources'),
|
||||
}
|
||||
info_data['images'].append(img_data)
|
||||
should_save = True
|
||||
|
||||
# The raw data
|
||||
if 'civitai' not in info_data['raw']:
|
||||
info_data['raw']['civitai'] = data_civitai
|
||||
should_save = True
|
||||
|
||||
else:
|
||||
if 'sha256' not in info_data:
|
||||
file_hash = get_sha256_hash(file_path)
|
||||
if file_hash is not None:
|
||||
info_data['sha256'] = file_hash
|
||||
should_save = True
|
||||
|
||||
# If we've fetched civitai, then the UI is likely waiting to see if the refreshed data is coming
|
||||
# in. Not needed yet, only for Lora Chooser.
|
||||
# await PromptServer.instance.send("rgthree-lora-info", {"data": info_data})
|
||||
|
||||
if should_save:
|
||||
if 'trainedWords' in info_data:
|
||||
# Sort by count; if it doesn't exist, then assume it's a top item from civitai or elsewhere.
|
||||
info_data['trainedWords'] = sorted(info_data['trainedWords'],
|
||||
key=lambda w: w['count'] if 'count' in w else 99999,
|
||||
reverse=True)
|
||||
save_model_info(file, info_data, model_type=model_type)
|
||||
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
def get_sha256_hash(path: str):
|
||||
"""Returns the hash for the file."""
|
||||
file_hash = None
|
||||
sha256_hash = hashlib.sha256()
|
||||
with open(path, "rb") as f:
|
||||
# Read and update hash string value in blocks of 4K
|
||||
for byte_block in iter(lambda: f.read(4096), b""):
|
||||
sha256_hash.update(byte_block)
|
||||
file_hash = sha256_hash.hexdigest()
|
||||
return file_hash
|
||||
def _update_data(info_data: dict) -> bool:
|
||||
"""Ports old data to new data if necessary."""
|
||||
should_save = False
|
||||
# If we have "triggerWords" then move them over to "trainedWords"
|
||||
if 'triggerWords' in info_data and len(info_data['triggerWords']) > 0:
|
||||
civitai_words = ','.join((get_dict_value(info_data, 'raw.civitai.triggerWords', default=[]) +
|
||||
get_dict_value(info_data, 'raw.civitai.trainedWords', default=[])))
|
||||
if 'trainedWords' not in info_data:
|
||||
info_data['trainedWords'] = []
|
||||
for trigger_word in info_data['triggerWords']:
|
||||
word_data = next((data for data in info_data['trainedWords'] if data['word'] == trigger_word),
|
||||
None)
|
||||
if word_data is None:
|
||||
word_data = {'word': trigger_word}
|
||||
info_data['trainedWords'].append(word_data)
|
||||
if trigger_word in civitai_words:
|
||||
word_data['civitai'] = True
|
||||
else:
|
||||
word_data['user'] = True
|
||||
|
||||
del info_data['triggerWords']
|
||||
should_save = True
|
||||
return should_save
|
||||
|
||||
|
||||
def get_model_civitai_data(file: str, model_type="loras", default=None, refresh=False):
|
||||
def _merge_metadata(info_data: dict, data_meta: dict) -> bool:
|
||||
"""Returns true if data was saved."""
|
||||
should_save = False
|
||||
|
||||
base_model_file = get_dict_value(data_meta, 'ss_sd_model_name', None)
|
||||
if base_model_file:
|
||||
info_data['baseModelFile'] = base_model_file
|
||||
|
||||
# Loop over metadata tags
|
||||
trained_words = {}
|
||||
if 'ss_tag_frequency' in data_meta and isinstance(data_meta['ss_tag_frequency'], dict):
|
||||
for bucket_value in data_meta['ss_tag_frequency'].values():
|
||||
if isinstance(bucket_value, dict):
|
||||
for tag, count in bucket_value.items():
|
||||
if tag not in trained_words:
|
||||
trained_words[tag] = {'word': tag, 'count': 0, 'metadata': True}
|
||||
trained_words[tag]['count'] = trained_words[tag]['count'] + count
|
||||
|
||||
if 'trainedWords' not in info_data:
|
||||
info_data['trainedWords'] = list(trained_words.values())
|
||||
should_save = True
|
||||
else:
|
||||
# We can't merge, because the list may have other data, like it's part of civitaidata.
|
||||
merged_dict = {}
|
||||
for existing_word_data in info_data['trainedWords']:
|
||||
merged_dict[existing_word_data['word']] = existing_word_data
|
||||
for new_key, new_word_data in trained_words.items():
|
||||
if new_key not in merged_dict:
|
||||
merged_dict[new_key] = {}
|
||||
merged_dict[new_key] = {**merged_dict[new_key], **new_word_data}
|
||||
info_data['trainedWords'] = list(merged_dict.values())
|
||||
should_save = True
|
||||
|
||||
# trained_words = list(trained_words.values())
|
||||
# info_data['meta_trained_words'] = trained_words
|
||||
info_data['raw']['metadata'] = data_meta
|
||||
should_save = True
|
||||
|
||||
if 'sha256' not in info_data and '_sha256' in data_meta:
|
||||
info_data['sha256'] = data_meta['_sha256']
|
||||
should_save = True
|
||||
|
||||
return should_save
|
||||
|
||||
|
||||
def _merge_civitai_data(info_data: dict, data_civitai: dict) -> bool:
|
||||
"""Returns true if data was saved."""
|
||||
should_save = False
|
||||
|
||||
if 'name' not in info_data:
|
||||
info_data['name'] = get_dict_value(data_civitai, 'model.name', '')
|
||||
should_save = True
|
||||
version_name = get_dict_value(data_civitai, 'name')
|
||||
if version_name is not None:
|
||||
info_data['name'] += f' - {version_name}'
|
||||
|
||||
if 'type' not in info_data:
|
||||
info_data['type'] = get_dict_value(data_civitai, 'model.type')
|
||||
should_save = True
|
||||
if 'baseModel' not in info_data:
|
||||
info_data['baseModel'] = get_dict_value(data_civitai, 'baseModel')
|
||||
should_save = True
|
||||
|
||||
# We always want to merge triggerword.
|
||||
civitai_trigger = get_dict_value(data_civitai, 'triggerWords', default=[])
|
||||
civitai_trained = get_dict_value(data_civitai, 'trainedWords', default=[])
|
||||
civitai_words = ','.join(civitai_trigger + civitai_trained)
|
||||
if civitai_words:
|
||||
civitai_words = re.sub(r"\s*,\s*", ",", civitai_words)
|
||||
civitai_words = re.sub(r",+", ",", civitai_words)
|
||||
civitai_words = re.sub(r"^,", "", civitai_words)
|
||||
civitai_words = re.sub(r",$", "", civitai_words)
|
||||
if civitai_words:
|
||||
civitai_words = civitai_words.split(',')
|
||||
if 'trainedWords' not in info_data:
|
||||
info_data['trainedWords'] = []
|
||||
for trigger_word in civitai_words:
|
||||
word_data = next(
|
||||
(data for data in info_data['trainedWords'] if data['word'] == trigger_word), None)
|
||||
if word_data is None:
|
||||
word_data = {'word': trigger_word}
|
||||
info_data['trainedWords'].append(word_data)
|
||||
word_data['civitai'] = True
|
||||
|
||||
if 'sha256' not in info_data:
|
||||
info_data['sha256'] = data_civitai['_sha256']
|
||||
should_save = True
|
||||
|
||||
if 'modelId' in data_civitai:
|
||||
info_data['links'] = info_data['links'] if 'links' in info_data else []
|
||||
civitai_link = f'https://civitai.com/models/{get_dict_value(data_civitai, "modelId")}'
|
||||
if get_dict_value(data_civitai, "id"):
|
||||
civitai_link += f'?modelVersionId={get_dict_value(data_civitai, "id")}'
|
||||
info_data['links'].append(civitai_link)
|
||||
info_data['links'].append(data_civitai['_civitai_api'])
|
||||
should_save = True
|
||||
|
||||
# Take images from civitai
|
||||
if 'images' in data_civitai:
|
||||
info_data_image_urls = list(map(lambda i: i['url']
|
||||
if 'url' in i else None, info_data['images']))
|
||||
for img in data_civitai['images']:
|
||||
img_url = get_dict_value(img, 'url')
|
||||
if img_url is not None and img_url not in info_data_image_urls:
|
||||
img_id = os.path.splitext(os.path.basename(img_url))[0] if img_url is not None else None
|
||||
img_data = {
|
||||
'url': img_url,
|
||||
'civitaiUrl': f'https://civitai.com/images/{img_id}' if img_id is not None else None,
|
||||
'width': get_dict_value(img, 'width'),
|
||||
'height': get_dict_value(img, 'height'),
|
||||
'type': get_dict_value(img, 'type'),
|
||||
'nsfwLevel': get_dict_value(img, 'nsfwLevel'),
|
||||
'seed': get_dict_value(img, 'meta.seed'),
|
||||
'positive': get_dict_value(img, 'meta.prompt'),
|
||||
'negative': get_dict_value(img, 'meta.negativePrompt'),
|
||||
'steps': get_dict_value(img, 'meta.steps'),
|
||||
'sampler': get_dict_value(img, 'meta.sampler'),
|
||||
'cfg': get_dict_value(img, 'meta.cfgScale'),
|
||||
'model': get_dict_value(img, 'meta.Model'),
|
||||
'resources': get_dict_value(img, 'meta.resources'),
|
||||
}
|
||||
info_data['images'].append(img_data)
|
||||
should_save = True
|
||||
|
||||
# The raw data
|
||||
if 'civitai' not in info_data['raw']:
|
||||
info_data['raw']['civitai'] = data_civitai
|
||||
should_save = True
|
||||
|
||||
return should_save
|
||||
|
||||
|
||||
def _get_model_civitai_data(file: str, model_type="loras", default=None, refresh=False):
|
||||
"""Gets the civitai data, either cached from the user directory, or from civitai api."""
|
||||
file_path = folder_paths.get_full_path(model_type, file)
|
||||
if not os.path.exists(file_path):
|
||||
file_path = os.path.abspath(file_path)
|
||||
|
||||
file_hash = get_sha256_hash(file_path)
|
||||
file_hash = _get_sha256_hash(get_folder_path(file, model_type))
|
||||
if file_hash is None:
|
||||
return None
|
||||
|
||||
json_file_path = f'civitai/{file_hash}.json'
|
||||
|
||||
api_url = f'https://civitai.com/api/v1/model-versions/by-hash/{file_hash}'
|
||||
file_data = read_userdata_json(f'info/{file_hash}_civitai.json')
|
||||
if file_data is None or refresh == True:
|
||||
file_data = read_userdata_json(json_file_path)
|
||||
if file_data is None or refresh is True:
|
||||
try:
|
||||
response = requests.get(api_url, timeout=5000)
|
||||
data = response.json()
|
||||
save_userdata_json(f'civitai/{file_hash}.json', {
|
||||
save_userdata_json(json_file_path, {
|
||||
'url': api_url,
|
||||
'timestamp': datetime.now().timestamp(),
|
||||
'response': data
|
||||
})
|
||||
file_data = read_userdata_json(f'civitai/{file_hash}.json')
|
||||
file_data = read_userdata_json(json_file_path)
|
||||
except requests.exceptions.RequestException as e: # This is the correct syntax
|
||||
print(e)
|
||||
response = file_data['response'] if file_data is not None and 'response' in file_data else None
|
||||
@@ -206,6 +311,86 @@ def get_model_civitai_data(file: str, model_type="loras", default=None, refresh=
|
||||
return response if response is not None else default
|
||||
|
||||
|
||||
def _get_model_metadata(file: str, model_type="loras", default=None, refresh=False):
|
||||
"""Gets the metadata from the file itself."""
|
||||
file_path = get_folder_path(file, model_type)
|
||||
file_hash = _get_sha256_hash(file_path)
|
||||
if file_hash is None:
|
||||
return default
|
||||
|
||||
json_file_path = f'metadata/{file_hash}.json'
|
||||
|
||||
file_data = read_userdata_json(json_file_path)
|
||||
if file_data is None or refresh is True:
|
||||
data = _read_file_metadata_from_header(file_path)
|
||||
if data is not None:
|
||||
file_data = {'url': file, 'timestamp': datetime.now().timestamp(), 'response': data}
|
||||
save_userdata_json(json_file_path, file_data)
|
||||
response = file_data['response'] if file_data is not None and 'response' in file_data else None
|
||||
if response is not None:
|
||||
response['_sha256'] = file_hash
|
||||
return response if response is not None else default
|
||||
|
||||
|
||||
def _read_file_metadata_from_header(file_path: str) -> dict:
|
||||
"""Reads the file's header and returns a JSON dict metdata if available."""
|
||||
data = None
|
||||
try:
|
||||
if file_path.endswith('.safetensors'):
|
||||
with open(file_path, "rb") as file:
|
||||
# https://github.com/huggingface/safetensors#format
|
||||
# 8 bytes: N, an unsigned little-endian 64-bit integer, containing the size of the header
|
||||
header_size = int.from_bytes(file.read(8), "little", signed=False)
|
||||
|
||||
if header_size <= 0:
|
||||
raise BufferError("Invalid header size")
|
||||
|
||||
header = file.read(header_size)
|
||||
if header is None:
|
||||
raise BufferError("Invalid header")
|
||||
|
||||
header_json = json.loads(header)
|
||||
data = header_json["__metadata__"] if "__metadata__" in header_json else None
|
||||
|
||||
if data is not None:
|
||||
for key, value in data.items():
|
||||
if isinstance(value, str) and value.startswith('{') and value.endswith('}'):
|
||||
try:
|
||||
value_as_json = json.loads(value)
|
||||
data[key] = value_as_json
|
||||
except Exception:
|
||||
print(f'metdata for field {key} did not parse as json')
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(e)
|
||||
data = None
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_folder_path(file: str, model_type="loras"):
|
||||
"""Gets the file path ensuring it exists."""
|
||||
file_path = folder_paths.get_full_path(model_type, file)
|
||||
if not os.path.exists(file_path):
|
||||
file_path = os.path.abspath(file_path)
|
||||
if not os.path.exists(file_path):
|
||||
return None
|
||||
return file_path
|
||||
|
||||
|
||||
def _get_sha256_hash(file_path: str):
|
||||
"""Returns the hash for the file."""
|
||||
if not file_path or not os.path.exists(file_path):
|
||||
return None
|
||||
file_hash = None
|
||||
sha256_hash = hashlib.sha256()
|
||||
with open(file_path, "rb") as f:
|
||||
# Read and update hash string value in blocks of 4K
|
||||
for byte_block in iter(lambda: f.read(4096), b""):
|
||||
sha256_hash.update(byte_block)
|
||||
file_hash = sha256_hash.hexdigest()
|
||||
return file_hash
|
||||
|
||||
|
||||
async def set_model_info_partial(file: str, info_data_partial, model_type="loras"):
|
||||
"""Sets partial data into the existing model info data."""
|
||||
info_data = await get_model_info(file, model_type=model_type, default={})
|
||||
|
||||
@@ -22,6 +22,13 @@ def save_userdata_file(rel_path: str, content: str):
|
||||
file.write(content)
|
||||
|
||||
|
||||
def delete_userdata_file(rel_path: str):
|
||||
"""Deletes a file from the userdata directory."""
|
||||
file_path = clean_path(rel_path)
|
||||
if os.path.isfile(file_path):
|
||||
os.remove(file_path)
|
||||
|
||||
|
||||
def read_userdata_json(rel_path: str):
|
||||
"""Reads a json file from the userdata directory."""
|
||||
file_path = clean_path(rel_path)
|
||||
|
||||
+130
-58
@@ -5,18 +5,30 @@ import {
|
||||
appendChildren,
|
||||
getClosestOrSelf,
|
||||
queryOne,
|
||||
setAttributes,
|
||||
query,
|
||||
} from "rgthree/common/utils_dom.js";
|
||||
import {
|
||||
logoCivitai,
|
||||
link,
|
||||
pencilColored,
|
||||
diskColored,
|
||||
dotdotdot,
|
||||
} from "rgthree/common/media/svgs.js";
|
||||
import { rgthreeApi } from "rgthree/common/rgthree_api.js";
|
||||
import { logoCivitai, link, pencilColored, diskColored } from "rgthree/common/media/svgs.js";
|
||||
import { RgthreeModelInfo } from "typings/rgthree.js";
|
||||
import { SERVICE as MODEL_INFO_SERVICE } from "rgthree/common/model_info_service.js";
|
||||
import { rgthree } from "./rgthree.js";
|
||||
import { generateId } from "rgthree/common/shared_utils.js";
|
||||
|
||||
function injectCss(): Promise<void> {
|
||||
const href = "rgthree/common/css/dialog_model_info.css";
|
||||
if (queryOne(`link[href^="${href}"]`)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
const link = $el<HTMLLinkElement>('link[rel="stylesheet"][type="text/css"]');
|
||||
const timeout = setTimeout(resolve, 1000);
|
||||
link.addEventListener("load", (e) => {
|
||||
clearInterval(timeout);
|
||||
resolve();
|
||||
});
|
||||
link.href = href;
|
||||
document.head.appendChild(link);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A dialog that displays information about a model/lora/etc.
|
||||
@@ -39,7 +51,9 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
}
|
||||
|
||||
private async init(file: string) {
|
||||
const cssPromise = injectCss();
|
||||
this.modelInfo = await MODEL_INFO_SERVICE.getLora(file, false, false);
|
||||
await cssPromise;
|
||||
this.setContent(this.getInfoContent());
|
||||
this.setTitle(this.modelInfo?.["name"] || this.modelInfo?.["file"] || "Unknown");
|
||||
this.attachEvents();
|
||||
@@ -54,53 +68,86 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
|
||||
private attachEvents() {
|
||||
this.contentElement.addEventListener("click", async (e: MouseEvent) => {
|
||||
const info = this.modelInfo;
|
||||
if (!info?.file) {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = getClosestOrSelf(e.target as HTMLElement, "[data-action]");
|
||||
const action = target?.getAttribute("data-action");
|
||||
if (action === "fetch-civitai") {
|
||||
this.modelInfo = await MODEL_INFO_SERVICE.refreshLora(info.file);
|
||||
this.setContent(this.getInfoContent());
|
||||
this.setTitle(this.modelInfo?.["name"] || this.modelInfo?.["file"] || "Unknown");
|
||||
} else if (action === "edit-row") {
|
||||
const tr = target!.closest("tr")!;
|
||||
const td = queryOne("td:nth-child(2)", tr)!;
|
||||
const input = td.querySelector("input,textarea");
|
||||
if (!input) {
|
||||
const fieldName = tr.dataset["fieldName"] as string;
|
||||
tr.classList.add("-rgthree-editing");
|
||||
const isTextarea = fieldName === "userNote";
|
||||
const input = $el(`${isTextarea ? "textarea" : 'input[type="text"]'}`, {
|
||||
value: td.textContent,
|
||||
});
|
||||
input.addEventListener("keydown", (e) => {
|
||||
if (!isTextarea && e.key === "Enter") {
|
||||
const modified = saveEditableRow(info!, tr, true);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
} else if (e.key === "Escape") {
|
||||
const modified = saveEditableRow(info!, tr, false);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
appendChildren(empty(td), [input]);
|
||||
input.focus();
|
||||
} else if (target!.nodeName.toLowerCase() === "button") {
|
||||
const modified = saveEditableRow(info!, tr, true);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!target || !action) {
|
||||
return;
|
||||
}
|
||||
await this.handleEventAction(action, target, e);
|
||||
});
|
||||
}
|
||||
|
||||
private async handleEventAction(action: string, target: HTMLElement, e?: Event) {
|
||||
const info = this.modelInfo!;
|
||||
if (!info?.file) {
|
||||
return;
|
||||
}
|
||||
if (action === "fetch-civitai") {
|
||||
this.modelInfo = await MODEL_INFO_SERVICE.refreshLora(info.file);
|
||||
this.setContent(this.getInfoContent());
|
||||
this.setTitle(this.modelInfo?.["name"] || this.modelInfo?.["file"] || "Unknown");
|
||||
} else if (action === "copy-trained-words") {
|
||||
const selected = query(".-rgthree-is-selected", target.closest("tr")!);
|
||||
const text = selected.map((el) => el.getAttribute("data-word")).join(", ");
|
||||
await navigator.clipboard.writeText(text);
|
||||
rgthree.showMessage({
|
||||
id: "copy-trained-words-" + generateId(4),
|
||||
type: "success",
|
||||
message: `Successfully copied ${selected.length} key word${
|
||||
selected.length === 1 ? "" : "s"
|
||||
}.`,
|
||||
timeout: 4000,
|
||||
});
|
||||
} else if (action === "toggle-trained-word") {
|
||||
target?.classList.toggle("-rgthree-is-selected");
|
||||
const tr = target.closest("tr");
|
||||
if (tr) {
|
||||
const span = queryOne("td:first-child > *", tr)!;
|
||||
let small = queryOne("small", span);
|
||||
if (!small) {
|
||||
small = $el("small", { parent: span });
|
||||
}
|
||||
const num = query(".-rgthree-is-selected", tr).length;
|
||||
small.innerHTML = num
|
||||
? `${num} selected | <span role="button" data-action="copy-trained-words">Copy</span>`
|
||||
: "";
|
||||
// this.handleEventAction('copy-trained-words', target, e);
|
||||
}
|
||||
} else if (action === "edit-row") {
|
||||
const tr = target!.closest("tr")!;
|
||||
const td = queryOne("td:nth-child(2)", tr)!;
|
||||
const input = td.querySelector("input,textarea");
|
||||
if (!input) {
|
||||
const fieldName = tr.dataset["fieldName"] as string;
|
||||
tr.classList.add("-rgthree-editing");
|
||||
const isTextarea = fieldName === "userNote";
|
||||
const input = $el(`${isTextarea ? "textarea" : 'input[type="text"]'}`, {
|
||||
value: td.textContent,
|
||||
});
|
||||
input.addEventListener("keydown", (e) => {
|
||||
if (!isTextarea && e.key === "Enter") {
|
||||
const modified = saveEditableRow(info!, tr, true);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
} else if (e.key === "Escape") {
|
||||
const modified = saveEditableRow(info!, tr, false);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
appendChildren(empty(td), [input]);
|
||||
input.focus();
|
||||
} else if (target!.nodeName.toLowerCase() === "button") {
|
||||
const modified = saveEditableRow(info!, tr, true);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
}
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
private getInfoContent() {
|
||||
const info = this.modelInfo || {};
|
||||
const civitaiLink = info.links?.find((i) => i.includes("civitai.com/models"));
|
||||
@@ -145,14 +192,21 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
)
|
||||
: ""
|
||||
}
|
||||
${infoTableRow("Base Model", info.baseModel || "")}
|
||||
|
||||
${infoTableRow("Name", info.name || "", "The name for display.", "name")}
|
||||
${infoTableRow(
|
||||
"Trigger Words",
|
||||
info.triggerWords?.join(", ") ?? "",
|
||||
"Easily keep track of the trigger words to reference here.",
|
||||
"triggerWords",
|
||||
"Base Model",
|
||||
(info.baseModel || " ") + (info.baseModelFile ? `(${info.baseModelFile})` : ""),
|
||||
)}
|
||||
${infoTableRow(
|
||||
"Name",
|
||||
info.name || info.raw?.metadata?.ss_output_name || "",
|
||||
"The name for display.",
|
||||
"name",
|
||||
)}
|
||||
|
||||
${infoTableRow(
|
||||
"Trained Words",
|
||||
getTrainedWordsMarkup(info.trainedWords) ?? "",
|
||||
"Trained words from the metadata and/or civitai. Click to select for copy.",
|
||||
)}
|
||||
${infoTableRow(
|
||||
"Strength Min",
|
||||
@@ -241,7 +295,9 @@ function infoTableRow(
|
||||
editableFieldName ? `data-field-name="${editableFieldName}"` : ""
|
||||
}>
|
||||
<td><span>${name} ${help ? `<span class="-help" title="${help}"></span>` : ""}<span></td>
|
||||
<td ${editableFieldName ? "" : 'colspan="2"'}><span>${value}</span></td>
|
||||
<td ${editableFieldName ? "" : 'colspan="2"'}>${
|
||||
String(value).startsWith("<") ? value : `<span>${value}<span>`
|
||||
}</td>
|
||||
${
|
||||
editableFieldName
|
||||
? `<td style="width: 24px;"><button class="rgthree-button-reset rgthree-button-edit" data-action="edit-row">${pencilColored}${diskColored}</button></td>`
|
||||
@@ -250,6 +306,22 @@ function infoTableRow(
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
function getTrainedWordsMarkup(words: RgthreeModelInfo["trainedWords"]) {
|
||||
let markup = `<ul class="rgthree-info-trained-words-list">`;
|
||||
for (const wordData of words || []) {
|
||||
markup += `<li title="${wordData.word}" data-word="${
|
||||
wordData.word
|
||||
}" class="rgthree-info-trained-words-list-item" data-action="toggle-trained-word">
|
||||
<span>${wordData.word}</span>
|
||||
${wordData.civitai ? logoCivitai : ""}
|
||||
${wordData.count != null ? `<small>${wordData.count}</small>` : ""}
|
||||
</li>`;
|
||||
}
|
||||
markup += `</ul>`;
|
||||
console.log(markup);
|
||||
return markup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves / cancels an editable row. Returns a boolean if the data was modified.
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@ import { RgthreeProgressBar } from "rgthree/common/progress_bar.js";
|
||||
import { RgthreeConfigDialog } from "./config.js";
|
||||
import { iconGear, iconReplace, iconStarFilled, logoRgthree } from "rgthree/common/media/svgs.js";
|
||||
import type { Bookmark } from "./bookmark";
|
||||
import { query } from "rgthree/common/utils_dom.js";
|
||||
|
||||
declare const LiteGraph: typeof TLiteGraph;
|
||||
declare const LGraphCanvas: typeof TLGraphCanvas;
|
||||
@@ -789,6 +790,16 @@ class Rgthree extends EventTarget {
|
||||
container.classList.add("rgthree-top-messages-container");
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
// If we have a dialog open then we want to append the message to the dialog so they show over
|
||||
// the modal.
|
||||
const dialogs = query<HTMLDialogElement>('dialog[open]');
|
||||
if (dialogs.length) {
|
||||
let dialog = dialogs[dialogs.length - 1]!;
|
||||
dialog.appendChild(container);
|
||||
dialog.addEventListener('close', (e) => {
|
||||
document.body.appendChild(container!);
|
||||
});
|
||||
}
|
||||
// Hide if we exist.
|
||||
await this.hideMessage(data.id);
|
||||
|
||||
|
||||
@@ -127,405 +127,3 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
|
||||
.rgthree-info-dialog {
|
||||
|
||||
min-width: 600px;
|
||||
|
||||
.rgthree-info-tags {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
|
||||
> li {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
|
||||
+ li {
|
||||
margin-left: 6px;
|
||||
}
|
||||
&:not(.-link) + li.-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
> * {
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255,255,255,0.85);
|
||||
background: rgb(69, 92, 85);;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
padding-left: .5em;
|
||||
padding-right: .5em;
|
||||
padding-bottom: .1em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
|
||||
> svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
&:first-child {
|
||||
margin-right: .3em;
|
||||
display: none;
|
||||
}
|
||||
&:last-child {
|
||||
margin-left: .5em;
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&[href] {
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,0.25), inset 0px -1px 0px rgba(0,0,0,0.66);
|
||||
}
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.-civitai > * {
|
||||
color: #ddd;
|
||||
background: #1b65aa;
|
||||
transition: all 0.15s ease-in-out;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
border-color: #1971c2;
|
||||
background: #1971c2;
|
||||
}
|
||||
}
|
||||
&.-type > * {
|
||||
background: rgb(73, 54, 94);
|
||||
color: rgb(228, 209, 248);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rgthree-info-table {
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
|
||||
tr.editable button {
|
||||
display: flex;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
svg + svg {display: none;}
|
||||
}
|
||||
tr.editable.-rgthree-editing button {
|
||||
svg {display: none;}
|
||||
svg + svg {display: inline-block;}
|
||||
}
|
||||
|
||||
td {
|
||||
position: relative;
|
||||
border: 1px solid rgba(255,255,255,0.25);
|
||||
padding: 0;
|
||||
|
||||
&:first-child {
|
||||
background: rgba(255,255,255,0.075);
|
||||
width: 10px; // Small, so it doesn't adjust.
|
||||
> *:first-child {
|
||||
white-space: nowrap;
|
||||
padding-right: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
a, a:hover, a:visited {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: .5em 0;
|
||||
padding: 0 0 0 1em;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 1.3333em;
|
||||
height: 1.3333em;
|
||||
vertical-align: -0.285em;
|
||||
|
||||
&.logo-civitai {
|
||||
margin-right: 0.3333em;
|
||||
}
|
||||
}
|
||||
|
||||
> *:first-child {
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
> input, > textarea{
|
||||
padding: 5px 10px;
|
||||
border: 0;
|
||||
box-shadow: inset 1px 1px 5px 0px rgba(0,0,0,0.5);
|
||||
font: inherit;
|
||||
appearance: none;
|
||||
background: #fff;
|
||||
color: #121212;
|
||||
resize: vertical;
|
||||
|
||||
&:only-child {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr[data-field-name="userNote"] td > span:first-child {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
tr.rgthree-info-table-break-row td {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
padding: 12px 4px 4px;
|
||||
font-size: 1.2em;
|
||||
|
||||
> small {
|
||||
font-style: italic;
|
||||
opacity: 0.66;
|
||||
}
|
||||
|
||||
&:empty {
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
td .-help {
|
||||
border: 1px solid currentColor;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
line-height: 1;
|
||||
font-size: 11px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
cursor: help;
|
||||
&::before {
|
||||
content: '?';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.rgthree-info-images {
|
||||
list-style:none;
|
||||
padding:0;
|
||||
margin:0;
|
||||
scroll-snap-type: x mandatory;
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
overflow: auto;
|
||||
|
||||
> li {
|
||||
scroll-snap-align: start;
|
||||
max-width: 90%;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
|
||||
.rgthree-info-table {
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rgthree-info-civitai-link {
|
||||
margin: 8px;
|
||||
color: #eee;
|
||||
|
||||
a, a:hover, a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
> svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.rgthree-lora-chooser-dialog {
|
||||
max-width: 100%;
|
||||
|
||||
|
||||
.rgthree-dialog-container-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rgthree-dialog-container-title h2 {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-search {
|
||||
margin-left: auto;
|
||||
border-radius: 50px;
|
||||
width: 50%;
|
||||
max-width: 170px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.rgthree-lora-chooser-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.rgthree-lora-filters-container {
|
||||
svg {width: 16px; height: 16px;}
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-content {
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
}
|
||||
|
||||
.rgthree-button-reset {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
> svg {width: 100%; height: 100%;}
|
||||
|
||||
}
|
||||
|
||||
ul.rgthree-lora-chooser-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: start;
|
||||
justify-content: space-around;
|
||||
|
||||
> li {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
width: 170px;
|
||||
max-width: 100%;
|
||||
margin: 8px 8px 16px;
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
margin: 0;
|
||||
z-index: 2;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(120,120,120,1);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
|
||||
&:checked {
|
||||
opacity: 1;
|
||||
background: #0060df;
|
||||
&::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: inset 100px 100px #fff;
|
||||
clip-path: polygon(40.13% 68.39%, 23.05% 51.31%, 17.83% 48.26%, 12.61% 49.57%, 9.57% 53.04%, 8% 60%, 34.13% 85.87%, 39.82% 89.57%, 45.88% 86.73%, 90.66% 32.39%, 88.92% 26.1%, 83.03% 22.17%, 76.94% 22.62%)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
figure {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(120, 120, 120, .8);
|
||||
background: rgba(120, 120, 120, .5);
|
||||
width: 100%;
|
||||
padding-top: 120%;
|
||||
transition: box-shadow 0.15s ease-in-out;
|
||||
opacity: 0.75;
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
&:empty {
|
||||
&::before {
|
||||
content: 'No image.';
|
||||
color: rgba(200, 200, 200, .8);
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
> img, > video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
div {
|
||||
word-wrap: break-word;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
&:hover figure::after{
|
||||
box-shadow: 0px 2px 6px rgba(0,0,0,0.75);
|
||||
}
|
||||
:checked ~ figure::after {
|
||||
box-shadow: 0 0 5px #fff, 0px 0px 15px rgba(49, 131, 255, 0.88), inset 0 0 3px #fff, inset 0px 0px 5px rgba(49, 131, 255, 0.88)
|
||||
}
|
||||
|
||||
&:hover *,
|
||||
&:hover input[type="checkbox"],
|
||||
:checked ~ * {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
|
||||
.rgthree-info-dialog {
|
||||
|
||||
width: 90vw;
|
||||
max-width: 960px;
|
||||
|
||||
.rgthree-info-tags {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
|
||||
> li {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
|
||||
+ li {
|
||||
margin-left: 6px;
|
||||
}
|
||||
&:not(.-link) + li.-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
> * {
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255,255,255,0.85);
|
||||
background: rgb(69, 92, 85);;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
padding-left: .5em;
|
||||
padding-right: .5em;
|
||||
padding-bottom: .1em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
|
||||
> svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
&:first-child {
|
||||
margin-right: .3em;
|
||||
display: none;
|
||||
}
|
||||
&:last-child {
|
||||
margin-left: .5em;
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&[href] {
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,0.25), inset 0px -1px 0px rgba(0,0,0,0.66);
|
||||
}
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.-civitai > * {
|
||||
color: #ddd;
|
||||
background: #1b65aa;
|
||||
transition: all 0.15s ease-in-out;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
border-color: #1971c2;
|
||||
background: #1971c2;
|
||||
}
|
||||
}
|
||||
&.-type > * {
|
||||
background: rgb(73, 54, 94);
|
||||
color: rgb(228, 209, 248);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rgthree-info-table {
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
|
||||
tr.editable button {
|
||||
display: flex;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
svg + svg {display: none;}
|
||||
}
|
||||
tr.editable.-rgthree-editing button {
|
||||
svg {display: none;}
|
||||
svg + svg {display: inline-block;}
|
||||
}
|
||||
|
||||
td {
|
||||
position: relative;
|
||||
border: 1px solid rgba(255,255,255,0.25);
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
|
||||
&:first-child {
|
||||
background: rgba(255,255,255,0.075);
|
||||
width: 10px; // Small, so it doesn't adjust.
|
||||
> *:first-child {
|
||||
white-space: nowrap;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
small {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
opacity: 0.75;
|
||||
|
||||
> [data-action] {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a, a:hover, a:visited {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 1.3333em;
|
||||
height: 1.3333em;
|
||||
vertical-align: -0.285em;
|
||||
|
||||
&.logo-civitai {
|
||||
margin-right: 0.3333em;
|
||||
}
|
||||
}
|
||||
|
||||
> *:first-child {
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
> input, > textarea{
|
||||
padding: 5px 10px;
|
||||
border: 0;
|
||||
box-shadow: inset 1px 1px 5px 0px rgba(0,0,0,0.5);
|
||||
font: inherit;
|
||||
appearance: none;
|
||||
background: #fff;
|
||||
color: #121212;
|
||||
resize: vertical;
|
||||
|
||||
&:only-child {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr[data-field-name="userNote"] td > span:first-child {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
tr.rgthree-info-table-break-row td {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
padding: 12px 4px 4px;
|
||||
font-size: 1.2em;
|
||||
|
||||
> small {
|
||||
font-style: italic;
|
||||
opacity: 0.66;
|
||||
}
|
||||
|
||||
&:empty {
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
td .-help {
|
||||
border: 1px solid currentColor;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 6px;
|
||||
line-height: 1;
|
||||
font-size: 11px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
cursor: help;
|
||||
&::before {
|
||||
content: '?';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
td > ul.rgthree-info-trained-words-list {
|
||||
list-style: none;
|
||||
padding: 2px 8px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
max-height: 15vh;
|
||||
overflow: auto;
|
||||
|
||||
> li {
|
||||
display: inline-flex;
|
||||
margin: 2px;
|
||||
vertical-align: top;
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255,255,255,0.85);
|
||||
background: rgb(73, 91, 106);
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
max-width: 183px;
|
||||
|
||||
&:hover {
|
||||
background: rgb(68, 109, 142);
|
||||
}
|
||||
|
||||
> svg {
|
||||
width: auto;
|
||||
height: 1.2em;
|
||||
}
|
||||
|
||||
> span {
|
||||
padding-left: .5em;
|
||||
padding-right: .5em;
|
||||
padding-bottom: .1em;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
> small {
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0.5em;
|
||||
background: rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
&.-rgthree-is-selected {
|
||||
background: rgb(42, 126, 193);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rgthree-info-images {
|
||||
list-style:none;
|
||||
padding:0;
|
||||
margin:0;
|
||||
scroll-snap-type: x mandatory;
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
overflow: auto;
|
||||
|
||||
> li {
|
||||
scroll-snap-align: start;
|
||||
max-width: 90%;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
|
||||
.rgthree-info-table {
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rgthree-info-civitai-link {
|
||||
margin: 8px;
|
||||
color: #eee;
|
||||
|
||||
a, a:hover, a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
> svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.rgthree-lora-chooser-dialog {
|
||||
max-width: 100%;
|
||||
|
||||
|
||||
.rgthree-dialog-container-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rgthree-dialog-container-title h2 {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-search {
|
||||
margin-left: auto;
|
||||
border-radius: 50px;
|
||||
width: 50%;
|
||||
max-width: 170px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.rgthree-lora-chooser-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.rgthree-lora-filters-container {
|
||||
svg {width: 16px; height: 16px;}
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-content {
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
}
|
||||
|
||||
.rgthree-button-reset {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
> svg {width: 100%; height: 100%;}
|
||||
|
||||
}
|
||||
|
||||
ul.rgthree-lora-chooser-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: start;
|
||||
justify-content: space-around;
|
||||
|
||||
> li {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
width: 170px;
|
||||
max-width: 100%;
|
||||
margin: 8px 8px 16px;
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
margin: 0;
|
||||
z-index: 2;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(120,120,120,1);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
|
||||
&:checked {
|
||||
opacity: 1;
|
||||
background: #0060df;
|
||||
&::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: inset 100px 100px #fff;
|
||||
clip-path: polygon(40.13% 68.39%, 23.05% 51.31%, 17.83% 48.26%, 12.61% 49.57%, 9.57% 53.04%, 8% 60%, 34.13% 85.87%, 39.82% 89.57%, 45.88% 86.73%, 90.66% 32.39%, 88.92% 26.1%, 83.03% 22.17%, 76.94% 22.62%)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
figure {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(120, 120, 120, .8);
|
||||
background: rgba(120, 120, 120, .5);
|
||||
width: 100%;
|
||||
padding-top: 120%;
|
||||
transition: box-shadow 0.15s ease-in-out;
|
||||
opacity: 0.75;
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
&:empty {
|
||||
&::before {
|
||||
content: 'No image.';
|
||||
color: rgba(200, 200, 200, .8);
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
> img, > video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
div {
|
||||
word-wrap: break-word;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
&:hover figure::after{
|
||||
box-shadow: 0px 2px 6px rgba(0,0,0,0.75);
|
||||
}
|
||||
:checked ~ figure::after {
|
||||
box-shadow: 0 0 5px #fff, 0px 0px 15px rgba(49, 131, 255, 0.88), inset 0 0 3px #fff, inset 0px 0px 5px rgba(49, 131, 255, 0.88)
|
||||
}
|
||||
|
||||
&:hover *,
|
||||
&:hover input[type="checkbox"],
|
||||
:checked ~ * {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -25,10 +25,17 @@ export type RgthreeModelInfo = {
|
||||
name?: string;
|
||||
type?: string;
|
||||
baseModel?: string;
|
||||
baseModelFile?: string;
|
||||
links?: string[];
|
||||
strengthMin?: number;
|
||||
strengthMax?: number;
|
||||
triggerWords?: string[];
|
||||
trainedWords?: {
|
||||
word: string;
|
||||
count?: number;
|
||||
civitai?: boolean
|
||||
user?: boolean
|
||||
}[];
|
||||
description?: string;
|
||||
sha256?: string;
|
||||
path?: string;
|
||||
|
||||
+121
-56
@@ -1,7 +1,25 @@
|
||||
import { RgthreeDialog } from "../../rgthree/common/dialog.js";
|
||||
import { createElement as $el, empty, appendChildren, getClosestOrSelf, queryOne, } from "../../rgthree/common/utils_dom.js";
|
||||
import { logoCivitai, link, pencilColored, diskColored, } from "../../rgthree/common/media/svgs.js";
|
||||
import { createElement as $el, empty, appendChildren, getClosestOrSelf, queryOne, query, } from "../../rgthree/common/utils_dom.js";
|
||||
import { logoCivitai, link, pencilColored, diskColored } from "../../rgthree/common/media/svgs.js";
|
||||
import { SERVICE as MODEL_INFO_SERVICE } from "../../rgthree/common/model_info_service.js";
|
||||
import { rgthree } from "./rgthree.js";
|
||||
import { generateId } from "../../rgthree/common/shared_utils.js";
|
||||
function injectCss() {
|
||||
const href = "rgthree/common/css/dialog_model_info.css";
|
||||
if (queryOne(`link[href^="${href}"]`)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
const link = $el('link[rel="stylesheet"][type="text/css"]');
|
||||
const timeout = setTimeout(resolve, 1000);
|
||||
link.addEventListener("load", (e) => {
|
||||
clearInterval(timeout);
|
||||
resolve();
|
||||
});
|
||||
link.href = href;
|
||||
document.head.appendChild(link);
|
||||
});
|
||||
}
|
||||
export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
constructor(file) {
|
||||
const dialogOptions = {
|
||||
@@ -19,7 +37,9 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
}
|
||||
async init(file) {
|
||||
var _a, _b;
|
||||
const cssPromise = injectCss();
|
||||
this.modelInfo = await MODEL_INFO_SERVICE.getLora(file, false, false);
|
||||
await cssPromise;
|
||||
this.setContent(this.getInfoContent());
|
||||
this.setTitle(((_a = this.modelInfo) === null || _a === void 0 ? void 0 : _a["name"]) || ((_b = this.modelInfo) === null || _b === void 0 ? void 0 : _b["file"]) || "Unknown");
|
||||
this.attachEvents();
|
||||
@@ -32,57 +52,89 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
}
|
||||
attachEvents() {
|
||||
this.contentElement.addEventListener("click", async (e) => {
|
||||
var _a, _b;
|
||||
const info = this.modelInfo;
|
||||
if (!(info === null || info === void 0 ? void 0 : info.file)) {
|
||||
return;
|
||||
}
|
||||
const target = getClosestOrSelf(e.target, "[data-action]");
|
||||
const action = target === null || target === void 0 ? void 0 : target.getAttribute("data-action");
|
||||
if (action === "fetch-civitai") {
|
||||
this.modelInfo = await MODEL_INFO_SERVICE.refreshLora(info.file);
|
||||
this.setContent(this.getInfoContent());
|
||||
this.setTitle(((_a = this.modelInfo) === null || _a === void 0 ? void 0 : _a["name"]) || ((_b = this.modelInfo) === null || _b === void 0 ? void 0 : _b["file"]) || "Unknown");
|
||||
}
|
||||
else if (action === "edit-row") {
|
||||
const tr = target.closest("tr");
|
||||
const td = queryOne("td:nth-child(2)", tr);
|
||||
const input = td.querySelector("input,textarea");
|
||||
if (!input) {
|
||||
const fieldName = tr.dataset["fieldName"];
|
||||
tr.classList.add("-rgthree-editing");
|
||||
const isTextarea = fieldName === "userNote";
|
||||
const input = $el(`${isTextarea ? "textarea" : 'input[type="text"]'}`, {
|
||||
value: td.textContent,
|
||||
});
|
||||
input.addEventListener("keydown", (e) => {
|
||||
if (!isTextarea && e.key === "Enter") {
|
||||
const modified = saveEditableRow(info, tr, true);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
else if (e.key === "Escape") {
|
||||
const modified = saveEditableRow(info, tr, false);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
appendChildren(empty(td), [input]);
|
||||
input.focus();
|
||||
}
|
||||
else if (target.nodeName.toLowerCase() === "button") {
|
||||
const modified = saveEditableRow(info, tr, true);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!target || !action) {
|
||||
return;
|
||||
}
|
||||
await this.handleEventAction(action, target, e);
|
||||
});
|
||||
}
|
||||
async handleEventAction(action, target, e) {
|
||||
var _a, _b;
|
||||
const info = this.modelInfo;
|
||||
if (!(info === null || info === void 0 ? void 0 : info.file)) {
|
||||
return;
|
||||
}
|
||||
if (action === "fetch-civitai") {
|
||||
this.modelInfo = await MODEL_INFO_SERVICE.refreshLora(info.file);
|
||||
this.setContent(this.getInfoContent());
|
||||
this.setTitle(((_a = this.modelInfo) === null || _a === void 0 ? void 0 : _a["name"]) || ((_b = this.modelInfo) === null || _b === void 0 ? void 0 : _b["file"]) || "Unknown");
|
||||
}
|
||||
else if (action === "copy-trained-words") {
|
||||
const selected = query(".-rgthree-is-selected", target.closest("tr"));
|
||||
const text = selected.map((el) => el.getAttribute("data-word")).join(", ");
|
||||
await navigator.clipboard.writeText(text);
|
||||
rgthree.showMessage({
|
||||
id: "copy-trained-words-" + generateId(4),
|
||||
type: "success",
|
||||
message: `Successfully copied ${selected.length} key word${selected.length === 1 ? "" : "s"}.`,
|
||||
timeout: 4000,
|
||||
});
|
||||
}
|
||||
else if (action === "toggle-trained-word") {
|
||||
target === null || target === void 0 ? void 0 : target.classList.toggle("-rgthree-is-selected");
|
||||
const tr = target.closest("tr");
|
||||
if (tr) {
|
||||
const span = queryOne("td:first-child > *", tr);
|
||||
let small = queryOne("small", span);
|
||||
if (!small) {
|
||||
small = $el("small", { parent: span });
|
||||
}
|
||||
const num = query(".-rgthree-is-selected", tr).length;
|
||||
small.innerHTML = num
|
||||
? `${num} selected | <span role="button" data-action="copy-trained-words">Copy</span>`
|
||||
: "";
|
||||
}
|
||||
}
|
||||
else if (action === "edit-row") {
|
||||
const tr = target.closest("tr");
|
||||
const td = queryOne("td:nth-child(2)", tr);
|
||||
const input = td.querySelector("input,textarea");
|
||||
if (!input) {
|
||||
const fieldName = tr.dataset["fieldName"];
|
||||
tr.classList.add("-rgthree-editing");
|
||||
const isTextarea = fieldName === "userNote";
|
||||
const input = $el(`${isTextarea ? "textarea" : 'input[type="text"]'}`, {
|
||||
value: td.textContent,
|
||||
});
|
||||
input.addEventListener("keydown", (e) => {
|
||||
if (!isTextarea && e.key === "Enter") {
|
||||
const modified = saveEditableRow(info, tr, true);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
else if (e.key === "Escape") {
|
||||
const modified = saveEditableRow(info, tr, false);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
appendChildren(empty(td), [input]);
|
||||
input.focus();
|
||||
}
|
||||
else if (target.nodeName.toLowerCase() === "button") {
|
||||
const modified = saveEditableRow(info, tr, true);
|
||||
this.modifiedModelData = this.modifiedModelData || modified;
|
||||
}
|
||||
e === null || e === void 0 ? void 0 : e.preventDefault();
|
||||
e === null || e === void 0 ? void 0 : e.stopPropagation();
|
||||
}
|
||||
}
|
||||
getInfoContent() {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
||||
const info = this.modelInfo || {};
|
||||
const civitaiLink = (_a = info.links) === null || _a === void 0 ? void 0 : _a.find((i) => i.includes("civitai.com/models"));
|
||||
const html = `
|
||||
@@ -109,18 +161,18 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
: !((_h = info.raw) === null || _h === void 0 ? void 0 : _h.civitai)
|
||||
? infoTableRow("Civitai", `<button data-action="fetch-civitai">Fetch info from civitai</button>`)
|
||||
: ""}
|
||||
${infoTableRow("Base Model", info.baseModel || "")}
|
||||
${infoTableRow("Base Model", (info.baseModel || " ") + (info.baseModelFile ? `(${info.baseModelFile})` : ""))}
|
||||
${infoTableRow("Name", info.name || ((_k = (_j = info.raw) === null || _j === void 0 ? void 0 : _j.metadata) === null || _k === void 0 ? void 0 : _k.ss_output_name) || "", "The name for display.", "name")}
|
||||
|
||||
${infoTableRow("Name", info.name || "", "The name for display.", "name")}
|
||||
${infoTableRow("Trigger Words", (_k = (_j = info.triggerWords) === null || _j === void 0 ? void 0 : _j.join(", ")) !== null && _k !== void 0 ? _k : "", "Easily keep track of the trigger words to reference here.", "triggerWords")}
|
||||
${infoTableRow("Strength Min", (_l = info.strengthMin) !== null && _l !== void 0 ? _l : "", "The recommended minimum strength, In the Power Lora Loader node, strength will signal when it is below this threshold.", "strengthMin")}
|
||||
${infoTableRow("Strength Max", (_m = info.strengthMax) !== null && _m !== void 0 ? _m : "", "The recommended maximum strength. In the Power Lora Loader node, strength will signal when it is above this threshold.", "strengthMax")}
|
||||
${infoTableRow("Trained Words", (_l = getTrainedWordsMarkup(info.trainedWords)) !== null && _l !== void 0 ? _l : "", "Trained words from the metadata and/or civitai. Click to select for copy.")}
|
||||
${infoTableRow("Strength Min", (_m = info.strengthMin) !== null && _m !== void 0 ? _m : "", "The recommended minimum strength, In the Power Lora Loader node, strength will signal when it is below this threshold.", "strengthMin")}
|
||||
${infoTableRow("Strength Max", (_o = info.strengthMax) !== null && _o !== void 0 ? _o : "", "The recommended maximum strength. In the Power Lora Loader node, strength will signal when it is above this threshold.", "strengthMax")}
|
||||
${""}
|
||||
${infoTableRow("Additional Notes", (_o = info.userNote) !== null && _o !== void 0 ? _o : "", "Additional notes you'd like to keep and reference in the info dialog.", "userNote")}
|
||||
${infoTableRow("Additional Notes", (_p = info.userNote) !== null && _p !== void 0 ? _p : "", "Additional notes you'd like to keep and reference in the info dialog.", "userNote")}
|
||||
|
||||
</table>
|
||||
|
||||
<ul class="rgthree-info-images">${(_q = (_p = info.images) === null || _p === void 0 ? void 0 : _p.map((img) => {
|
||||
<ul class="rgthree-info-images">${(_r = (_q = info.images) === null || _q === void 0 ? void 0 : _q.map((img) => {
|
||||
var _a;
|
||||
return `
|
||||
<li>
|
||||
@@ -146,7 +198,7 @@ export class RgthreeInfoDialog extends RgthreeDialog {
|
||||
: ""}
|
||||
</table-->
|
||||
</li>`;
|
||||
}).join("")) !== null && _q !== void 0 ? _q : ""}</ul>
|
||||
}).join("")) !== null && _r !== void 0 ? _r : ""}</ul>
|
||||
`;
|
||||
const div = $el("div", { html });
|
||||
return div;
|
||||
@@ -156,12 +208,25 @@ function infoTableRow(name, value, help = "", editableFieldName = "") {
|
||||
return `
|
||||
<tr class="${editableFieldName ? "editable" : ""}" ${editableFieldName ? `data-field-name="${editableFieldName}"` : ""}>
|
||||
<td><span>${name} ${help ? `<span class="-help" title="${help}"></span>` : ""}<span></td>
|
||||
<td ${editableFieldName ? "" : 'colspan="2"'}><span>${value}</span></td>
|
||||
<td ${editableFieldName ? "" : 'colspan="2"'}>${String(value).startsWith("<") ? value : `<span>${value}<span>`}</td>
|
||||
${editableFieldName
|
||||
? `<td style="width: 24px;"><button class="rgthree-button-reset rgthree-button-edit" data-action="edit-row">${pencilColored}${diskColored}</button></td>`
|
||||
: ""}
|
||||
</tr>`;
|
||||
}
|
||||
function getTrainedWordsMarkup(words) {
|
||||
let markup = `<ul class="rgthree-info-trained-words-list">`;
|
||||
for (const wordData of words || []) {
|
||||
markup += `<li title="${wordData.word}" data-word="${wordData.word}" class="rgthree-info-trained-words-list-item" data-action="toggle-trained-word">
|
||||
<span>${wordData.word}</span>
|
||||
${wordData.civitai ? logoCivitai : ""}
|
||||
${wordData.count != null ? `<small>${wordData.count}</small>` : ""}
|
||||
</li>`;
|
||||
}
|
||||
markup += `</ul>`;
|
||||
console.log(markup);
|
||||
return markup;
|
||||
}
|
||||
function saveEditableRow(info, tr, saving = true) {
|
||||
var _a;
|
||||
const fieldName = tr.dataset["fieldName"];
|
||||
|
||||
@@ -336,359 +336,6 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.rgthree-info-dialog {
|
||||
min-width: 600px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li + li {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li:not(.-link) + li.-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * {
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgb(69, 92, 85);
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
padding-bottom: 0.1em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg:first-child {
|
||||
margin-right: 0.3em;
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg:last-child {
|
||||
margin-left: 0.5em;
|
||||
fill: currentColor;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > *[href] {
|
||||
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.25), inset 0px -1px 0px rgba(0, 0, 0, 0.66);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > *:empty {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-civitai > * {
|
||||
color: #ddd;
|
||||
background: #1b65aa;
|
||||
transition: all 0.15s ease-in-out;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-civitai > *:hover {
|
||||
color: #fff;
|
||||
border-color: #1971c2;
|
||||
background: #1971c2;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-type > * {
|
||||
background: rgb(73, 54, 94);
|
||||
color: rgb(228, 209, 248);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table {
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable button {
|
||||
display: flex;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable button svg + svg {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable.-rgthree-editing button svg {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable.-rgthree-editing button svg + svg {
|
||||
display: inline-block;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td {
|
||||
position: relative;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
padding: 0;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child {
|
||||
background: rgba(255, 255, 255, 0.075);
|
||||
width: 10px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child > *:first-child {
|
||||
white-space: nowrap;
|
||||
padding-right: 32px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td a, .rgthree-info-dialog .rgthree-info-table td a:hover, .rgthree-info-dialog .rgthree-info-table td a:visited {
|
||||
color: inherit;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td ul {
|
||||
margin: 0.5em 0;
|
||||
padding: 0 0 0 1em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td svg {
|
||||
width: 1.3333em;
|
||||
height: 1.3333em;
|
||||
vertical-align: -0.285em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td svg.logo-civitai {
|
||||
margin-right: 0.3333em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > *:first-child {
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > input, .rgthree-info-dialog .rgthree-info-table td > textarea {
|
||||
padding: 5px 10px;
|
||||
border: 0;
|
||||
box-shadow: inset 1px 1px 5px 0px rgba(0, 0, 0, 0.5);
|
||||
font: inherit;
|
||||
appearance: none;
|
||||
background: #fff;
|
||||
color: #121212;
|
||||
resize: vertical;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > input:only-child, .rgthree-info-dialog .rgthree-info-table td > textarea:only-child {
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr[data-field-name=userNote] td > span:first-child {
|
||||
white-space: pre;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
padding: 12px 4px 4px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td > small {
|
||||
font-style: italic;
|
||||
opacity: 0.66;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td:empty {
|
||||
padding: 4px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td .-help {
|
||||
border: 1px solid currentColor;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
line-height: 1;
|
||||
font-size: 11px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
cursor: help;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td .-help::before {
|
||||
content: "?";
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
scroll-snap-type: x mandatory;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li {
|
||||
scroll-snap-align: start;
|
||||
max-width: 90%;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li .rgthree-info-table {
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link {
|
||||
margin: 8px;
|
||||
color: #eee;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link a, .rgthree-info-dialog .rgthree-info-civitai-link a:hover, .rgthree-info-dialog .rgthree-info-civitai-link a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.rgthree-lora-chooser-dialog {
|
||||
max-width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-title h2 {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-chooser-search {
|
||||
margin-left: auto;
|
||||
border-radius: 50px;
|
||||
width: 50%;
|
||||
max-width: 170px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-chooser-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-filters-container svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-content {
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-button-reset {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-button-reset > svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: start;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
width: 170px;
|
||||
max-width: 100%;
|
||||
margin: 8px 8px 16px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li label {
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox] {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
margin: 0;
|
||||
z-index: 2;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgb(120, 120, 120);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox]:checked {
|
||||
opacity: 1;
|
||||
background: #0060df;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox]:checked::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: inset 100px 100px #fff;
|
||||
clip-path: polygon(40.13% 68.39%, 23.05% 51.31%, 17.83% 48.26%, 12.61% 49.57%, 9.57% 53.04%, 8% 60%, 34.13% 85.87%, 39.82% 89.57%, 45.88% 86.73%, 90.66% 32.39%, 88.92% 26.1%, 83.03% 22.17%, 76.94% 22.62%);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(120, 120, 120, 0.8);
|
||||
background: rgba(120, 120, 120, 0.5);
|
||||
width: 100%;
|
||||
padding-top: 120%;
|
||||
transition: box-shadow 0.15s ease-in-out;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure:empty::before {
|
||||
content: "No image.";
|
||||
color: rgba(200, 200, 200, 0.8);
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure > img, .rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure > video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li div {
|
||||
word-wrap: break-word;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover figure::after {
|
||||
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li :checked ~ figure::after {
|
||||
box-shadow: 0 0 5px #fff, 0px 0px 15px rgba(49, 131, 255, 0.88), inset 0 0 3px #fff, inset 0px 0px 5px rgba(49, 131, 255, 0.88);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover *, .rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover input[type=checkbox],
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li :checked ~ * {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { NodeTypesString } from "./constants.js";
|
||||
import { RgthreeProgressBar } from "../../rgthree/common/progress_bar.js";
|
||||
import { RgthreeConfigDialog } from "./config.js";
|
||||
import { iconGear, iconReplace, iconStarFilled, logoRgthree } from "../../rgthree/common/media/svgs.js";
|
||||
import { query } from "../../rgthree/common/utils_dom.js";
|
||||
export var LogLevel;
|
||||
(function (LogLevel) {
|
||||
LogLevel[LogLevel["IMPORTANT"] = 1] = "IMPORTANT";
|
||||
@@ -539,6 +540,14 @@ class Rgthree extends EventTarget {
|
||||
container.classList.add("rgthree-top-messages-container");
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
const dialogs = query('dialog[open]');
|
||||
if (dialogs.length) {
|
||||
let dialog = dialogs[dialogs.length - 1];
|
||||
dialog.appendChild(container);
|
||||
dialog.addEventListener('close', (e) => {
|
||||
document.body.appendChild(container);
|
||||
});
|
||||
}
|
||||
await this.hideMessage(data.id);
|
||||
const messageContainer = document.createElement("div");
|
||||
messageContainer.setAttribute("type", data.type || "info");
|
||||
|
||||
@@ -122,356 +122,3 @@
|
||||
body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-container) {
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.rgthree-info-dialog {
|
||||
min-width: 600px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li + li {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li:not(.-link) + li.-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * {
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgb(69, 92, 85);
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
padding-bottom: 0.1em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg:first-child {
|
||||
margin-right: 0.3em;
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg:last-child {
|
||||
margin-left: 0.5em;
|
||||
fill: currentColor;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > *[href] {
|
||||
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.25), inset 0px -1px 0px rgba(0, 0, 0, 0.66);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > *:empty {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-civitai > * {
|
||||
color: #ddd;
|
||||
background: #1b65aa;
|
||||
transition: all 0.15s ease-in-out;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-civitai > *:hover {
|
||||
color: #fff;
|
||||
border-color: #1971c2;
|
||||
background: #1971c2;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-type > * {
|
||||
background: rgb(73, 54, 94);
|
||||
color: rgb(228, 209, 248);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table {
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable button {
|
||||
display: flex;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable button svg + svg {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable.-rgthree-editing button svg {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable.-rgthree-editing button svg + svg {
|
||||
display: inline-block;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td {
|
||||
position: relative;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
padding: 0;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child {
|
||||
background: rgba(255, 255, 255, 0.075);
|
||||
width: 10px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child > *:first-child {
|
||||
white-space: nowrap;
|
||||
padding-right: 32px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td a, .rgthree-info-dialog .rgthree-info-table td a:hover, .rgthree-info-dialog .rgthree-info-table td a:visited {
|
||||
color: inherit;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td ul {
|
||||
margin: 0.5em 0;
|
||||
padding: 0 0 0 1em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td svg {
|
||||
width: 1.3333em;
|
||||
height: 1.3333em;
|
||||
vertical-align: -0.285em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td svg.logo-civitai {
|
||||
margin-right: 0.3333em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > *:first-child {
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > input, .rgthree-info-dialog .rgthree-info-table td > textarea {
|
||||
padding: 5px 10px;
|
||||
border: 0;
|
||||
box-shadow: inset 1px 1px 5px 0px rgba(0, 0, 0, 0.5);
|
||||
font: inherit;
|
||||
appearance: none;
|
||||
background: #fff;
|
||||
color: #121212;
|
||||
resize: vertical;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > input:only-child, .rgthree-info-dialog .rgthree-info-table td > textarea:only-child {
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr[data-field-name=userNote] td > span:first-child {
|
||||
white-space: pre;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
padding: 12px 4px 4px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td > small {
|
||||
font-style: italic;
|
||||
opacity: 0.66;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td:empty {
|
||||
padding: 4px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td .-help {
|
||||
border: 1px solid currentColor;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 50%;
|
||||
margin-top: -7px;
|
||||
line-height: 1;
|
||||
font-size: 11px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
cursor: help;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td .-help::before {
|
||||
content: "?";
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
scroll-snap-type: x mandatory;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li {
|
||||
scroll-snap-align: start;
|
||||
max-width: 90%;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li .rgthree-info-table {
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link {
|
||||
margin: 8px;
|
||||
color: #eee;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link a, .rgthree-info-dialog .rgthree-info-civitai-link a:hover, .rgthree-info-dialog .rgthree-info-civitai-link a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.rgthree-lora-chooser-dialog {
|
||||
max-width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-title h2 {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-chooser-search {
|
||||
margin-left: auto;
|
||||
border-radius: 50px;
|
||||
width: 50%;
|
||||
max-width: 170px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-chooser-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-filters-container svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-content {
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-button-reset {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-button-reset > svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: start;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
width: 170px;
|
||||
max-width: 100%;
|
||||
margin: 8px 8px 16px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li label {
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox] {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
margin: 0;
|
||||
z-index: 2;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgb(120, 120, 120);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox]:checked {
|
||||
opacity: 1;
|
||||
background: #0060df;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox]:checked::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: inset 100px 100px #fff;
|
||||
clip-path: polygon(40.13% 68.39%, 23.05% 51.31%, 17.83% 48.26%, 12.61% 49.57%, 9.57% 53.04%, 8% 60%, 34.13% 85.87%, 39.82% 89.57%, 45.88% 86.73%, 90.66% 32.39%, 88.92% 26.1%, 83.03% 22.17%, 76.94% 22.62%);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(120, 120, 120, 0.8);
|
||||
background: rgba(120, 120, 120, 0.5);
|
||||
width: 100%;
|
||||
padding-top: 120%;
|
||||
transition: box-shadow 0.15s ease-in-out;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure:empty::before {
|
||||
content: "No image.";
|
||||
color: rgba(200, 200, 200, 0.8);
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure > img, .rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure > video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li div {
|
||||
word-wrap: break-word;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover figure::after {
|
||||
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li :checked ~ figure::after {
|
||||
box-shadow: 0 0 5px #fff, 0px 0px 15px rgba(49, 131, 255, 0.88), inset 0 0 3px #fff, inset 0px 0px 5px rgba(49, 131, 255, 0.88);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover *, .rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover input[type=checkbox],
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li :checked ~ * {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
.rgthree-info-dialog {
|
||||
width: 90vw;
|
||||
max-width: 960px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li + li {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li:not(.-link) + li.-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * {
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgb(69, 92, 85);
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
padding-bottom: 0.1em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg:first-child {
|
||||
margin-right: 0.3em;
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > * > svg:last-child {
|
||||
margin-left: 0.5em;
|
||||
fill: currentColor;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > *[href] {
|
||||
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.25), inset 0px -1px 0px rgba(0, 0, 0, 0.66);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li > *:empty {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-civitai > * {
|
||||
color: #ddd;
|
||||
background: #1b65aa;
|
||||
transition: all 0.15s ease-in-out;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-civitai > *:hover {
|
||||
color: #fff;
|
||||
border-color: #1971c2;
|
||||
background: #1971c2;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-tags > li.-type > * {
|
||||
background: rgb(73, 54, 94);
|
||||
color: rgb(228, 209, 248);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table {
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable button {
|
||||
display: flex;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable button svg + svg {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable.-rgthree-editing button svg {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable.-rgthree-editing button svg + svg {
|
||||
display: inline-block;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td {
|
||||
position: relative;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child {
|
||||
background: rgba(255, 255, 255, 0.075);
|
||||
width: 10px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child > *:first-child {
|
||||
white-space: nowrap;
|
||||
padding-right: 32px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child small {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child small > [data-action] {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child small > [data-action]:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td a, .rgthree-info-dialog .rgthree-info-table td a:hover, .rgthree-info-dialog .rgthree-info-table td a:visited {
|
||||
color: inherit;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td svg {
|
||||
width: 1.3333em;
|
||||
height: 1.3333em;
|
||||
vertical-align: -0.285em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td svg.logo-civitai {
|
||||
margin-right: 0.3333em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > *:first-child {
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > input, .rgthree-info-dialog .rgthree-info-table td > textarea {
|
||||
padding: 5px 10px;
|
||||
border: 0;
|
||||
box-shadow: inset 1px 1px 5px 0px rgba(0, 0, 0, 0.5);
|
||||
font: inherit;
|
||||
appearance: none;
|
||||
background: #fff;
|
||||
color: #121212;
|
||||
resize: vertical;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > input:only-child, .rgthree-info-dialog .rgthree-info-table td > textarea:only-child {
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr[data-field-name=userNote] td > span:first-child {
|
||||
white-space: pre;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
padding: 12px 4px 4px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td > small {
|
||||
font-style: italic;
|
||||
opacity: 0.66;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td:empty {
|
||||
padding: 4px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td .-help {
|
||||
border: 1px solid currentColor;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 6px;
|
||||
line-height: 1;
|
||||
font-size: 11px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
cursor: help;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td .-help::before {
|
||||
content: "?";
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list {
|
||||
list-style: none;
|
||||
padding: 2px 8px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
max-height: 15vh;
|
||||
overflow: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li {
|
||||
display: inline-flex;
|
||||
margin: 2px;
|
||||
vertical-align: top;
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgb(73, 91, 106);
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
max-width: 183px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li:hover {
|
||||
background: rgb(68, 109, 142);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li > svg {
|
||||
width: auto;
|
||||
height: 1.2em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li > span {
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
padding-bottom: 0.1em;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li > small {
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0.5em;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li.-rgthree-is-selected {
|
||||
background: rgb(42, 126, 193);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
scroll-snap-type: x mandatory;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li {
|
||||
scroll-snap-align: start;
|
||||
max-width: 90%;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li .rgthree-info-table {
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link {
|
||||
margin: 8px;
|
||||
color: #eee;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link a, .rgthree-info-dialog .rgthree-info-civitai-link a:hover, .rgthree-info-dialog .rgthree-info-civitai-link a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.rgthree-lora-chooser-dialog {
|
||||
max-width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-title h2 {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-chooser-search {
|
||||
margin-left: auto;
|
||||
border-radius: 50px;
|
||||
width: 50%;
|
||||
max-width: 170px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-chooser-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-filters-container svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-content {
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-button-reset {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-button-reset > svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: start;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
width: 170px;
|
||||
max-width: 100%;
|
||||
margin: 8px 8px 16px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li label {
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox] {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
margin: 0;
|
||||
z-index: 2;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgb(120, 120, 120);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox]:checked {
|
||||
opacity: 1;
|
||||
background: #0060df;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox]:checked::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: inset 100px 100px #fff;
|
||||
clip-path: polygon(40.13% 68.39%, 23.05% 51.31%, 17.83% 48.26%, 12.61% 49.57%, 9.57% 53.04%, 8% 60%, 34.13% 85.87%, 39.82% 89.57%, 45.88% 86.73%, 90.66% 32.39%, 88.92% 26.1%, 83.03% 22.17%, 76.94% 22.62%);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(120, 120, 120, 0.8);
|
||||
background: rgba(120, 120, 120, 0.5);
|
||||
width: 100%;
|
||||
padding-top: 120%;
|
||||
transition: box-shadow 0.15s ease-in-out;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure:empty::before {
|
||||
content: "No image.";
|
||||
color: rgba(200, 200, 200, 0.8);
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure > img, .rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure > video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li div {
|
||||
word-wrap: break-word;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover figure::after {
|
||||
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li :checked ~ figure::after {
|
||||
box-shadow: 0 0 5px #fff, 0px 0px 15px rgba(49, 131, 255, 0.88), inset 0 0 3px #fff, inset 0px 0px 5px rgba(49, 131, 255, 0.88);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover *, .rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover input[type=checkbox],
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li :checked ~ * {
|
||||
opacity: 1;
|
||||
}
|
||||
Reference in New Issue
Block a user