This commit is contained in:
2025-11-24 00:15:32 +08:00
parent 9f7667a475
commit 0eeeb54784
256 changed files with 49494 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
#
# This library is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. This library is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
__version__ = "2.20.2"
def version():
"""
Return the current version of the Studio Library
:rtype: str
"""
return __version__
from studiolibrary import config
from studiolibrary import resource
from studiolibrary.utils import *
from studiolibrary.library import Library
from studiolibrary.libraryitem import LibraryItem
from studiolibrary.main import main

View File

@@ -0,0 +1,94 @@
# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
#
# This library is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. This library is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
import json
_config = None
def get(*args):
"""
Get values from the config.
:rtype: str
"""
global _config
if not _config:
_config = read(paths())
return _config.get(*args)
def set(key, value):
global _config
if not _config:
_config = read(paths())
_config[key] = value
def paths():
"""
Return all possible config paths.
:rtype: list[str]
"""
cwd = os.path.dirname(__file__)
paths_ = [os.path.join(cwd, "config", "default.json")]
path = os.environ.get("STUDIO_LIBRARY_CONFIG_PATH")
path = path or os.path.join(cwd, "config", "config.json")
if not os.path.exists(path):
cwd = os.path.dirname(os.path.dirname(cwd))
path = os.path.join(cwd, "config", "config.json")
if os.path.exists(path):
paths_.append(path)
return paths_
def read(paths):
"""
Read all paths and overwrite the keys with each successive file.
A custom config parser for passing JSON files.
We use this instead of the standard ConfigParser as the JSON format
can support list and dict types.
This parser can also support comments using the following style "//"
:type paths: list[str]
:rtype: dict
"""
conf = {}
for path in paths:
lines = []
with open(path) as f:
for line in f.readlines():
if not line.strip().startswith('//'):
lines.append(line)
data = '\n'.join(lines)
if data:
conf.update(json.loads(data))
return conf

View File

@@ -0,0 +1,61 @@
// This is the default config file and should NOT be changed.
//
// There are two ways to create a custom config.
//
// 1. You can create a "config.json" at repo/config/config.json.
// This file will override any keys in this default.json file
// and will be ignored by git.
//
// 2. The other way is to create an environment variable with the name
// STUDIO_LIBRARY_CONFIG_PATH. The value of this variable should be the
// full path to your config.json file.
//
// 3. Or you could use code to modify the config before loading the window.
// import studiolibrary
// studiolibrary.config.set("recursiveSearchDepth", 6)
// studiolibrary.main()
{
// The database path is used for caching the library items.
// You can use environment variables within the path. eg: {HOME}
"databasePath": "{root}/.studiolibrary/database.json",
// The temp location used for saving out items and thumbnails
"tempPath": "{temp}/StudioLibrary/{user}",
// The metadata path used for each item. Used for tags, item color etc
// eg: /library/data/animation/nemo/.metadata
"metadataPath": "{path}/.studiolibrary/metadata.json",
// Used for saving persistent user data
"settingsPath": "{local}/StudioLibrary/LibraryWidget.json",
// The maximum walking depth from the root directory
"recursiveSearchDepth": 5,
// A list of paths to ignore when walking the root directory
"ignorePaths": ["/."],
// The command used to show a path in the file explorer
//"showInFolderCmd": "konqueror \"{path}\"&",
// Enables the scale factor option in the setting dialog
// This might be useful when using high-DPI devices like a 4k monitor
"scaleFactorEnabled": true,
// Check if there are any new versions available on start up
"checkForUpdatesEnabled": true,
// A list of the default item plugins
"itemRegistry": [
// This is an example item for development
// "studiolibrarymaya.exampleitem.ExampleItem",
// The maya file item is in development
// "studiolibrarymaya.mayafileitem.MayaFileItem",
"studiolibrarymaya.poseitem.PoseItem",
"studiolibrarymaya.animitem.AnimItem",
"studiolibrarymaya.mirroritem.MirrorItem",
"studiolibrarymaya.setsitem.SetsItem",
"studiolibrary.folderitem.FolderItem"
]
}

View File

@@ -0,0 +1,367 @@
# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
#
# This library is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. This library is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
from datetime import datetime
from studiovendor.Qt import QtGui
from studiovendor.Qt import QtCore
from studiovendor.Qt import QtWidgets
import studioqt
import studiolibrary
import studiolibrary.widgets
class FolderItem(studiolibrary.LibraryItem):
NAME = "Folder"
TYPE = "Folder"
MENU_ORDER = 0 # Show at the top of the menu
SYNC_ORDER = 100 # Last item to run when syncing
LOAD_WIDGET_CLASS = studiolibrary.widgets.PreviewWidget
ENABLE_NESTED_ITEMS = True
ICON_PATH = studiolibrary.resource.get("icons", "folder.svg")
TYPE_ICON_PATH = "" # Don't show a type icon for the folder item
THUMBNAIL_PATH = studiolibrary.resource.get("icons", "folder_item.png")
DEFAULT_ICON_COLOR = "rgba(150,150,150,100)"
DEFAULT_ICON_COLORS = [
"rgb(239, 112, 99)",
"rgb(239, 207, 103)",
"rgb(136, 200, 101)",
"rgb(111, 183, 239)",
"rgb(199, 142, 220)",
DEFAULT_ICON_COLOR,
]
DEFAULT_ICONS = [
"folder.svg",
"user.svg",
"character.svg",
"users.svg",
"inbox.svg",
"favorite.svg",
"shot.svg",
"asset.svg",
"assets.svg",
"cloud.svg",
"book.svg",
"archive.svg",
"circle.svg",
"share.svg",
"tree.svg",
"environment.svg",
"vehicle.svg",
"trash.svg",
"layers.svg",
"database.svg",
"video.svg",
"face.svg",
"hand.svg",
"globe.svg",
]
_THUMBNAIL_ICON_CACHE = {}
@classmethod
def match(cls, path):
"""
Return True if the given path is supported by the item.
:type path: str
:rtype: bool
"""
if os.path.isdir(path):
return True
def itemData(self):
"""
Reimplementing this method to set a trash folder icon.
:rtype: dict
"""
data = super(FolderItem, self).itemData()
if self.path().endswith("Trash") and not data.get("icon"):
data["icon"] = "trash.svg"
return data
def updatePermissionsEnabled(self):
return True
def updateMetadata(self, metadata):
"""
Overriding this method to support updating the library widget directly.
:type metadata: dict
"""
super(FolderItem, self).updateMetadata(metadata)
if self.libraryWindow():
self.libraryWindow().setFolderData(self.path(), self.itemData())
self.updateIcon()
def doubleClicked(self):
"""Overriding this method to show the items contained in the folder."""
self.libraryWindow().selectFolderPath(self.path())
def createOverwriteMenu(self, menu):
"""
Overwriting this method to ignore/hide the overwrite menu action.
:type menu: QtWidgets.QMenu
"""
pass
def _showPreviewFromMenu(self):
self.libraryWindow().itemsWidget().clearSelection()
self.showPreviewWidget(self.libraryWindow())
def contextEditMenu(self, menu, items=None):
"""
Called when creating the context menu for the item.
:type menu: QtWidgets.QMenu
:type items: list[FolderItem] or None
"""
super(FolderItem, self).contextEditMenu(menu, items=items)
action = QtWidgets.QAction("Show in Preview", menu)
action.triggered.connect(self._showPreviewFromMenu)
menu.addAction(action)
menu.addSeparator()
action = studiolibrary.widgets.colorpicker.ColorPickerAction(menu)
action.picker().setColors(self.DEFAULT_ICON_COLORS)
action.picker().colorChanged.connect(self.setIconColor)
action.picker().setCurrentColor(self.iconColor())
action.picker().menuButton().hide()
menu.addAction(action)
iconName = self.itemData().get("icon", "")
action = studiolibrary.widgets.iconpicker.IconPickerAction(menu)
action.picker().setIcons(self.DEFAULT_ICONS)
action.picker().setCurrentIcon(iconName)
action.picker().iconChanged.connect(self.setCustomIcon)
action.picker().menuButton().hide()
menu.addAction(action)
def iconColor(self):
"""
Get the icon color for the folder item.
:rtype: str
"""
return self.itemData().get("color", "")
def setIconColor(self, color):
"""
Set the icon color for the folder item.
:type color: str
"""
if color == self.DEFAULT_ICON_COLOR:
color = ""
self.updateMetadata({"color": color})
def customIconPath(self):
"""
Get the icon for the folder item.
:rtype: str
"""
return self.itemData().get("icon", "")
def setCustomIcon(self, name):
"""
Set the icon for the folder item.
:type name: str
"""
if name == "folder.svg":
name = ""
self.updateMetadata({"icon": name})
def thumbnailIcon(self):
"""
Overriding this method add support for dynamic icon colors.
:rtype: QtGui.QIcon
"""
customPath = self.customIconPath()
if customPath and "/" not in customPath and "\\" not in customPath:
customPath = studiolibrary.resource.get("icons", customPath)
color = self.iconColor()
if not color:
color = self.DEFAULT_ICON_COLOR
key = customPath + color
icon = self._THUMBNAIL_ICON_CACHE.get(key)
if not icon:
color1 = studioqt.Color.fromString(color)
pixmap1 = studioqt.Pixmap(self.THUMBNAIL_PATH)
pixmap1.setColor(color1)
pixmap1 = pixmap1.scaled(
128,
128,
QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation
)
color2 = studioqt.Color.fromString("rgba(255,255,255,150)")
pixmap2 = studioqt.Pixmap(customPath)
pixmap2.setColor(color2)
pixmap2 = pixmap2.scaled(
64,
64,
QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation
)
x = (128 - pixmap2.width()) / 2
y = (128 - pixmap2.height()) / 2
painter = QtGui.QPainter(pixmap1)
painter.drawPixmap(x, y+5, pixmap2)
painter.end()
icon = studioqt.Icon(pixmap1)
self._THUMBNAIL_ICON_CACHE[key] = icon
return self._THUMBNAIL_ICON_CACHE.get(key)
def loadValidator(self, **kwargs):
"""
The validator used for validating the load arguments.
:type kwargs: dict
"""
if kwargs.get("fieldChanged") == "color":
self.setIconColor(kwargs.get("color"))
if kwargs.get("fieldChanged") == "icon":
self.setCustomIcon(kwargs.get("icon"))
def loadSchema(self):
"""
Get the info to display to user.
:rtype: list[dict]
"""
created = os.stat(self.path()).st_ctime
created = datetime.fromtimestamp(created).strftime("%Y-%m-%d %H:%M %p")
modified = os.stat(self.path()).st_mtime
modified = datetime.fromtimestamp(modified).strftime("%Y-%m-%d %H:%M %p")
iconName = self.itemData().get("icon", "")
return [
{
"name": "infoGroup",
"title": "Info",
"value": True,
"type": "group",
"persistent": True,
"persistentKey": "BaseItem",
},
{
"name": "name",
"value": self.name()
},
{
"name": "path",
"value": self.path()
},
{
"name": "created",
"value": created,
},
{
"name": "modified",
"value": modified,
},
{
"name": "optionsGroup",
"title": "Options",
"type": "group",
},
{
"name": "color",
"type": "color",
"value": self.iconColor(),
"layout": "vertical",
"label": {"visible": False},
"colors": self.DEFAULT_ICON_COLORS,
},
{
"name": "icon",
"type": "iconPicker",
"value": iconName,
"layout": "vertical",
"label": {"visible": False},
"items": self.DEFAULT_ICONS,
}
]
@classmethod
def showSaveWidget(cls, libraryWindow):
"""
Show the dialog for creating a new folder.
:rtype: None
"""
path = libraryWindow.selectedFolderPath() or libraryWindow.path()
name, button = studiolibrary.widgets.MessageBox.input(
libraryWindow,
"Create folder",
"Create a new folder with the name:",
buttons=[
("Create", QtWidgets.QDialogButtonBox.AcceptRole),
("Cancel", QtWidgets.QDialogButtonBox.RejectRole)
]
)
name = name.strip()
if name and button == "Create":
path = os.path.join(path, name)
item = cls(path, libraryWindow=libraryWindow)
item.safeSave()
if libraryWindow:
libraryWindow.refresh()
libraryWindow.selectFolderPath(path)
def save(self, *args, **kwargs):
"""Adding this method to avoid NotImpementedError."""
pass

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,913 @@
# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
#
# This library is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. This library is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
import shutil
import logging
from functools import partial
from studiovendor.Qt import QtGui
from studiovendor.Qt import QtCore
from studiovendor.Qt import QtWidgets
import studiolibrary
import studiolibrary.widgets
import studiolibrary.librarywindow
import studioqt
logger = logging.getLogger(__name__)
class ItemError(Exception):
""""""
class ItemSaveError(ItemError):
""""""
class ItemLoadError(ItemError):
""""""
class LibraryItemSignals(QtCore.QObject):
""""""
saved = QtCore.Signal(object)
saving = QtCore.Signal(object)
loaded = QtCore.Signal(object)
copied = QtCore.Signal(object, object, object)
deleted = QtCore.Signal(object)
renamed = QtCore.Signal(object, object, object)
dataChanged = QtCore.Signal(object)
# Note: We will be changing the base class in the near future
class LibraryItem(studiolibrary.widgets.Item):
NAME = ""
TYPE = ""
THUMBNAIL_PATH = studiolibrary.resource.get("icons", "thumbnail.png")
EXTENSION = ""
EXTENSIONS = []
ENABLE_DELETE = False
ENABLE_NESTED_ITEMS = False
SYNC_ORDER = 10
MENU_ORDER = 10
SAVE_WIDGET_CLASS = None
LOAD_WIDGET_CLASS = None
_libraryItemSignals = LibraryItemSignals()
saved = _libraryItemSignals.saved
saving = _libraryItemSignals.saving
loaded = _libraryItemSignals.loaded
copied = _libraryItemSignals.renamed
renamed = _libraryItemSignals.renamed
deleted = _libraryItemSignals.deleted
dataChanged = _libraryItemSignals.dataChanged
def createItemData(self):
"""
Called when syncing the given path with the library cache.
:rtype: dict
"""
import studiolibrary.library
path = self.path()
path = studiolibrary.latestVersionPath(path) or path
if studiolibrary.isVersionPath(path):
dirname = os.path.dirname(path)
name = os.path.basename(dirname)
dirname, basename, extension = studiolibrary.splitPath(dirname)
else:
dirname, basename, extension = studiolibrary.splitPath(path)
name = os.path.basename(path)
category = os.path.basename(dirname) or dirname
modified = ""
if os.path.exists(path):
modified = os.path.getmtime(path)
itemData = dict(self.readMetadata())
itemData.update({
"name": name,
"path": path,
"type": self.TYPE or extension,
"folder": dirname,
"category": category,
"modified": modified,
"__class__": self.__class__.__module__ + "." + self.__class__.__name__
})
return itemData
@classmethod
def createAction(cls, menu, libraryWindow):
"""
Return the action to be displayed when the user
ks the "plus" icon.
:type menu: QtWidgets.QMenu
:type libraryWindow: studiolibrary.LibraryWindow
:rtype: QtCore.QAction
"""
if cls.NAME:
icon = QtGui.QIcon(cls.ICON_PATH)
callback = partial(cls.showSaveWidget, libraryWindow)
action = QtWidgets.QAction(icon, cls.NAME, menu)
action.triggered.connect(callback)
return action
@classmethod
def showSaveWidget(cls, libraryWindow, item=None):
"""
Show the create widget for creating a new item.
:type libraryWindow: studiolibrary.LibraryWindow
:type item: studiolibrary.LibraryItem or None
"""
item = item or cls()
widget = cls.SAVE_WIDGET_CLASS(item=item)
libraryWindow.setCreateWidget(widget)
@classmethod
def isValidPath(cls, path):
"""
This method has been deprecated.
Please use LibraryItem.match(cls, path)
:type path: str
:rtype: bool
"""
return cls.match(path)
@classmethod
def match(cls, path):
"""
Return True if the given path location is supported by the item.
:type path: str
:rtype: bool
"""
extensions = cls.EXTENSIONS
if not extensions and cls.EXTENSION:
extensions = [cls.EXTENSION]
for ext in extensions:
if path.endswith(ext):
return True
return False
def __init__(
self,
path="",
library=None,
libraryWindow=None,
):
"""
The LibraryItem class provides an item for use with the LibraryWindow.
:type path: str
:type library: studiolibrary.Library or None
:type libraryWindow: studiolibrary.LibraryWindow or None
"""
super(LibraryItem, self).__init__()
self._path = path
self._modal = None
self._library = None
self._metadata = None
self._libraryWindow = None
self._readOnly = False
self._ignoreExistsDialog = False
if libraryWindow:
self.setLibraryWindow(libraryWindow)
if library:
self.setLibrary(library)
# if path:
# self.setPath(path)
def updatePermissionsEnabled(self):
return False
def setReadOnly(self, readOnly):
"""
Set the item to read only.
:type readOnly: bool
"""
self._readOnly = readOnly
def isReadOnly(self):
"""
Check if the item is read only.
:rtype: bool
"""
if self.isLocked():
return True
return self._readOnly
def isLocked(self):
"""
Check if the item has been locked by the window.
:rtype: bool
"""
locked = False
if self.libraryWindow():
locked = self.libraryWindow().isLocked()
return locked
def isDeletable(self):
"""
Check if the item is deletable.
:rtype: bool
"""
if self.isLocked():
return False
return self.ENABLE_DELETE
def overwrite(self):
"""
Show the save widget with the input fields populated.
"""
self._ignoreExistsDialog = True
widget = self.showSaveWidget(self.libraryWindow(), item=self)
def loadSchema(self):
"""
Get the options used to load the item.
:rtype: list[dict]
"""
return []
def loadValidator(self, **kwargs):
"""
Validate the current load options.
:type kwargs: dict
:rtype: list[dict]
"""
return []
def load(self, *args, **kwargs):
"""
Reimplement this method for loading item data.
:type args: list
:type kwargs: dict
"""
raise NotImplementedError("The load method has not been implemented!")
def id(self):
"""
Return the unique id for the item.
:rtype: str
"""
return self.path()
def showToastMessage(self, text):
"""
A convenience method for showing the toast widget with the given text.
:type text: str
"""
if self.libraryWindow():
self.libraryWindow().showToastMessage(text)
def showErrorDialog(self, title, text):
"""
Convenience method for showing an error dialog to the user.
:type title: str
:type text: str
:rtype: QMessageBox.StandardButton or None
"""
if self.libraryWindow():
self.libraryWindow().showErrorMessage(text)
button = None
if not self._modal:
self._modal = True
try:
button = studiolibrary.widgets.MessageBox.critical(self.libraryWindow(), title, text)
finally:
self._modal = False
return button
def showExceptionDialog(self, title, error):
"""
Convenience method for showing a question dialog to the user.
:type title: str
:type error: Exception
:rtype: QMessageBox.StandardButton
"""
logger.exception(error)
return self.showErrorDialog(title, error)
def showQuestionDialog(self, title, text):
"""
Convenience method for showing a question dialog to the user.
:type title: str
:type text: str
:rtype: QMessageBox.StandardButton
"""
return studiolibrary.widgets.MessageBox.question(self.libraryWindow(), title, text)
def thumbnailPath(self):
"""
Return the thumbnail location on disc for this item.
:rtype: str
"""
thumbnailPath = self.path() + "/thumbnail.jpg"
if os.path.exists(thumbnailPath):
return thumbnailPath
thumbnailPath = thumbnailPath.replace(".jpg", ".png")
if os.path.exists(thumbnailPath):
return thumbnailPath
return self.THUMBNAIL_PATH
def isTHUMBNAIL_PATH(self):
"""
Check if the thumbnail path is the default path.
:rtype: bool
"""
return self.thumbnailPath() == self.THUMBNAIL_PATH
def showPreviewWidget(self, libraryWindow):
"""
Show the preview Widget for the item instance.
:type libraryWindow: studiolibrary.LibraryWindow
"""
widget = self.previewWidget(libraryWindow)
libraryWindow.setPreviewWidget(widget)
def previewWidget(self, libraryWindow):
"""
Return the widget to be shown when the user clicks on the item.
:type libraryWindow: studiolibrary.LibraryWindow
:rtype: QtWidgets.QWidget or None
"""
widget = None
if self.LOAD_WIDGET_CLASS:
widget = self.LOAD_WIDGET_CLASS(item=self)
return widget
def isVersionPath(self):
return studiolibrary.isVersionPath(self.path())
def contextEditMenu(self, menu, items=None):
"""
Called when the user would like to edit the item from the menu.
The given menu is shown as a submenu of the main context menu.
:type menu: QtWidgets.QMenu
:type items: list[LibraryItem] or None
"""
# Adding a blank icon fixes the text alignment issue when using Qt 5.12.+
icon = studiolibrary.resource.icon("blank")
enabled = not self.isVersionPath()
action = QtWidgets.QAction("Rename", menu)
action.setEnabled(enabled)
action.setIcon(icon)
action.triggered.connect(self.showRenameDialog)
menu.addAction(action)
action = QtWidgets.QAction("Move to", menu)
action.setEnabled(enabled)
action.triggered.connect(self.showMoveDialog)
menu.addAction(action)
action = QtWidgets.QAction("Copy Path", menu)
action.triggered.connect(self.copyPathToClipboard)
action.setEnabled(enabled)
menu.addAction(action)
if self.libraryWindow():
action = QtWidgets.QAction("Select Folder", menu)
action.triggered.connect(self.selectFolder)
menu.addAction(action)
action = QtWidgets.QAction("Show in Folder", menu)
action.triggered.connect(self.showInFolder)
menu.addAction(action)
if self.isDeletable():
menu.addSeparator()
action = QtWidgets.QAction("Delete", menu)
action.setEnabled(enabled)
action.triggered.connect(self.showDeleteDialog)
menu.addAction(action)
self.createOverwriteMenu(menu)
def createOverwriteMenu(self, menu):
"""
Create a menu or action to trigger the overwrite method.
:type menu: QtWidgets.QMenu
"""
if not self.isReadOnly():
enabled = not self.isVersionPath()
menu.addSeparator()
action = QtWidgets.QAction("Overwrite", menu)
action.setEnabled(enabled)
action.triggered.connect(self.overwrite)
menu.addAction(action)
def copyPathToClipboard(self):
"""Copy the item path to the system clipboard."""
cb = QtWidgets.QApplication.clipboard()
cb.clear(mode=cb.Clipboard)
cb.setText(self.path(), mode=cb.Clipboard)
def contextMenu(self, menu, items=None):
"""
Called when the user right clicks on the item.
:type menu: QtWidgets.QMenu
:type items: list[LibraryItem]
:rtype: None
"""
pass
def showInFolder(self):
"""Open the file explorer at the given path location."""
path = self.path()
studiolibrary.showInFolder(path)
def selectFolder(self):
"""select the folder in the library widget"""
if self.libraryWindow():
path = '/'.join(studiolibrary.normPath(self.path()).split('/')[:-1])
self.libraryWindow().selectFolderPath(path)
def url(self):
"""Used by the mime data when dragging/dropping the item."""
return QtCore.QUrl("file:///" + self.path())
def setLibraryWindow(self, libraryWindow):
"""
Set the library widget containing the item.
:rtype: studiolibrary.LibraryWindow or None
"""
self._libraryWindow = libraryWindow
def libraryWindow(self):
"""
Return the library widget containing the item.
:rtype: studiolibrary.LibraryWindow or None
"""
return self._libraryWindow
def setLibrary(self, library):
"""
Set the library model for the item.
:type library: studiolibrary.Library
"""
self._library = library
def library(self):
"""
Return the library model for the item.
:rtype: studiolibrary.Library or None
"""
if not self._library and self.libraryWindow():
return self.libraryWindow().library()
return self._library
def setIconPath(self, path):
"""
Set the icon path for the current item.
:type path: str
:rtype: None
"""
self._iconPath = path
def iconPath(self):
"""
Return the icon path for the current item.
:rtype: None
"""
return self._iconPath
def mimeText(self):
"""
:rtype: str
"""
return self.path()
def path(self):
"""
Get the path for the item.
:rtype: str
"""
return self._path
def setPath(self, path):
"""
Set the path for the item.
:rtype: str
"""
self._path = studiolibrary.normPath(path)
def setMetadata(self, metadata):
"""
Set the given metadata for the item.
:type metadata: dict
"""
self._metadata = metadata
def metadata(self):
"""
Get the metadata for the item from disc.
:rtype: dict
"""
return self._metadata
def updateMetadata(self, metadata):
"""
Update the current metadata from disc with the given metadata.
:type metadata: dict
"""
metadata_ = self.readMetadata()
metadata_.update(metadata)
self.saveMetadata(metadata_)
def saveMetadata(self, metadata):
"""
Save the given metadata to disc.
:type metadata: dict
"""
formatString = studiolibrary.config.get('metadataPath')
path = studiolibrary.formatPath(formatString, self.path())
studiolibrary.saveJson(path, metadata)
if self.updatePermissionsEnabled():
self.library().updatePermissions(path)
self.setMetadata(metadata)
self.syncItemData(emitDataChanged=False)
self.dataChanged.emit(self)
def readMetadata(self):
"""
Read the metadata for the item from disc.
:rtype: dict
"""
if self._metadata is None:
formatString = studiolibrary.config.get('metadataPath')
path = studiolibrary.formatPath(formatString, self.path())
if os.path.exists(path):
self._metadata = studiolibrary.readJson(path)
else:
self._metadata = {}
return self._metadata
def syncItemData(self, emitDataChanged=True):
"""Sync the item data to the database."""
data = self.createItemData()
self.setItemData(data)
if self.library():
self.library().saveItemData([self], emitDataChanged=emitDataChanged)
def saveSchema(self):
"""
Get the schema used for saving the item.
:rtype: list[dict]
"""
return []
def saveValidator(self, **fields):
"""
Validate the given save fields.
:type fields: dict
:rtype: list[dict]
"""
return []
@studioqt.showWaitCursor
def safeSave(self, *args, **kwargs):
"""
Safe save the item.
"""
dst = self.path()
if dst and not dst.endswith(self.EXTENSION):
dst += self.EXTENSION
self.setPath(dst)
logger.debug(u'Item Saving: {0}'.format(dst))
self.saving.emit(self)
if os.path.exists(dst):
if studiolibrary.latestVersionPath(self.path()):
raise NameError("You can only save items that were "
"created using Studio Library version 2!")
elif self._ignoreExistsDialog:
self._moveToTrash()
else:
self.showAlreadyExistsDialog()
tmp = studiolibrary.createTempPath(self.__class__.__name__)
self.setPath(tmp)
self.save(*args, **kwargs)
shutil.move(tmp, dst)
self.setPath(dst)
if self.updatePermissionsEnabled():
self.library().updatePermissions(dst)
self.syncItemData()
if self.libraryWindow():
self.libraryWindow().selectItems([self])
self.saved.emit(self)
logger.debug(u'Item Saved: {0}'.format(dst))
def save(self, *args, **kwargs):
"""
Save the item io data to the given path.
:type args: list
:type kwargs: dict
"""
raise NotImplementedError("The save method has not been implemented!")
# -----------------------------------------------------------------
# Support for copy and rename
# -----------------------------------------------------------------
def delete(self):
"""
Delete the item from disc and the library model.
:rtype: None
"""
studiolibrary.removePath(self.path())
if self.library():
self.library().removePath(self.path())
self.deleted.emit(self)
def copy(self, dst):
"""
Make a copy/duplicate the current item to the given destination.
:type dst: str
:rtype: None
"""
src = self.path()
dst = studiolibrary.copyPath(src, dst)
if self.library():
self.library().copyPath(src, dst)
self.copied.emit(self, src, dst)
if self.libraryWindow():
self.libraryWindow().refresh()
def move(self, dst):
"""
Move the current item to the given destination.
:type dst: str
:rtype: None
"""
self.rename(dst)
def rename(self, dst, extension=None):
"""
Rename the current path to the given destination path.
:type dst: str
:type extension: bool or None
:rtype: None
"""
extension = extension or self.EXTENSION
if dst and extension not in dst:
dst += extension
src = self.path()
# Rename the path on the filesystem
dst = studiolibrary.renamePath(src, dst)
# Rename the path inside the library database
if self.library():
self.library().renamePath(src, dst)
self._path = dst
self.syncItemData()
self.renamed.emit(self, src, dst)
def showRenameDialog(self, parent=None):
"""
Show the rename dialog.
:type parent: QtWidgets.QWidget
"""
if self.isVersionPath():
raise NameError("You can only rename items that were "
"created using Studio Library version 2!")
select = False
if self.libraryWindow():
parent = parent or self.libraryWindow()
select = self.libraryWindow().selectedFolderPath() == self.path()
name, button = studiolibrary.widgets.MessageBox.input(
parent,
"Rename item",
"Rename the current item to:",
inputText=self.name(),
buttons=[
("Rename", QtWidgets.QDialogButtonBox.AcceptRole),
("Cancel", QtWidgets.QDialogButtonBox.RejectRole)
]
)
if button == "Rename":
try:
self.rename(name)
if select:
self.libraryWindow().selectFolderPath(self.path())
except Exception as error:
self.showExceptionDialog("Rename Error", error)
raise
return button
def showMoveDialog(self, parent=None):
"""
Show the move to browser dialog.
:type parent: QtWidgets.QWidget
"""
if self.isVersionPath():
raise NameError("You can only move items that were "
"created using Studio Library version 2!")
title = "Move To..."
path = os.path.dirname(os.path.dirname(self.path()))
dst = QtWidgets.QFileDialog.getExistingDirectory(None, title, path)
if dst:
dst = "{}/{}".format(dst, os.path.basename(self.path()))
try:
self.move(dst)
except Exception as error:
self.showExceptionDialog("Move Error", error)
raise
def showDeleteDialog(self):
"""
Show the delete item dialog.
:rtype: None
"""
if self.isVersionPath():
raise NameError("You can only delete items that were "
"created using Studio Library version 2!")
text = 'Are you sure you want to delete this item?'
button = self.showQuestionDialog("Delete Item", text)
if button == QtWidgets.QDialogButtonBox.Yes:
try:
self.delete()
except Exception as error:
self.showExceptionDialog("Delete Error", error)
raise
def showAlreadyExistsDialog(self):
"""
Show a warning dialog if the item already exists on save.
:rtype: None
"""
if self.isVersionPath():
raise NameError("You can only override items that were "
"created using Studio Library version 2!")
if not self.libraryWindow():
raise ItemSaveError("Item already exists!")
title = "Item already exists"
text = 'Would you like to move the existing item "{}" to the trash?'
text = text.format(os.path.basename(self.path()))
buttons = [
QtWidgets.QDialogButtonBox.Yes,
QtWidgets.QDialogButtonBox.Cancel
]
try:
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.ArrowCursor)
button = self.libraryWindow().showQuestionDialog(title, text, buttons)
finally:
QtWidgets.QApplication.restoreOverrideCursor()
if button == QtWidgets.QDialogButtonBox.Yes:
self._moveToTrash()
else:
raise ItemSaveError("You cannot save over an existing item.")
return button
# -----------------------------------------------------------------
# Support for painting the type icon
# -----------------------------------------------------------------
def _moveToTrash(self):
"""
Move the current item to the trash.
This method should only be used when saving.
"""
path = self.path()
library = self.library()
item = studiolibrary.LibraryItem(path, library=library)
self.libraryWindow().moveItemsToTrash([item])
# self.setPath(path)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
#
# This library is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. This library is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import studioqt
import studiolibrary
def main(*args, **kwargs):
"""
Convenience method for creating/showing a library widget instance.
return studiolibrary.LibraryWindow.instance(
name="",
path="",
show=True,
lock=False,
superusers=None,
lockRegExp=None,
unlockRegExp=None
)
:rtype: studiolibrary.LibraryWindow
"""
# Reload all Studio Library modules when Shift is pressed.
# This is for developers to test their changes in a DCC application.
if studioqt.isShiftModifier():
import studiolibrary
studiolibrary.reload()
# Register all the items from the config file.
import studiolibrary
studiolibrary.registerItems()
if studiolibrary.isMaya():
from studiolibrarymaya import mayalibrarywindow
libraryWindow = mayalibrarywindow.MayaLibraryWindow.instance(*args, **kwargs)
else:
from studiolibrary import librarywindow
libraryWindow = librarywindow.LibraryWindow.instance(*args, **kwargs)
return libraryWindow
if __name__ == "__main__":
# Run the Studio Library in a QApplication instance
import studioqt
with studioqt.app():
studiolibrary.main()

View File

@@ -0,0 +1,74 @@
# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
#
# This library is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. This library is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
from studioqt import Icon
from studioqt import Pixmap
from . import utils
PATH = os.path.abspath(__file__)
DIRNAME = os.path.dirname(PATH)
RESOURCE_DIRNAME = os.path.join(DIRNAME, "resource")
def get(*args):
"""
This is a convenience function for returning the resource path.
:rtype: str
"""
path = os.path.join(RESOURCE_DIRNAME, *args)
return utils.normPath(path)
def icon(*args, **kwargs):
"""
Return an Icon object from the given resource name.
:rtype: str
"""
path = get("icons", *args)
return Icon(pixmap(path, **kwargs))
def pixmap(name, scope="icons", extension="png", color=None):
"""
Return a Pixmap object from the given resource name.
:type name: str
:type scope: str
:type extension: str
:type color: str
:rtype: QtWidgets.QPixmap
"""
if name.endswith(".svg"):
extension = ""
path = ""
if os.path.exists(name):
path = name
elif extension:
path = get(scope, name + "." + extension)
if not os.path.exists(path):
path = get(scope, name + ".svg")
p = Pixmap(path)
if color:
p.setColor(color)
return p

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M32 448c0 17.7 14.3 32 32 32h384c17.7 0 32-14.3 32-32V160H32v288zm160-212c0-6.6 5.4-12 12-12h104c6.6 0 12 5.4 12 12v8c0 6.6-5.4 12-12 12H204c-6.6 0-12-5.4-12-12v-8zM480 32H32C14.3 32 0 46.3 0 64v48c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16V64c0-17.7-14.3-32-32-32z"/></svg>

After

Width:  |  Height:  |  Size: 344 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M69.4 210.6C89.8 126.5 165.6 64 256 64c71.1 0 133.1 38.6 166.3 96H368c-8.8 0-16 7.2-16 16s7.2 16 16 16h80.7H464c8.8 0 16-7.2 16-16V80c0-8.8-7.2-16-16-16s-16 7.2-16 16v60.6C408.8 75.5 337.5 32 256 32C149.6 32 60.5 106.2 37.7 205.6C35.5 215.2 43.1 224 53 224c7.9 0 14.6-5.7 16.5-13.4zm373.2 90.9C422.2 385.5 346.4 448 256 448c-71.1 0-133.1-38.6-166.3-96h54.5c8.8 0 16-7.2 16-16s-7.2-16-16-16H63.3 48.2c-8.8 0-16 7.2-16 16v96c0 8.8 7.2 16 16 16s16-7.2 16-16V371.8C103.4 436.6 174.7 480 256 480c106.4 0 195.5-74.2 218.3-173.6c2.2-9.6-5.4-18.4-15.3-18.4c-7.9 0-14.6 5.7-16.5 13.4z"/></svg>

After

Width:  |  Height:  |  Size: 823 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M239.1 6.3l-208 78c-18.7 7-31.1 25-31.1 45v225.1c0 18.2 10.3 34.8 26.5 42.9l208 104c13.5 6.8 29.4 6.8 42.9 0l208-104c16.3-8.1 26.5-24.8 26.5-42.9V129.3c0-20-12.4-37.9-31.1-44.9l-208-78C262 2.2 250 2.2 239.1 6.3zM256 68.4l192 72v1.1l-192 78-192-78v-1.1l192-72zm32 356V275.5l160-65v133.9l-160 80z"/></svg>

After

Width:  |  Height:  |  Size: 374 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M488.6 250.2L392 214V105.5c0-15-9.3-28.4-23.4-33.7l-100-37.5c-8.1-3.1-17.1-3.1-25.3 0l-100 37.5c-14.1 5.3-23.4 18.7-23.4 33.7V214l-96.6 36.2C9.3 255.5 0 268.9 0 283.9V394c0 13.6 7.7 26.1 19.9 32.2l100 50c10.1 5.1 22.1 5.1 32.2 0l103.9-52 103.9 52c10.1 5.1 22.1 5.1 32.2 0l100-50c12.2-6.1 19.9-18.6 19.9-32.2V283.9c0-15-9.3-28.4-23.4-33.7zM358 214.8l-85 31.9v-68.2l85-37v73.3zM154 104.1l102-38.2 102 38.2v.6l-102 41.4-102-41.4v-.6zm84 291.1l-85 42.5v-79.1l85-38.8v75.4zm0-112l-102 41.4-102-41.4v-.6l102-38.2 102 38.2v.6zm240 112l-85 42.5v-79.1l85-38.8v75.4zm0-112l-102 41.4-102-41.4v-.6l102-38.2 102 38.2v.6z"/></svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 80c0-8.8 7.2-16 16-16H432c8.8 0 16 7.2 16 16s-7.2 16-16 16H16C7.2 96 0 88.8 0 80zM0 240c0-8.8 7.2-16 16-16H432c8.8 0 16 7.2 16 16s-7.2 16-16 16H16c-8.8 0-16-7.2-16-16zM448 400c0 8.8-7.2 16-16 16H16c-8.8 0-16-7.2-16-16s7.2-16 16-16H432c8.8 0 16 7.2 16 16z"/></svg>

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M448 358.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16c0-6.4-3.2-12.8-9.6-19.2-3.2-16-3.2-60.8 0-73.6 6.4-3.2 9.6-9.6 9.6-19.2zM272 160l26.66 53.33L352 240l-53.34 26.67L272 320l-26.66-53.33L192 240l53.34-26.67L272 160zM160 96l16-32 16 32 32 16-32 16-16 32-16-32-32-16 32-16zm220.8 352H96c-19.2 0-32-12.8-32-32s16-32 32-32h284.8v64z"/></svg>

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M512 144v288c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V144c0-26.5 21.5-48 48-48h88l12.3-32.9c7-18.7 24.9-31.1 44.9-31.1h125.5c20 0 37.9 12.4 44.9 31.1L376 96h88c26.5 0 48 21.5 48 48zM376 288c0-66.2-53.8-120-120-120s-120 53.8-120 120 53.8 120 120 120 120-53.8 120-120zm-32 0c0 48.5-39.5 88-88 88s-88-39.5-88-88 39.5-88 88-88 88 39.5 88 88zm-120 0c0-17.6 14.4-32 32-32 8.8 0 16-7.2 16-16s-7.2-16-16-16c-35.3 0-64 28.7-64 64 0 8.8 7.2 16 16 16s16-7.2 16-16z"/></svg>

After

Width:  |  Height:  |  Size: 538 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M512 144v288c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V144c0-26.5 21.5-48 48-48h88l12.3-32.9c7-18.7 24.9-31.1 44.9-31.1h125.5c20 0 37.9 12.4 44.9 31.1L376 96h88c26.5 0 48 21.5 48 48zM376 288c0-66.2-53.8-120-120-120s-120 53.8-120 120 53.8 120 120 120 120-53.8 120-120zm-32 0c0 48.5-39.5 88-88 88s-88-39.5-88-88 39.5-88 88-88 88 39.5 88 88z"/></svg>

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"/></svg>

After

Width:  |  Height:  |  Size: 199 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"/></svg>

After

Width:  |  Height:  |  Size: 232 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M64 224h13.5c24.7 56.5 80.9 96 146.5 96s121.8-39.5 146.5-96H384c8.8 0 16-7.2 16-16v-96c0-8.8-7.2-16-16-16h-13.5C345.8 39.5 289.6 0 224 0S102.2 39.5 77.5 96H64c-8.8 0-16 7.2-16 16v96c0 8.8 7.2 16 16 16zm40-88c0-22.1 21.5-40 48-40h144c26.5 0 48 17.9 48 40v24c0 53-43 96-96 96h-48c-53 0-96-43-96-96v-24zm72 72l12-36 36-12-36-12-12-36-12 36-36 12 36 12 12 36zm151.6 113.4C297.7 340.7 262.2 352 224 352s-73.7-11.3-103.6-30.6C52.9 328.5 0 385 0 454.4v9.6c0 26.5 21.5 48 48 48h80v-64c0-17.7 14.3-32 32-32h128c17.7 0 32 14.3 32 32v64h80c26.5 0 48-21.5 48-48v-9.6c0-69.4-52.9-125.9-120.4-133zM272 448c-8.8 0-16 7.2-16 16s7.2 16 16 16 16-7.2 16-16-7.2-16-16-16zm-96 0c-8.8 0-16 7.2-16 16v48h32v-48c0-8.8-7.2-16-16-16z"/></svg>

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z"/></svg>

After

Width:  |  Height:  |  Size: 149 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z"/></svg>

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M448 64V448H576c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32H448zm-32 0H224V448H416V64zM192 448V64H64C46.3 64 32 78.3 32 96V416c0 17.7 14.3 32 32 32H192zM0 96C0 60.7 28.7 32 64 32H576c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96z"/></svg>

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M448 73.143v45.714C448 159.143 347.667 192 224 192S0 159.143 0 118.857V73.143C0 32.857 100.333 0 224 0s224 32.857 224 73.143zM448 176v102.857C448 319.143 347.667 352 224 352S0 319.143 0 278.857V176c48.125 33.143 136.208 48.572 224 48.572S399.874 209.143 448 176zm0 160v102.857C448 479.143 347.667 512 224 512S0 479.143 0 438.857V336c48.125 33.143 136.208 48.572 224 48.572S399.874 369.143 448 336z"/></svg>

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M635.73 406.91l-194.04-297.6c-11.57-17.75-39.8-17.75-51.37 0l-32.84 50.37 67.68 105.68c2.38 3.72 1.3 8.67-2.42 11.05l-13.46 8.62c-3.72 2.38-8.67 1.3-11.05-2.42l-59.9-93.54-70.81-110.55c-12.4-19.36-42.64-19.36-55.04 0L4.58 403.18C-7.99 422.81 6.81 448 30.92 448h580.22c22.5 0 36.32-23.09 24.59-41.09z"/></svg>

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M0 180V56c0-13.3 10.7-24 24-24h124c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H64v84c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12zM288 44v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12V56c0-13.3-10.7-24-24-24H300c-6.6 0-12 5.4-12 12zm148 276h-40c-6.6 0-12 5.4-12 12v84h-84c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24V332c0-6.6-5.4-12-12-12zM160 468v-40c0-6.6-5.4-12-12-12H64v-84c0-6.6-5.4-12-12-12H12c-6.6 0-12 5.4-12 12v124c0 13.3 10.7 24 24 24h124c6.6 0 12-5.4 12-12z"/></svg>

After

Width:  |  Height:  |  Size: 588 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M25.9 3.4C19-2 8.9-.8 3.4 6.1S-.8 23.1 6.1 28.6l608 480c6.9 5.5 17 4.3 22.5-2.6s4.3-17-2.6-22.5L25.9 3.4zM605.5 268.3c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-51.2 0-96 14.8-133.9 36.8l27.3 21.5C244.6 74.2 280.2 64 320 64c70.4 0 127.7 32 170.8 72c43.1 40 71.9 88 85.2 120c-9.2 22.1-25.9 52-49.5 81.5l25.1 19.8c25.6-32 43.7-64.4 53.9-89zM88.4 154.7c-25.6 32-43.7 64.4-53.9 89c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c51.2 0 96-14.8 133.9-36.8l-27.3-21.5C395.4 437.8 359.8 448 320 448c-70.4 0-127.7-32-170.8-72C106.1 336 77.3 288 64 256c9.2-22.1 25.9-52 49.5-81.5L88.4 154.7zM320 384c16.7 0 32.7-3.2 47.4-9.1l-30.9-24.4c-5.4 .9-10.9 1.4-16.5 1.4c-51 0-92.8-39.8-95.8-90.1l-30.9-24.4c-.9 6-1.3 12.2-1.3 18.5c0 70.7 57.3 128 128 128zM448 256c0-70.7-57.3-128-128-128c-16.7 0-32.7 3.2-47.4 9.1l30.9 24.4c5.4-.9 10.9-1.4 16.5-1.4c51 0 92.8 39.8 95.8 90.1l30.9 24.4c.9-6 1.3-12.2 1.3-18.5z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M117.2 136C160.3 96 217.6 64 288 64s127.7 32 170.8 72c43.1 40 71.9 88 85.2 120c-13.3 32-42.1 80-85.2 120c-43.1 40-100.4 72-170.8 72s-127.7-32-170.8-72C74.1 336 45.3 288 32 256c13.3-32 42.1-80 85.2-120zM288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM192 256a96 96 0 1 1 192 0 96 96 0 1 1 -192 0zm224 0a128 128 0 1 0 -256 0 128 128 0 1 0 256 0z"/></svg>

After

Width:  |  Height:  |  Size: 825 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm-160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm194.8 170.2C334.3 380.4 292.5 400 248 400s-86.3-19.6-114.8-53.8c-13.6-16.3 11-36.7 24.6-20.5 22.4 26.9 55.2 42.2 90.2 42.2s67.8-15.4 90.2-42.2c13.4-16.2 38.1 4.2 24.6 20.5z"/></svg>

After

Width:  |  Height:  |  Size: 466 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z"/></svg>

After

Width:  |  Height:  |  Size: 287 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm64 236c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12v8zm0-64c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12v8zm0-72v8c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm96-114.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"/></svg>

After

Width:  |  Height:  |  Size: 557 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm160-14.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"/></svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 71.5C0 49.7 17.7 32 39.5 32H472.5C494.3 32 512 49.7 512 71.5c0 9.2-3.2 18.1-9.1 25.2L320 317.8V446.1c0 18.7-15.2 33.9-33.9 33.9c-7.5 0-14.8-2.5-20.8-7.1l-61-47.4c-7.8-6.1-12.4-15.4-12.4-25.3V317.8L9.1 96.7C3.2 89.6 0 80.7 0 71.5zM39.5 64c-4.2 0-7.5 3.4-7.5 7.5c0 1.8 .6 3.4 1.7 4.8L220.3 301.8c2.4 2.9 3.7 6.5 3.7 10.2v88.2l61 47.4c.3 .3 .7 .4 1.1 .4c1 0 1.9-.8 1.9-1.9V312c0-3.7 1.3-7.3 3.7-10.2L478.3 76.3c1.1-1.3 1.7-3 1.7-4.8c0-4.2-3.4-7.5-7.5-7.5H39.5z"/></svg>

After

Width:  |  Height:  |  Size: 708 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M464 128H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48z"/></svg>

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M572.694 292.093L500.27 416.248A63.997 63.997 0 0 1 444.989 448H45.025c-18.523 0-30.064-20.093-20.731-36.093l72.424-124.155A64 64 0 0 1 152 256h399.964c18.523 0 30.064 20.093 20.73 36.093zM152 224h328v-48c0-26.51-21.49-48-48-48H272l-64-64H48C21.49 64 0 85.49 0 112v278.046l69.077-118.418C86.214 242.25 117.989 224 152 224z"/></svg>

After

Width:  |  Height:  |  Size: 402 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M248 8C111.03 8 0 119.03 0 256s111.03 248 248 248 248-111.03 248-248S384.97 8 248 8zm82.29 357.6c-3.9 3.88-7.99 7.95-11.31 11.28-2.99 3-5.1 6.7-6.17 10.71-1.51 5.66-2.73 11.38-4.77 16.87l-17.39 46.85c-13.76 3-28 4.69-42.65 4.69v-27.38c1.69-12.62-7.64-36.26-22.63-51.25-6-6-9.37-14.14-9.37-22.63v-32.01c0-11.64-6.27-22.34-16.46-27.97-14.37-7.95-34.81-19.06-48.81-26.11-11.48-5.78-22.1-13.14-31.65-21.75l-.8-.72a114.792 114.792 0 0 1-18.06-20.74c-9.38-13.77-24.66-36.42-34.59-51.14 20.47-45.5 57.36-82.04 103.2-101.89l24.01 12.01C203.48 89.74 216 82.01 216 70.11v-11.3c7.99-1.29 16.12-2.11 24.39-2.42l28.3 28.3c6.25 6.25 6.25 16.38 0 22.63L264 112l-10.34 10.34c-3.12 3.12-3.12 8.19 0 11.31l4.69 4.69c3.12 3.12 3.12 8.19 0 11.31l-8 8a8.008 8.008 0 0 1-5.66 2.34h-8.99c-2.08 0-4.08.81-5.58 2.27l-9.92 9.65a8.008 8.008 0 0 0-1.58 9.31l15.59 31.19c2.66 5.32-1.21 11.58-7.15 11.58h-5.64c-1.93 0-3.79-.7-5.24-1.96l-9.28-8.06a16.017 16.017 0 0 0-15.55-3.1l-31.17 10.39a11.95 11.95 0 0 0-8.17 11.34c0 4.53 2.56 8.66 6.61 10.69l11.08 5.54c9.41 4.71 19.79 7.16 30.31 7.16s22.59 27.29 32 32h66.75c8.49 0 16.62 3.37 22.63 9.37l13.69 13.69a30.503 30.503 0 0 1 8.93 21.57 46.536 46.536 0 0 1-13.72 32.98zM417 274.25c-5.79-1.45-10.84-5-14.15-9.97l-17.98-26.97a23.97 23.97 0 0 1 0-26.62l19.59-29.38c2.32-3.47 5.5-6.29 9.24-8.15l12.98-6.49C440.2 193.59 448 223.87 448 256c0 8.67-.74 17.16-1.82 25.54L417 274.25z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M408 216c-22.092 0-40 17.909-40 40h-8v-32c0-22.091-17.908-40-40-40s-40 17.909-40 40v32h-8V48c0-26.51-21.49-48-48-48s-48 21.49-48 48v208h-13.572L92.688 78.449C82.994 53.774 55.134 41.63 30.461 51.324 5.787 61.017-6.356 88.877 3.337 113.551l74.765 190.342-31.09 24.872c-15.381 12.306-19.515 33.978-9.741 51.081l64 112A39.998 39.998 0 0 0 136 512h240c18.562 0 34.686-12.77 38.937-30.838l32-136A39.97 39.97 0 0 0 448 336v-80c0-22.091-17.908-40-40-40z"/></svg>

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M567.938 243.908L462.25 85.374A48.003 48.003 0 0 0 422.311 64H153.689a48 48 0 0 0-39.938 21.374L8.062 243.908A47.994 47.994 0 0 0 0 270.533V400c0 26.51 21.49 48 48 48h480c26.51 0 48-21.49 48-48V270.533a47.994 47.994 0 0 0-8.062-26.625zM162.252 128h251.497l85.333 128H376l-32 64H232l-32-64H76.918l85.334-128z"/></svg>

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M12.41 148.02l232.94 105.67c6.8 3.09 14.49 3.09 21.29 0l232.94-105.67c16.55-7.51 16.55-32.52 0-40.03L266.65 2.31a25.607 25.607 0 0 0-21.29 0L12.41 107.98c-16.55 7.51-16.55 32.53 0 40.04zm487.18 88.28l-58.09-26.33-161.64 73.27c-7.56 3.43-15.59 5.17-23.86 5.17s-16.29-1.74-23.86-5.17L70.51 209.97l-58.1 26.33c-16.55 7.5-16.55 32.5 0 40l232.94 105.59c6.8 3.08 14.49 3.08 21.29 0L499.59 276.3c16.55-7.5 16.55-32.5 0-40zm0 127.8l-57.87-26.23-161.86 73.37c-7.56 3.43-15.59 5.17-23.86 5.17s-16.29-1.74-23.86-5.17L70.29 337.87 12.41 364.1c-16.55 7.5-16.55 32.5 0 40l232.94 105.59c6.8 3.08 14.49 3.08 21.29 0L499.59 404.1c16.55-7.5 16.55-32.5 0-40z"/></svg>

After

Width:  |  Height:  |  Size: 719 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z"/></svg>

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M384 208A176 176 0 1 0 32 208a176 176 0 1 0 352 0zM343.3 366C307 397.2 259.7 416 208 416C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208c0 51.7-18.8 99-50 135.3L507.3 484.7c6.2 6.2 6.2 16.4 0 22.6s-16.4 6.2-22.6 0L343.3 366z"/></svg>

After

Width:  |  Height:  |  Size: 477 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M272 16c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 224L16 240c-8.8 0-16 7.2-16 16s7.2 16 16 16l224 0 0 224c0 8.8 7.2 16 16 16s16-7.2 16-16l0-224 224 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-224 0 0-224z"/></svg>

After

Width:  |  Height:  |  Size: 437 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M240 64c0-8.8-7.2-16-16-16s-16 7.2-16 16V240H32c-8.8 0-16 7.2-16 16s7.2 16 16 16H208V448c0 8.8 7.2 16 16 16s16-7.2 16-16V272H416c8.8 0 16-7.2 16-16s-7.2-16-16-16H240V64z"/></svg>

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M508.5 468.9L387.1 347.5c-2.3-2.3-5.3-3.5-8.5-3.5h-13.2c31.5-36.5 50.6-84 50.6-136C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c52 0 99.5-19.1 136-50.6v13.2c0 3.2 1.3 6.2 3.5 8.5l121.4 121.4c4.7 4.7 12.3 4.7 17 0l22.6-22.6c4.7-4.7 4.7-12.3 0-17zM208 368c-88.4 0-160-71.6-160-160S119.6 48 208 48s160 71.6 160 160-71.6 160-160 160z"/></svg>

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M352 320c-22.608 0-43.387 7.819-59.79 20.895l-102.486-64.054a96.551 96.551 0 0 0 0-41.683l102.486-64.054C308.613 184.181 329.392 192 352 192c53.019 0 96-42.981 96-96S405.019 0 352 0s-96 42.981-96 96c0 7.158.79 14.13 2.276 20.841L155.79 180.895C139.387 167.819 118.608 160 96 160c-53.019 0-96 42.981-96 96s42.981 96 96 96c22.608 0 43.387-7.819 59.79-20.895l102.486 64.054A96.301 96.301 0 0 0 256 416c0 53.019 42.981 96 96 96s96-42.981 96-96-42.981-96-96-96z"/></svg>

After

Width:  |  Height:  |  Size: 536 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M488 64h-8v20c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12V64H96v20c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12V64h-8C10.7 64 0 74.7 0 88v336c0 13.3 10.7 24 24 24h8v-20c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v20h320v-20c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v20h8c13.3 0 24-10.7 24-24V88c0-13.3-10.7-24-24-24zM96 372c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm384 192c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40z"/></svg>

After

Width:  |  Height:  |  Size: 972 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 416c0 8.8 7.2 16 16 16l65.6 0c7.4 36.5 39.7 64 78.4 64s71-27.5 78.4-64L496 432c8.8 0 16-7.2 16-16s-7.2-16-16-16l-257.6 0c-7.4-36.5-39.7-64-78.4-64s-71 27.5-78.4 64L16 400c-8.8 0-16 7.2-16 16zm112 0a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zM304 256a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zm48-80c-38.7 0-71 27.5-78.4 64L16 240c-8.8 0-16 7.2-16 16s7.2 16 16 16l257.6 0c7.4 36.5 39.7 64 78.4 64s71-27.5 78.4-64l65.6 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-65.6 0c-7.4-36.5-39.7-64-78.4-64zM192 144a48 48 0 1 1 0-96 48 48 0 1 1 0 96zm78.4-64C263 43.5 230.7 16 192 16s-71 27.5-78.4 64L16 80C7.2 80 0 87.2 0 96s7.2 16 16 16l97.6 0c7.4 36.5 39.7 64 78.4 64s71-27.5 78.4-64L496 112c8.8 0 16-7.2 16-16s-7.2-16-16-16L270.4 80z"/></svg>

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Some files were not shown because too many files have changed in this diff Show More