Add light/dark theme switching and merge syntax and GUI theme (#2373)
This commit is contained in:
+2
-2
@@ -62,8 +62,8 @@ Some of the assets bundled with novelWriter were adapted from the following sour
|
|||||||
* **Material Symbols** icons by Google Inc (Apache 2.0)
|
* **Material Symbols** icons by Google Inc (Apache 2.0)
|
||||||
* **Remix** icons by RemixIcon (Apache 2.0)
|
* **Remix** icons by RemixIcon (Apache 2.0)
|
||||||
* **Font Awesome** icons by Fonticons Inc (CC BY 4.0)
|
* **Font Awesome** icons by Fonticons Inc (CC BY 4.0)
|
||||||
* **Tomorrow** syntax themes by Chris Kempson (MIT License)
|
* **Tomorrow** themes by Chris Kempson (MIT License)
|
||||||
* **Owl** syntax themes by Sarah Drasner (MIT License)
|
* **Owl** themes by Sarah Drasner (MIT License)
|
||||||
* **Solarized** themes by Ethan Schoonover (MIT License)
|
* **Solarized** themes by Ethan Schoonover (MIT License)
|
||||||
* **Cyberpunk Night** theme by Anders Lemvigh (CC BY-SA 4.0)
|
* **Cyberpunk Night** theme by Anders Lemvigh (CC BY-SA 4.0)
|
||||||
* **Dracula** theme by Zeno Rocha (MIT License)
|
* **Dracula** theme by Zeno Rocha (MIT License)
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ storage for robustness.
|
|||||||
|
|
||||||
more/counting
|
more/counting
|
||||||
more/typography
|
more/typography
|
||||||
|
more/dictionaries
|
||||||
more/customise
|
more/customise
|
||||||
more/handling_errors
|
more/handling_errors
|
||||||
more/project_format
|
more/project_format
|
||||||
|
|||||||
+185
-168
@@ -1,94 +1,35 @@
|
|||||||
.. _docs_more_custom:
|
.. _docs_more_custom:
|
||||||
|
|
||||||
**************
|
*************
|
||||||
Customisations
|
Custom Themes
|
||||||
**************
|
*************
|
||||||
|
|
||||||
.. _Enchant: https://rrthomas.github.io/enchant/
|
There are a few ways you can customise novelWriter yourself. Currently, you can relatively easily
|
||||||
.. _Free Desktop: https://cgit.freedesktop.org/libreoffice/dictionaries/tree/
|
add new GUI themes. You can also add new icon themes, although this is not as straightforward.
|
||||||
|
|
||||||
There are a few ways you can customise novelWriter yourself. Currently, you can add new GUI themes,
|
|
||||||
your own syntax themes, and install additional dictionaries.
|
|
||||||
|
|
||||||
|
|
||||||
.. _docs_more_custom_dict:
|
|
||||||
|
|
||||||
Spell Check Dictionaries
|
|
||||||
========================
|
|
||||||
|
|
||||||
novelWriter uses Enchant_ as the spell checking tool. Depending on your operating system, it may or
|
|
||||||
may not load all installed spell check dictionaries automatically.
|
|
||||||
|
|
||||||
|
|
||||||
Linux and MacOS
|
|
||||||
---------------
|
|
||||||
|
|
||||||
On Linux and MacOS, you generally only have to install hunspell, aspell or myspell dictionaries on
|
|
||||||
your system like you do for other applications. See your distro or OS documentation for how to do
|
|
||||||
this. These dictionaries should show up as available spell check languages in novelWriter.
|
|
||||||
|
|
||||||
|
|
||||||
Windows
|
|
||||||
-------
|
|
||||||
|
|
||||||
For Windows, English is included with the installation. For other languages you have to download
|
|
||||||
and add dictionaries yourself.
|
|
||||||
|
|
||||||
**Install Tool**
|
|
||||||
|
|
||||||
A small tool to assist with this can be found under **Tools > Add Dictionaries**. It will import
|
|
||||||
spell checking dictionaries from Free Office or Libre Office extensions. The dictionaries are then
|
|
||||||
installed in the install location for the Enchant library and should thus work for any application
|
|
||||||
that uses Enchant for spell checking.
|
|
||||||
|
|
||||||
**Manual Install**
|
|
||||||
|
|
||||||
If you prefer to do this manually or want to use a different source than the ones mentioned above,
|
|
||||||
You need to get compatible dictionary files for your language. You need two files files ending with
|
|
||||||
``.aff`` and ``.dic``. These files must then be copied to the following location:
|
|
||||||
|
|
||||||
``C:\Users\<USER>\AppData\Local\enchant\hunspell``
|
|
||||||
|
|
||||||
This assumes your user profile is stored at ``C:\Users\<USER>``. The last one or two folders may
|
|
||||||
not exist, so you may need to create them.
|
|
||||||
|
|
||||||
You can find the various dictionaries on the `Free Desktop`_ website.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
The Free Desktop link points to a repository, and what may look like file links inside the
|
|
||||||
dictionary folder are actually links to web pages. If you right-click and download those, you
|
|
||||||
get HTML files, not dictionaries!
|
|
||||||
|
|
||||||
In order to download the actual dictionary files, right-click the "plain" label at the end of
|
|
||||||
each line and download that.
|
|
||||||
|
|
||||||
|
|
||||||
.. _docs_more_custom_theme:
|
.. _docs_more_custom_theme:
|
||||||
|
|
||||||
Syntax and GUI Themes
|
Colour Themes
|
||||||
=====================
|
=============
|
||||||
|
|
||||||
Adding your own GUI and syntax themes is relatively easy, although it requires that you manually
|
Adding your own colour themes is relatively easy, although it requires that you manually edit
|
||||||
edit config files with colour values. The themes are defined by simple plain text config files with
|
config files with colour values. The themes are defined by simple plain text config files with meta
|
||||||
meta data and colour settings.
|
data and colour settings.
|
||||||
|
|
||||||
In order to make your own versions, first copy one of the existing files to your local computer and
|
In order to make your own versions, first copy one of the existing files to your local computer and
|
||||||
modify it as you like.
|
modify it as you like.
|
||||||
|
|
||||||
* The existing syntax themes are stored in
|
The existing colour themes are stored in
|
||||||
`novelwriter/assets/syntax <https://github.com/vkbo/novelWriter/tree/main/novelwriter/assets/syntax>`_.
|
`novelwriter/assets/themes <https://github.com/vkbo/novelWriter/tree/main/novelwriter/assets/themes>`_.
|
||||||
* The existing GUI themes are stored in
|
|
||||||
`novelwriter/assets/themes <https://github.com/vkbo/novelWriter/tree/main/novelwriter/assets/themes>`_.
|
|
||||||
* The existing icon themes are stored in
|
|
||||||
`novelwriter/assets/icons <https://github.com/vkbo/novelWriter/tree/main/novelwriter/assets/icons>`_.
|
|
||||||
|
|
||||||
Remember to also change the name of your theme by modifying the ``name`` setting at the top of the
|
Remember to also change the name of your theme by modifying the ``name`` setting at the top of the
|
||||||
file, otherwise you may not be able to distinguish them in **Preferences**.
|
file, otherwise you may not be able to distinguish them in **Preferences**.
|
||||||
|
|
||||||
For novelWriter to be able to locate the custom theme files, you must copy them to the
|
For novelWriter to be able to locate the custom theme files, you must copy them to the
|
||||||
:ref:`docs_technical_locations_data` location in your home or user area. There should be a folder there named
|
:ref:`docs_technical_locations_data` location in your home or user area. There should be a folder
|
||||||
``syntax`` for syntax themes, just ``themes`` for GUI themes, and ``icons`` for icon themes. These
|
there named ``themes`` for colour themes. These folders are created the first time you start
|
||||||
folders are created the first time you start novelWriter.
|
novelWriter.
|
||||||
|
|
||||||
Once the files are copied there, they should show up in **Preferences** with the label you
|
Once the files are copied there, they should show up in **Preferences** with the label you
|
||||||
set as ``name`` inside the file.
|
set as ``name`` inside the file.
|
||||||
@@ -99,71 +40,123 @@ set as ``name`` inside the file.
|
|||||||
files up to date.
|
files up to date.
|
||||||
|
|
||||||
|
|
||||||
Custom GUI and Icons Theme
|
The Theme File Format
|
||||||
--------------------------
|
---------------------
|
||||||
|
|
||||||
A GUI theme ``.conf`` file consists of the following settings:
|
A colour theme ``.conf`` file consists of the following settings:
|
||||||
|
|
||||||
.. code-block:: cfg
|
.. code-block:: cfg
|
||||||
|
:caption: The theme file for the "Default Light Theme"
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
name = My Custom Theme
|
name = Default Light Theme
|
||||||
description = A description of my custom theme
|
mode = light
|
||||||
author = Jane Doe
|
description = The novelWriter standard light theme
|
||||||
credit = John Doe
|
author = Veronica Berglyd Olsen
|
||||||
url = https://example.com
|
credit = Veronica Berglyd Olsen
|
||||||
|
url = https://github.com/vkbo/novelWriter
|
||||||
license = CC BY-SA 4.0
|
license = CC BY-SA 4.0
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||||
|
|
||||||
[Icons]
|
[Base]
|
||||||
default = 100, 100, 100
|
default = #303030
|
||||||
faded = 100, 100, 100
|
faded = #6c6c6c
|
||||||
red = 255, 0, 0
|
red = #a62a2d
|
||||||
orange = 255, 128, 0
|
orange = #b36829
|
||||||
yellow = 255, 255, 0
|
yellow = #a68542
|
||||||
green = 0, 255, 0
|
green = #296629
|
||||||
aqua = 0, 255, 255
|
cyan = #269999
|
||||||
blue = 0, 0, 255
|
blue = #3a70a6
|
||||||
purple = 255, 0, 255
|
purple = #b35ab3
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
root = 0, 255, 255
|
root = blue
|
||||||
folder = 255, 255, 0
|
folder = yellow
|
||||||
file = 100, 100, 100
|
file = default
|
||||||
title = 0, 255, 0
|
title = green
|
||||||
chapter = 255, 0, 0
|
chapter = red
|
||||||
scene = 0, 0, 255
|
scene = blue
|
||||||
note = 255, 255, 0
|
note = yellow
|
||||||
|
|
||||||
[Palette]
|
[Palette]
|
||||||
window = 100, 100, 100
|
window = #efefef
|
||||||
windowtext = 100, 100, 100
|
windowtext = #000000
|
||||||
base = 100, 100, 100
|
base = #ffffff
|
||||||
alternatebase = 100, 100, 100
|
alternatebase = #e0e0e0
|
||||||
text = 100, 100, 100
|
text = #000000
|
||||||
tooltipbase = 100, 100, 100
|
tooltipbase = #ffffc0
|
||||||
tooltiptext = 100, 100, 100
|
tooltiptext = #15150d
|
||||||
button = 100, 100, 100
|
button = #efefef
|
||||||
buttontext = 100, 100, 100
|
buttontext = #000000
|
||||||
brighttext = 100, 100, 100
|
brighttext = #ffffff
|
||||||
highlight = 100, 100, 100
|
highlight = #3087c6
|
||||||
highlightedtext = 100, 100, 100
|
highlightedtext = #ffffff
|
||||||
link = 100, 100, 100
|
link = blue
|
||||||
linkvisited = 100, 100, 100
|
linkvisited = blue
|
||||||
|
|
||||||
[GUI]
|
[GUI]
|
||||||
helptext = 0, 0, 0
|
helptext = #5c5c5c
|
||||||
fadedtext = 128, 128, 128
|
fadedtext = #6c6c6c
|
||||||
errortext = 255, 0, 0
|
errortext = red
|
||||||
|
|
||||||
In the Main section you must at least define the ``name`` settings.
|
[Syntax]
|
||||||
|
background = #ffffff
|
||||||
|
text = #000000
|
||||||
|
link = blue
|
||||||
|
headertext = green
|
||||||
|
headertag = green:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = blue
|
||||||
|
altdialog = blue
|
||||||
|
note = yellow
|
||||||
|
hidden = faded
|
||||||
|
shortcode = green
|
||||||
|
keyword = red
|
||||||
|
tag = green
|
||||||
|
value = blue
|
||||||
|
optional = green
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = green
|
||||||
|
modifier = green
|
||||||
|
texthighlight = #c8c80060
|
||||||
|
|
||||||
The Palette values correspond to the Qt enum values for ``QPalette::ColorRole``, see the
|
|
||||||
`Qt documentation <https://doc.qt.io/qt-6/qpalette.html#ColorRole-enum>`_ for more details. The
|
Theme Sections
|
||||||
colour values are RGB numbers on the format ``r, g, b`` where each is an integer from ``0`` to
|
--------------
|
||||||
``255``. Omitted values are not loaded and will use default values. If the ``helptext`` colour is
|
|
||||||
not defined, it is computed as a colour between the ``window`` and ``windowtext`` colour.
|
.. _ColorRole: https://doc.qt.io/qt-6/qpalette.html#ColorRole-enum
|
||||||
Additional shades of some of the colours are also computed. These are mainly used for 3D effects.
|
|
||||||
|
The theme file is made up of different sections depending on what part of novelWriter the theme
|
||||||
|
affects.
|
||||||
|
|
||||||
|
.. csv-table:: Theme Sections Overview
|
||||||
|
:header: "Section", "Description"
|
||||||
|
:class: "tight-table"
|
||||||
|
|
||||||
|
"``[Main]``", "Meta data about the theme, You must at least set ``name`` and ``mode``, and ``mode`` must be either ``light`` or ``dark``."
|
||||||
|
"``[Base]``", "The base colours of the theme. These are also selectable colours in various places inside the app, like for icon colours in **Preferences**."
|
||||||
|
"``[Project]``", "The colours used for icons and markers for the different project item types."
|
||||||
|
"``[Palette]``", "The colours used for styling the user interface. The values correspond to the ColorRole_ values in the Qt library."
|
||||||
|
"``[GUI]``", "The colours used for styling additional elements of the user interface."
|
||||||
|
"``[Syntax]``", "The colours used for syntax highlighting in documents."
|
||||||
|
|
||||||
|
|
||||||
|
Colour Value Formats
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
There are several ways to enter colour values:
|
||||||
|
|
||||||
|
.. csv-table:: Colour Formats
|
||||||
|
:header: "Syntax", "Description"
|
||||||
|
:class: "tight-table"
|
||||||
|
|
||||||
|
"``#RRGGBB``", "A CSS style hexadecimal values, like ``#ff0000`` for red."
|
||||||
|
"``#RRGGBBAA``", "A CSS style hexadecimal values with transparency, like ``#ff00007f`` for half-transparent red."
|
||||||
|
"``name``", "A name referring to one of the colours already specified under the ``[Base]`` section, like ``red``. Note that you should not use named colours in the ``[Base]`` section itself as that may have unintended results."
|
||||||
|
"``name:alpha``", "A name referring to one of the colours already specified under the ``[Base]`` section, with a transparency value added. The alpha value must be in the range ``0`` to ``255``, like ``red:127`` for half-transparent red."
|
||||||
|
"``r, g, b``", "A set of red, green and blue numbers in the range ``0`` to ``255``, like ``255, 0, 0`` for red."
|
||||||
|
"``r, g, b, a``", "A set of red, green, blue and alpha numbers in the range ``0`` to ``255``, like ``255, 0, 0, 127`` for half-transparent red."
|
||||||
|
|
||||||
.. versionadded:: 2.5
|
.. versionadded:: 2.5
|
||||||
The ``fadedtext`` and ``errortext`` theme colour entries were added.
|
The ``fadedtext`` and ``errortext`` theme colour entries were added.
|
||||||
@@ -172,60 +165,84 @@ Additional shades of some of the colours are also computed. These are mainly use
|
|||||||
The ``icontheme`` setting was dropped as the icon theme is now its own setting.
|
The ``icontheme`` setting was dropped as the icon theme is now its own setting.
|
||||||
The ``[Icons]`` and ``[Project]`` sections were added, and the ``status*`` settings removed.
|
The ``[Icons]`` and ``[Project]`` sections were added, and the ``status*`` settings removed.
|
||||||
|
|
||||||
|
.. versionadded:: 2.8
|
||||||
|
The ``[Syntax]`` section was moved into the main theme file. Previously, these settings were in
|
||||||
|
their own file. The ``[Icons]`` section was renamed to ``[Base]``.
|
||||||
|
|
||||||
Custom Syntax Theme
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
A syntax theme ``.conf`` file consists of the following settings:
|
Icon Themes
|
||||||
|
===========
|
||||||
|
|
||||||
|
Icon themes are *not* straightforward to add, but if you want to make the effort, this section
|
||||||
|
describes how to do it.
|
||||||
|
|
||||||
|
The existing icon themes are stored in
|
||||||
|
`novelwriter/assets/icons <https://github.com/vkbo/novelWriter/tree/main/novelwriter/assets/icons>`_.
|
||||||
|
|
||||||
|
As with colour themes, remember to change the name of your theme by modifying the ``name`` setting
|
||||||
|
at the top of the file, otherwise you may not be able to distinguish them in **Preferences**.
|
||||||
|
|
||||||
|
For novelWriter to be able to locate the custom theme files, you must copy them to the
|
||||||
|
:ref:`docs_technical_locations_data` location in your home or user area. There should be a folder
|
||||||
|
there ``icons`` for icon themes. These folders are created the first time you start novelWriter.
|
||||||
|
|
||||||
|
|
||||||
|
The Icons File Format
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Icon themes are kept in files with the ``.icons`` file extension. The file format is a custom
|
||||||
|
format with entries on the form ``section:key = value``.
|
||||||
|
|
||||||
.. code-block:: cfg
|
.. code-block:: cfg
|
||||||
|
:caption: The icons file for "Material Symbols - Rounded Medium" (truncated)
|
||||||
|
|
||||||
[Main]
|
# Meta
|
||||||
name = My Syntax Theme
|
meta:name = Material Symbols - Rounded Medium
|
||||||
author = Jane Doe
|
meta:author = Google Inc
|
||||||
credit = John Doe
|
meta:license = Apache 2.0
|
||||||
url = https://example.com
|
|
||||||
license = CC BY-SA 4.0
|
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
|
||||||
|
|
||||||
[Syntax]
|
# Icons
|
||||||
background = 255, 255, 255
|
icon:alert_error = <svg ...>
|
||||||
text = 0, 0, 0
|
icon:alert_info = <svg ...>
|
||||||
link = 0, 0, 0
|
icon:alert_question = <svg ...>
|
||||||
headertext = 0, 0, 0
|
icon:alert_warn = <svg ...>
|
||||||
headertag = 0, 0, 0
|
icon:cls_archive = <svg ...>
|
||||||
emphasis = 0, 0, 0
|
icon:cls_character = <svg ...>
|
||||||
dialog = 0, 0, 0
|
icon:cls_custom = <svg ...>
|
||||||
altdialog = 0, 0, 0
|
icon:cls_entity = <svg ...>
|
||||||
note = 0, 0, 0
|
icon:cls_none = <svg ...>
|
||||||
hidden = 0, 0, 0
|
icon:cls_novel = <svg ...>
|
||||||
shortcode = 0, 0, 0
|
icon:cls_object = <svg ...>
|
||||||
keyword = 0, 0, 0
|
icon:cls_plot = <svg ...>
|
||||||
tag = 0, 0, 0
|
icon:cls_template = <svg ...>
|
||||||
value = 0, 0, 0
|
icon:cls_timeline = <svg ...>
|
||||||
optional = 0, 0, 0
|
icon:cls_trash = <svg ...>
|
||||||
spellcheckline = 0, 0, 0
|
icon:cls_world = <svg ...>
|
||||||
errorline = 0, 0, 0
|
|
||||||
replacetag = 0, 0, 0
|
|
||||||
modifier = 0, 0, 0
|
|
||||||
texthighlight = 255, 255, 255, 128
|
|
||||||
|
|
||||||
In the Main section, you must define at least the ``name`` setting. The Syntax colour values are
|
The icon keys are associated with icon placement locations inside novelWriter, and the template for
|
||||||
RGB(A) numbers of the format ``r, g, b, a`` where each is an integer from ``0`` to ``255``. The
|
them is defined in the script that generates the default icon themes.
|
||||||
fourth value is the alpha channel, which can be omitted.
|
|
||||||
|
|
||||||
Omitted syntax colours default to black, except ``background`` which defaults to white, and
|
The script can be found under
|
||||||
``texthighlight`` which defaults to white with half transparency.
|
`utils/icon_themes.py <https://github.com/vkbo/novelWriter/blob/main/utils/icon_themes.py>`__
|
||||||
|
in the source code.
|
||||||
|
|
||||||
.. versionadded:: 2.2
|
This file includes all the code needed to generate the themes that are included in novelWriter. The
|
||||||
The ``shortcode`` syntax colour entry was added.
|
icon keys are mapped to icon keys from the specific themes in JSON files in the ``icon_themes``
|
||||||
|
folder next to the script. This is the recommended way to generate these themes. Doing it manually
|
||||||
|
is not advisable.
|
||||||
|
|
||||||
.. versionadded:: 2.3
|
|
||||||
The ``optional`` syntax colour entry was added.
|
|
||||||
|
|
||||||
.. versionadded:: 2.4
|
Icon Value Format
|
||||||
The ``texthighlight`` syntax colour entry was added.
|
-----------------
|
||||||
|
|
||||||
.. versionadded:: 2.5
|
As can be seen from the example, an icon is defined in the ``icon`` section with a key and an
|
||||||
The ``dialog``, ``altdialog``, ``note`` and ``tag`` syntax colour entries were added.
|
in-line SVG XML block. The XML must fit on one line and obey the following rules:
|
||||||
``straightquotes``, ``doublequotes`` and ``singlequotes`` were removed.
|
|
||||||
|
#. It must be single colour, that is, the fill colour attribute must be able to colourise the
|
||||||
|
entire icon.
|
||||||
|
#. The fill colour attribute *must* be defined and must be set to: ``fill="#000000"``. This value
|
||||||
|
is replaced by the relevant theme colour when the icon is processed in novelWriter.
|
||||||
|
|
||||||
|
.. versionadded:: 2.7
|
||||||
|
The icon theme files were added. Previously, icons were stored as individual SVG files with a
|
||||||
|
config file mapping the file names to the internal icon keys.
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
.. _docs_more_dictionaries:
|
||||||
|
|
||||||
|
************************
|
||||||
|
Spell Check Dictionaries
|
||||||
|
************************
|
||||||
|
|
||||||
|
.. _Enchant: https://rrthomas.github.io/enchant/
|
||||||
|
.. _Free Desktop: https://cgit.freedesktop.org/libreoffice/dictionaries/tree/
|
||||||
|
|
||||||
|
Spell checking is provided by the Enchant_ library. Depending on your operating system, it may or
|
||||||
|
may not load all installed spell check dictionaries automatically.
|
||||||
|
|
||||||
|
|
||||||
|
Linux and MacOS
|
||||||
|
===============
|
||||||
|
|
||||||
|
On Linux and MacOS, you generally only have to install hunspell, aspell or myspell dictionaries on
|
||||||
|
your system like you do for other applications. See your distro or OS documentation for how to do
|
||||||
|
this. These dictionaries should show up as available spell check languages in novelWriter.
|
||||||
|
|
||||||
|
|
||||||
|
Windows
|
||||||
|
=======
|
||||||
|
|
||||||
|
For Windows, English is included with the installation. For other languages you have to download
|
||||||
|
and add dictionaries yourself.
|
||||||
|
|
||||||
|
**Install Tool**
|
||||||
|
|
||||||
|
A small tool to assist with this can be found under **Tools > Add Dictionaries**. It will import
|
||||||
|
spell checking dictionaries from Free Office or Libre Office extensions. The dictionaries are then
|
||||||
|
installed in the install location for the Enchant library and should thus work for any application
|
||||||
|
that uses Enchant for spell checking.
|
||||||
|
|
||||||
|
**Manual Install**
|
||||||
|
|
||||||
|
If you prefer to do this manually or want to use a different source than the ones mentioned above,
|
||||||
|
You need to get compatible dictionary files for your language. You need two files files ending with
|
||||||
|
``.aff`` and ``.dic``. These files must then be copied to the following location:
|
||||||
|
|
||||||
|
``C:\Users\<USER>\AppData\Local\enchant\hunspell``
|
||||||
|
|
||||||
|
This assumes your user profile is stored at ``C:\Users\<USER>``. The last one or two folders may
|
||||||
|
not exist, so you may need to create them.
|
||||||
|
|
||||||
|
You can find the various dictionaries on the `Free Desktop`_ website.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The Free Desktop link points to a repository, and what may look like file links inside the
|
||||||
|
dictionary folder are actually links to web pages. If you right-click and download those, you
|
||||||
|
get HTML files, not dictionaries!
|
||||||
|
|
||||||
|
In order to download the actual dictionary files, right-click the "plain" label at the end of
|
||||||
|
each line and download that.
|
||||||
@@ -55,7 +55,7 @@ edited from the **Project Word List** tool available from the **Tools** menu.
|
|||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Generally, spell checking dictionaries are collected from your operating system, but on Windows
|
Generally, spell checking dictionaries are collected from your operating system, but on Windows
|
||||||
they are not. See :ref:`docs_more_custom_dict` for how to add spell checking dictionaries on
|
they are not. See :ref:`docs_more_dictionaries` for how to add spell checking dictionaries on
|
||||||
Windows.
|
Windows.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ __license__ = "GPLv3"
|
|||||||
__author__ = "Veronica Berglyd Olsen"
|
__author__ = "Veronica Berglyd Olsen"
|
||||||
__maintainer__ = "Veronica Berglyd Olsen"
|
__maintainer__ = "Veronica Berglyd Olsen"
|
||||||
__email__ = "code@vkbo.net"
|
__email__ = "code@vkbo.net"
|
||||||
__version__ = "2.8 Alpha 0"
|
__version__ = "2.8a0"
|
||||||
__hexversion__ = "0x020800a0"
|
__hexversion__ = "0x020800a0"
|
||||||
__date__ = "2025-06-01"
|
__date__ = "2025-06-01"
|
||||||
__status__ = "Stable"
|
__status__ = "Stable"
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="#000000" height="128" width="128"><path d="M471.6 21.7c-21.9-21.9-57.3-21.9-79.2 0L362.3 51.7l97.9 97.9 30.1-30.1c21.9-21.9 21.9-57.3 0-79.2L471.6 21.7zm-299.2 220c-6.1 6.1-10.8 13.6-13.5 21.9l-29.6 88.8c-2.9 8.6-.6 18.1 5.8 24.6s15.9 8.7 24.6 5.8l88.8-29.6c8.2-2.7 15.7-7.4 21.9-13.5L437.7 172.3 339.7 74.3 172.4 241.7zM96 64C43 64 0 107 0 160L0 416c0 53 43 96 96 96l256 0c53 0 96-43 96-96l0-96c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 96c0 17.7-14.3 32-32 32L96 448c-17.7 0-32-14.3-32-32l0-256c0-17.7 14.3-32 32-32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L96 64z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="#000000" height="128" width="128"><path d="M471.6 21.7c-21.9-21.9-57.3-21.9-79.2 0L362.3 51.7l97.9 97.9 30.1-30.1c21.9-21.9 21.9-57.3 0-79.2L471.6 21.7zm-299.2 220c-6.1 6.1-10.8 13.6-13.5 21.9l-29.6 88.8c-2.9 8.6-.6 18.1 5.8 24.6s15.9 8.7 24.6 5.8l88.8-29.6c8.2-2.7 15.7-7.4 21.9-13.5L437.7 172.3 339.7 74.3 172.4 241.7zM96 64C43 64 0 107 0 160L0 416c0 53 43 96 96 96l256 0c53 0 96-43 96-96l0-96c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 96c0 17.7-14.3 32-32 32L96 448c-17.7 0-32-14.3-32-32l0-256c0-17.7 14.3-32 32-32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L96 64z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="#000000" height="128" width="128"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="#000000" height="128" width="128"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 0 512 512" fill="#000000" height="128" width="128"><path d="M160 80c0-26.5 21.5-48 48-48l32 0c26.5 0 48 21.5 48 48l0 352c0 26.5-21.5 48-48 48l-32 0c-26.5 0-48-21.5-48-48l0-352zM0 272c0-26.5 21.5-48 48-48l32 0c26.5 0 48 21.5 48 48l0 160c0 26.5-21.5 48-48 48l-32 0c-26.5 0-48-21.5-48-48L0 272zM368 96l32 0c26.5 0 48 21.5 48 48l0 288c0 26.5-21.5 48-48 48l-32 0c-26.5 0-48-21.5-48-48l0-288c0-26.5 21.5-48 48-48z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 0 512 512" fill="#000000" height="128" width="128"><path d="M160 80c0-26.5 21.5-48 48-48l32 0c26.5 0 48 21.5 48 48l0 352c0 26.5-21.5 48-48 48l-32 0c-26.5 0-48-21.5-48-48l0-352zM0 272c0-26.5 21.5-48 48-48l32 0c26.5 0 48 21.5 48 48l0 160c0 26.5-21.5 48-48 48l-32 0c-26.5 0-48-21.5-48-48L0 272zM368 96l32 0c26.5 0 48 21.5 48 48l0 288c0 26.5-21.5 48-48 48l-32 0c-26.5 0-48-21.5-48-48l0-288c0-26.5 21.5-48 48-48z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="#000000" height="128" width="128"><path d="M361.5 1.2c5 2.1 8.6 6.6 9.6 11.9L391 121l107.9 19.8c5.3 1 9.8 4.6 11.9 9.6s1.5 10.7-1.6 15.2L446.9 256l62.3 90.3c3.1 4.5 3.7 10.2 1.6 15.2s-6.6 8.6-11.9 9.6L391 391 371.1 498.9c-1 5.3-4.6 9.8-9.6 11.9s-10.7 1.5-15.2-1.6L256 446.9l-90.3 62.3c-4.5 3.1-10.2 3.7-15.2 1.6s-8.6-6.6-9.6-11.9L121 391 13.1 371.1c-5.3-1-9.8-4.6-11.9-9.6s-1.5-10.7 1.6-15.2L65.1 256 2.8 165.7c-3.1-4.5-3.7-10.2-1.6-15.2s6.6-8.6 11.9-9.6L121 121 140.9 13.1c1-5.3 4.6-9.8 9.6-11.9s10.7-1.5 15.2 1.6L256 65.1 346.3 2.8c4.5-3.1 10.2-3.7 15.2-1.6zM160 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>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" viewBox="-64 0 512 512" fill="#000000" height="128" width="128"><path d="M223.5 32C100 32 0 132.3 0 256S100 480 223.5 480c60.6 0 115.5-24.2 155.8-63.4c5-4.9 6.3-12.5 3.1-18.7s-10.1-9.7-17-8.5c-9.8 1.7-19.8 2.6-30.1 2.6c-96.9 0-175.5-78.8-175.5-176c0-65.8 36-123.1 89.3-153.3c6.1-3.5 9.2-10.5 7.7-17.3s-7.3-11.9-14.3-12.5c-6.3-.5-12.6-.8-19-.8z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="#000000" height="128" width="128"><path d="M448 256c0-106-86-192-192-192l0 384c106 0 192-86 192-192zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 0 512 512" fill="#000000" height="128" width="128"><path d="M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 144L48 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l144 0 0 144c0 17.7 14.3 32 32 32s32-14.3 32-32l0-144 144 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-144 0 0-144z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 0 512 512" fill="#000000" height="128" width="128"><path d="M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 144L48 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l144 0 0 144c0 17.7 14.3 32 32 32s32-14.3 32-32l0-144 144 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-144 0 0-144z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" viewBox="-64 0 512 512" fill="#000000" height="128" width="128"><path d="M0 48V487.7C0 501.1 10.9 512 24.3 512c5 0 9.9-1.5 14-4.4L192 400 345.7 507.6c4.1 2.9 9 4.4 14 4.4c13.4 0 24.3-10.9 24.3-24.3V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" viewBox="-64 0 512 512" fill="#000000" height="128" width="128"><path d="M0 48V487.7C0 501.1 10.9 512 24.3 512c5 0 9.9-1.5 14-4.4L192 400 345.7 507.6c4.1 2.9 9 4.4 14 4.4c13.4 0 24.3-10.9 24.3-24.3V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" viewBox="32 0 512 512" fill="#000000" height="128" width="128"><path d="M88.7 223.8L0 375.8 0 96C0 60.7 28.7 32 64 32l117.5 0c17 0 33.3 6.7 45.3 18.7l26.5 26.5c12 12 28.3 18.7 45.3 18.7L416 96c35.3 0 64 28.7 64 64l0 32-336 0c-22.8 0-43.8 12.1-55.3 31.8zm27.6 16.1C122.1 230 132.6 224 144 224l400 0c11.5 0 22 6.1 27.7 16.1s5.7 22.2-.1 32.1l-112 192C453.9 474 443.4 480 432 480L32 480c-11.5 0-22-6.1-27.7-16.1s-5.7-22.2 .1-32.1l112-192z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" viewBox="32 0 512 512" fill="#000000" height="128" width="128"><path d="M88.7 223.8L0 375.8 0 96C0 60.7 28.7 32 64 32l117.5 0c17 0 33.3 6.7 45.3 18.7l26.5 26.5c12 12 28.3 18.7 45.3 18.7L416 96c35.3 0 64 28.7 64 64l0 32-336 0c-22.8 0-43.8 12.1-55.3 31.8zm27.6 16.1C122.1 230 132.6 224 144 224l400 0c11.5 0 22 6.1 27.7 16.1s5.7 22.2-.1 32.1l-112 192C453.9 474 443.4 480 432 480L32 480c-11.5 0-22-6.1-27.7-16.1s-5.7-22.2 .1-32.1l112-192z" /></svg>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" height="128" view
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M556.61-113.78v-63.74q0-10.83 4.13-20.31 4.13-9.47 11.83-17.17L781-423q10.7-10.7 23.67-15.54 12.98-4.85 26.24-4.85 14.26 0 27.24 5.35 12.98 5.34 23.68 16.04l37 37q9.69 10.7 15.04 23.67 5.35 12.98 5.35 26.24 0 13.83-4.85 27.03-4.85 13.19-15.54 23.89l-208 208q-7.7 7.69-17.18 11.54-9.48 3.85-20.3 3.85h-63.74q-22.09 0-37.54-15.46-15.46-15.46-15.46-37.54Zm279.96-187.96 31.34-33.35-37-37-32.34 32.35 38 38ZM166.78-140.78q-44.3 0-75.15-30.85-30.85-30.85-30.85-75.15v-466.44q0-44.3 30.85-75.15 30.85-30.85 75.15-30.85h181q21.09 0 40.39 7.98 19.31 7.98 34.26 22.94L480-730.74h313.22q44.3 0 75.15 30.85 30.85 30.85 30.85 75.15v57q0 21.96-17.89 35.22-17.89 13.26-40.85 9.13-9.78-.57-19.35.28-9.57.85-18.78 3.68-21.79 2.82-41.76 12.82-19.98 10-36.59 26.61L507.52-263.52q-14.95 14.95-22.93 33.98-7.98 19.02-7.98 40.67v1.31q0 19.82-13.48 33.3-13.48 13.48-33.3 13.48H166.78Z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M556.61-113.78v-63.74q0-10.83 4.13-20.31 4.13-9.47 11.83-17.17L781-423q10.7-10.7 23.67-15.54 12.98-4.85 26.24-4.85 14.26 0 27.24 5.35 12.98 5.34 23.68 16.04l37 37q9.69 10.7 15.04 23.67 5.35 12.98 5.35 26.24 0 13.83-4.85 27.03-4.85 13.19-15.54 23.89l-208 208q-7.7 7.69-17.18 11.54-9.48 3.85-20.3 3.85h-63.74q-22.09 0-37.54-15.46-15.46-15.46-15.46-37.54Zm279.96-187.96 31.34-33.35-37-37-32.34 32.35 38 38ZM166.78-140.78q-44.3 0-75.15-30.85-30.85-30.85-30.85-75.15v-466.44q0-44.3 30.85-75.15 30.85-30.85 75.15-30.85h181q21.09 0 40.39 7.98 19.31 7.98 34.26 22.94L480-730.74h313.22q44.3 0 75.15 30.85 30.85 30.85 30.85 75.15v57q0 21.96-17.89 35.22-17.89 13.26-40.85 9.13-9.78-.57-19.35.28-9.57.85-18.78 3.68-21.79 2.82-41.76 12.82-19.98 10-36.59 26.61L507.52-263.52q-14.95 14.95-22.93 33.98-7.98 19.02-7.98 40.67v1.31q0 19.82-13.48 33.3-13.48 13.48-33.3 13.48H166.78Z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M375.48-307q-114.09 0-193.55-79.46-79.45-79.45-79.45-193.54 0-114.09 79.45-193.54Q261.39-853 375.48-853q114.09 0 193.54 79.46 79.46 79.45 79.46 193.54 0 45.13-12.87 83.28T601-429.7l219.48 220.05q14.96 15.52 14.96 37.32 0 21.81-15.53 36.77-14.95 14.95-37.04 14.95t-37.04-14.95L526.91-354.48q-29.43 21.74-68.15 34.61Q420.04-307 375.48-307Zm0-106q69.91 0 118.45-48.54 48.55-48.55 48.55-118.46t-48.55-118.46Q445.39-747 375.48-747t-118.46 48.54Q208.48-649.91 208.48-580t48.54 118.46Q305.57-413 375.48-413Z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M375.48-307q-114.09 0-193.55-79.46-79.45-79.45-79.45-193.54 0-114.09 79.45-193.54Q261.39-853 375.48-853q114.09 0 193.54 79.46 79.46 79.45 79.46 193.54 0 45.13-12.87 83.28T601-429.7l219.48 220.05q14.96 15.52 14.96 37.32 0 21.81-15.53 36.77-14.95 14.95-37.04 14.95t-37.04-14.95L526.91-354.48q-29.43 21.74-68.15 34.61Q420.04-307 375.48-307Zm0-106q69.91 0 118.45-48.54 48.55-48.55 48.55-118.46t-48.55-118.46Q445.39-747 375.48-747t-118.46 48.54Q208.48-649.91 208.48-580t48.54 118.46Q305.57-413 375.48-413Z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M694.7-140.78q-22.09 0-37.55-15.46-15.45-15.46-15.45-37.54v-201.13q0-22.09 15.45-37.55 15.46-15.45 37.55-15.45h71.52q22.08 0 37.54 15.45 15.46 15.46 15.46 37.55v201.13q0 22.08-15.46 37.54t-37.54 15.46H694.7Zm-250.18 0q-22.09 0-37.54-15.46-15.46-15.46-15.46-37.54v-572.44q0-22.08 15.46-37.54 15.45-15.46 37.54-15.46h70.96q22.09 0 37.54 15.46 15.46 15.46 15.46 37.54v572.44q0 22.08-15.46 37.54-15.45 15.46-37.54 15.46h-70.96Zm-250.74 0q-22.08 0-37.54-15.46t-15.46-37.54v-372.44q0-22.08 15.46-37.54t37.54-15.46h71.52q22.09 0 37.55 15.46 15.45 15.46 15.45 37.54v372.44q0 22.08-15.45 37.54-15.46 15.46-37.55 15.46h-71.52Z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M694.7-140.78q-22.09 0-37.55-15.46-15.45-15.46-15.45-37.54v-201.13q0-22.09 15.45-37.55 15.46-15.45 37.55-15.45h71.52q22.08 0 37.54 15.45 15.46 15.46 15.46 37.55v201.13q0 22.08-15.46 37.54t-37.54 15.46H694.7Zm-250.18 0q-22.09 0-37.54-15.46-15.46-15.46-15.46-37.54v-572.44q0-22.08 15.46-37.54 15.45-15.46 37.54-15.46h70.96q22.09 0 37.54 15.46 15.46 15.46 15.46 37.54v572.44q0 22.08-15.46 37.54-15.45 15.46-37.54 15.46h-70.96Zm-250.74 0q-22.08 0-37.54-15.46t-15.46-37.54v-372.44q0-22.08 15.46-37.54t37.54-15.46h71.52q22.09 0 37.55 15.46 15.45 15.46 15.45 37.54v372.44q0 22.08-15.45 37.54-15.46 15.46-37.55 15.46h-71.52Z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480q0 83-58.5 141.5T480-280ZM80-427q-22.09 0-37.54-15.46Q27-457.91 27-480t15.46-37.54Q57.91-533 80-533h80q22.09 0 37.54 15.46Q213-502.09 213-480t-15.46 37.54Q182.09-427 160-427H80Zm720 0q-22.09 0-37.54-15.46Q747-457.91 747-480t15.46-37.54Q777.91-533 800-533h80q22.09 0 37.54 15.46Q933-502.09 933-480t-15.46 37.54Q902.09-427 880-427h-80ZM480-747q-22.09 0-37.54-15.46Q427-777.91 427-800v-80q0-22.09 15.46-37.54Q457.91-933 480-933t37.54 15.46Q533-902.09 533-880v80q0 22.09-15.46 37.54Q502.09-747 480-747Zm0 720q-22.09 0-37.54-15.46Q427-57.91 427-80v-80q0-22.09 15.46-37.54Q457.91-213 480-213t37.54 15.46Q533-182.09 533-160v80q0 22.09-15.46 37.54Q502.09-27 480-27ZM216.96-668.39l-43-42Q158-725.35 158.5-747.43q.5-22.09 15.46-38.61Q189.35-802 211.43-802q22.09 0 37.61 15.96l42.57 43q14.96 15.39 14.67 36.76-.28 21.37-14.67 37.32-14.96 15.96-36.83 16.03-21.87.06-37.82-15.46Zm494 494.43-42.57-43q-14.96-15.39-14.96-36.97 0-21.59 14.96-37.11 14.96-15.96 36.83-15.46 21.87.5 37.82 15.46l43 41.43q15.96 14.96 15.46 37.04-.5 22.09-15.46 38.61Q770.65-158 748.57-158q-22.09 0-37.61-15.96Zm-42-494.43Q653-683.35 653.5-705.22q.5-21.87 15.46-37.82l41.43-43q14.96-15.96 37.04-15.46 22.09.5 38.61 15.46Q802-770.65 802-748.57q0 22.09-15.96 37.61l-43 42.57q-15.39 14.96-36.76 14.67-21.37-.28-37.32-14.67Zm-495 494.43Q158-189.35 158-211.43q0-22.09 15.96-37.61l43-42.57q15.39-14.96 36.97-14.96 21.59 0 37.11 14.96 15.96 14.96 15.46 36.83-.5 21.87-15.46 37.82l-41.43 43Q234.65-158 212.57-158.5q-22.09-.5-38.61-15.46Z" /></svg>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480.57-111.52q-157.22 0-263.14-105.63Q111.52-322.78 111.52-480q0-128.39 77.57-229.89 77.56-101.5 214.17-129.24 18.65-5.39 33.74-1.59 15.09 3.81 25.04 13.37 10.52 9.57 14.13 23.83 3.61 14.26-1 30.35-9.65 23.74-15.6 47.08-5.96 23.35-5.96 48 0 93.96 66.11 159.79 66.11 65.82 160.63 65.82 24.78 0 49.63-5.32 24.85-5.33 46.02-14.55 15.52-4.17 28.72-.85 13.19 3.33 22.19 11.72 9.44 8.39 13.24 22.63 3.81 14.24-1.02 33.33Q814.96-276 713.72-193.76q-101.24 82.24-233.15 82.24Z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M479.95-60.78q-86.91 0-163.3-32.91-76.39-32.92-133.22-89.74-56.82-56.83-89.74-133.27-32.91-76.44-32.91-163.35t32.91-163.3q32.92-76.39 89.74-133.22 56.83-56.82 133.27-89.74 76.44-32.91 163.35-32.91t163.3 32.91q76.39 32.92 133.22 89.74 56.82 56.83 89.74 133.27 32.91 76.44 32.91 163.35t-32.91 163.3q-32.92 76.39-89.74 133.22-56.83 56.82-133.27 89.74-76.44 32.91-163.35 32.91Zm46.83-110.13Q641.26-188.17 717.24-274t75.98-206q0-118.63-75.98-204.94-75.98-86.32-190.46-103.58v617.61Z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M427-427H233.78q-22.08 0-37.54-15.46-15.46-15.45-15.46-37.54t15.46-37.54Q211.7-533 233.78-533H427v-193.22q0-22.08 15.46-37.54 15.45-15.46 37.54-15.46t37.54 15.46Q533-748.3 533-726.22V-533h193.22q22.08 0 37.54 15.46 15.46 15.45 15.46 37.54t-15.46 37.54Q748.3-427 726.22-427H533v193.22q0 22.08-15.46 37.54-15.45 15.46-37.54 15.46t-37.54-15.46Q427-211.7 427-233.78V-427Z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M427-427H233.78q-22.08 0-37.54-15.46-15.46-15.45-15.46-37.54t15.46-37.54Q211.7-533 233.78-533H427v-193.22q0-22.08 15.46-37.54 15.45-15.46 37.54-15.46t37.54 15.46Q533-748.3 533-726.22V-533h193.22q22.08 0 37.54 15.46 15.46 15.45 15.46 37.54t-15.46 37.54Q748.3-427 726.22-427H533v193.22q0 22.08-15.46 37.54-15.45 15.46-37.54 15.46t-37.54-15.46Q427-211.7 427-233.78V-427Z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M387-150.39 241.04-86.87q-53 22.65-100.87-8.48-47.87-31.13-47.87-88.83v-461.34q0-44.3 30.85-75.15 30.85-30.85 75.15-30.85h377.39q44.31 0 75.16 30.85 30.85 30.85 30.85 75.15v461.34q0 57.7-47.87 88.83-47.87 31.13-100.88 8.48L387-150.39Zm427.7-27.13q-22.09 0-37.55-15.46-15.45-15.46-15.45-37.54v-601h-441q-22.09 0-37.55-15.46-15.45-15.45-15.45-37.54t15.45-37.55q15.46-15.45 37.55-15.45h441q44.3 0 75.15 30.85 30.85 30.84 30.85 75.15v601q0 22.08-15.46 37.54t-37.54 15.46Z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M387-150.39 241.04-86.87q-53 22.65-100.87-8.48-47.87-31.13-47.87-88.83v-461.34q0-44.3 30.85-75.15 30.85-30.85 75.15-30.85h377.39q44.31 0 75.16 30.85 30.85 30.85 30.85 75.15v461.34q0 57.7-47.87 88.83-47.87 31.13-100.88 8.48L387-150.39Zm427.7-27.13q-22.09 0-37.55-15.46-15.45-15.46-15.45-37.54v-601h-441q-22.09 0-37.55-15.46-15.45-15.45-15.45-37.54t15.45-37.55q15.46-15.45 37.55-15.45h441q44.3 0 75.15 30.85 30.85 30.84 30.85 75.15v601q0 22.08-15.46 37.54t-37.54 15.46Z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M166.78-140.78q-44.3 0-75.15-30.85-30.85-30.85-30.85-75.15v-466.44q0-44.87 30.85-75.43 30.85-30.57 75.15-30.57h181q21.09 0 40.39 7.98 19.31 7.98 34.26 22.94L480-730.74h366.22q22.08 0 37.54 15.46 15.46 15.45 15.46 37.54t-15.46 37.54q-15.46 15.46-37.54 15.46H340.57q-69.35 0-121.57 43.52-52.22 43.53-52.22 110.31v226.95l70.52-226.82q10.83-33.35 38.55-53.65 27.72-20.31 62.76-20.31h471.91q54 0 85.7 43.52 31.69 43.53 15.61 94.53l-53.92 174.43q-14.78 45.78-46.17 68.63-31.39 22.85-78.31 22.85H166.78Z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M166.78-140.78q-44.3 0-75.15-30.85-30.85-30.85-30.85-75.15v-466.44q0-44.87 30.85-75.43 30.85-30.57 75.15-30.57h181q21.09 0 40.39 7.98 19.31 7.98 34.26 22.94L480-730.74h366.22q22.08 0 37.54 15.46 15.46 15.45 15.46 37.54t-15.46 37.54q-15.46 15.46-37.54 15.46H340.57q-69.35 0-121.57 43.52-52.22 43.53-52.22 110.31v226.95l70.52-226.82q10.83-33.35 38.55-53.65 27.72-20.31 62.76-20.31h471.91q54 0 85.7 43.52 31.69 43.53 15.61 94.53l-53.92 174.43q-14.78 45.78-46.17 68.63-31.39 22.85-78.31 22.85H166.78Z" /></svg>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" height="128" view
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M560-120v-66q0-8 3-15.5t9-13.5l209-208q9-9 20-13t22-4q12 0 23 4.5t20 13.5l37 37q8 9 12.5 20t4.5 22q0 11-4 22.5T903-300L695-92q-6 6-13.5 9T666-80h-66q-17 0-28.5-11.5T560-120Zm263-184 37-39-37-37-38 38 38 38ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h207q16 0 30.5 6t25.5 17l57 57h320q33 0 56.5 23.5T880-640v83q0 18-14.5 29t-33.5 8h-11q-28 0-52.5 10T724-480L503-259q-11 11-17 25.5t-6 30.5v3q0 17-11.5 28.5T440-160H160Z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M560-120v-66q0-8 3-15.5t9-13.5l209-208q9-9 20-13t22-4q12 0 23 4.5t20 13.5l37 37q8 9 12.5 20t4.5 22q0 11-4 22.5T903-300L695-92q-6 6-13.5 9T666-80h-66q-17 0-28.5-11.5T560-120Zm263-184 37-39-37-37-38 38 38 38ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h207q16 0 30.5 6t25.5 17l57 57h320q33 0 56.5 23.5T880-640v83q0 18-14.5 29t-33.5 8h-11q-28 0-52.5 10T724-480L503-259q-11 11-17 25.5t-6 30.5v3q0 17-11.5 28.5T440-160H160Z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M380-320q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l224 224q11 11 11 28t-11 28q-11 11-28 11t-28-11L532-372q-30 24-69 38t-83 14Zm0-80q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M380-320q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l224 224q11 11 11 28t-11 28q-11 11-28 11t-28-11L532-372q-30 24-69 38t-83 14Zm0-80q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M680-160q-17 0-28.5-11.5T640-200v-200q0-17 11.5-28.5T680-440h80q17 0 28.5 11.5T800-400v200q0 17-11.5 28.5T760-160h-80Zm-240 0q-17 0-28.5-11.5T400-200v-560q0-17 11.5-28.5T440-800h80q17 0 28.5 11.5T560-760v560q0 17-11.5 28.5T520-160h-80Zm-240 0q-17 0-28.5-11.5T160-200v-360q0-17 11.5-28.5T200-600h80q17 0 28.5 11.5T320-560v360q0 17-11.5 28.5T280-160h-80Z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M680-160q-17 0-28.5-11.5T640-200v-200q0-17 11.5-28.5T680-440h80q17 0 28.5 11.5T800-400v200q0 17-11.5 28.5T760-160h-80Zm-240 0q-17 0-28.5-11.5T400-200v-560q0-17 11.5-28.5T440-800h80q17 0 28.5 11.5T560-760v560q0 17-11.5 28.5T520-160h-80Zm-240 0q-17 0-28.5-11.5T160-200v-360q0-17 11.5-28.5T200-600h80q17 0 28.5 11.5T320-560v360q0 17-11.5 28.5T280-160h-80Z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480q0 83-58.5 141.5T480-280ZM80-440q-17 0-28.5-11.5T40-480q0-17 11.5-28.5T80-520h80q17 0 28.5 11.5T200-480q0 17-11.5 28.5T160-440H80Zm720 0q-17 0-28.5-11.5T760-480q0-17 11.5-28.5T800-520h80q17 0 28.5 11.5T920-480q0 17-11.5 28.5T880-440h-80ZM480-760q-17 0-28.5-11.5T440-800v-80q0-17 11.5-28.5T480-920q17 0 28.5 11.5T520-880v80q0 17-11.5 28.5T480-760Zm0 720q-17 0-28.5-11.5T440-80v-80q0-17 11.5-28.5T480-200q17 0 28.5 11.5T520-160v80q0 17-11.5 28.5T480-40ZM226-678l-43-42q-12-11-11.5-28t11.5-29q12-12 29-12t28 12l42 43q11 12 11 28t-11 28q-11 12-27.5 11.5T226-678Zm494 495-42-43q-11-12-11-28.5t11-27.5q11-12 27.5-11.5T734-282l43 42q12 11 11.5 28T777-183q-12 12-29 12t-28-12Zm-42-495q-12-11-11.5-27.5T678-734l42-43q11-12 28-11.5t29 11.5q12 12 12 29t-12 28l-43 42q-12 11-28 11t-28-11ZM183-183q-12-12-12-29t12-28l43-42q12-11 28.5-11t27.5 11q12 11 11.5 27.5T282-226l-42 43q-11 12-28 11.5T183-183Z" /></svg>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-120q-151 0-255.5-104.5T120-480q0-138 90-239.5T440-838q13-2 23 3.5t16 14.5q6 9 6.5 21t-7.5 23q-17 26-25.5 55t-8.5 61q0 90 63 153t153 63q31 0 61.5-9t54.5-25q11-7 22.5-6.5T819-479q10 5 15.5 15t3.5 24q-14 138-117.5 229T480-120Z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm40-83q119-15 199.5-104.5T800-480q0-123-80.5-212.5T520-797v634Z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M440-440H240q-17 0-28.5-11.5T200-480q0-17 11.5-28.5T240-520h200v-200q0-17 11.5-28.5T480-760q17 0 28.5 11.5T520-720v200h200q17 0 28.5 11.5T760-480q0 17-11.5 28.5T720-440H520v200q0 17-11.5 28.5T480-200q-17 0-28.5-11.5T440-240v-200Z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M440-440H240q-17 0-28.5-11.5T200-480q0-17 11.5-28.5T240-520h200v-200q0-17 11.5-28.5T480-760q17 0 28.5 11.5T520-720v200h200q17 0 28.5 11.5T760-480q0 17-11.5 28.5T720-440H520v200q0 17-11.5 28.5T480-200q-17 0-28.5-11.5T440-240v-200Z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M400-160 232-88q-40 17-76-6.5T120-161v-519q0-33 23.5-56.5T200-760h400q33 0 56.5 23.5T680-680v519q0 43-36 66.5T568-88l-168-72Zm400 0q-17 0-28.5-11.5T760-200v-640H280q-17 0-28.5-11.5T240-880q0-17 11.5-28.5T280-920h480q33 0 56.5 23.5T840-840v640q0 17-11.5 28.5T800-160Z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M400-160 232-88q-40 17-76-6.5T120-161v-519q0-33 23.5-56.5T200-760h400q33 0 56.5 23.5T680-680v519q0 43-36 66.5T568-88l-168-72Zm400 0q-17 0-28.5-11.5T760-200v-640H280q-17 0-28.5-11.5T240-880q0-17 11.5-28.5T280-920h480q33 0 56.5 23.5T840-840v640q0 17-11.5 28.5T800-160Z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h207q16 0 30.5 6t25.5 17l57 57h360q17 0 28.5 11.5T880-680q0 17-11.5 28.5T840-640H314q-62 0-108 39t-46 99v262l79-263q8-26 29.5-41.5T316-560h516q41 0 64.5 32.5T909-457l-72 240q-8 26-29.5 41.5T760-160H160Z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h207q16 0 30.5 6t25.5 17l57 57h360q17 0 28.5 11.5T880-680q0 17-11.5 28.5T840-640H314q-62 0-108 39t-46 99v262l79-263q8-26 29.5-41.5T316-560h516q41 0 64.5 32.5T909-457l-72 240q-8 26-29.5 41.5T760-160H160Z" /></svg>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" height="128" view
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M569.23-152.31v-42.92q0-6.46 2.23-12.04 2.23-5.58 7.46-10.81l203.62-202.61q5.92-5.16 12.31-7.62 6.38-2.46 12.77-2.46 6.61 0 13.38 2.58 6.77 2.57 11.92 7.73l37 37.77q4.93 5.92 7.5 12.31Q880-364 880-357.62q0 6.39-2.08 12.89-2.07 6.5-8 12.42L667.31-129.69q-5.23 5.23-10.81 7.46-5.58 2.23-12.04 2.23h-42.92q-13.92 0-23.12-9.19-9.19-9.19-9.19-23.12Zm238.39-167.07 37-38.24-37-37.76-38 38 38 38ZM184.62-200q-27.62 0-46.12-18.5Q120-237 120-264.62v-430.76q0-27.62 18.5-46.12Q157-760 184.62-760H357q12.92 0 25.12 5.23 12.19 5.23 20.88 13.92L463.85-680h311.53q27.62 0 46.12 18.5Q840-643 840-615.38v61.46q0 12.61-9.88 20.92-9.89 8.31-22.74 6.85H804.85q-22.62 0-44.43 8.46-21.8 8.46-40.27 24.61L493-266.69q-8.69 8.69-13.92 20.5t-5.23 24.73v.69q0 8.54-6.12 14.65-6.11 6.12-14.65 6.12H184.62Z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M569.23-152.31v-42.92q0-6.46 2.23-12.04 2.23-5.58 7.46-10.81l203.62-202.61q5.92-5.16 12.31-7.62 6.38-2.46 12.77-2.46 6.61 0 13.38 2.58 6.77 2.57 11.92 7.73l37 37.77q4.93 5.92 7.5 12.31Q880-364 880-357.62q0 6.39-2.08 12.89-2.07 6.5-8 12.42L667.31-129.69q-5.23 5.23-10.81 7.46-5.58 2.23-12.04 2.23h-42.92q-13.92 0-23.12-9.19-9.19-9.19-9.19-23.12Zm238.39-167.07 37-38.24-37-37.76-38 38 38 38ZM184.62-200q-27.62 0-46.12-18.5Q120-237 120-264.62v-430.76q0-27.62 18.5-46.12Q157-760 184.62-760H357q12.92 0 25.12 5.23 12.19 5.23 20.88 13.92L463.85-680h311.53q27.62 0 46.12 18.5Q840-643 840-615.38v61.46q0 12.61-9.88 20.92-9.89 8.31-22.74 6.85H804.85q-22.62 0-44.43 8.46-21.8 8.46-40.27 24.61L493-266.69q-8.69 8.69-13.92 20.5t-5.23 24.73v.69q0 8.54-6.12 14.65-6.11 6.12-14.65 6.12H184.62Z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M381.54-350.77q-95.92 0-162.58-66.65-66.65-66.66-66.65-162.58 0-95.92 66.65-162.58 66.66-66.65 162.58-66.65 95.92 0 162.58 66.65 66.65 66.66 66.65 162.58 0 41.69-14.77 80.69t-38.77 66.69l236.31 236.31q5.61 5.62 6 13.77.38 8.16-6 14.54-6.39 6.38-14.16 6.38-7.76 0-14.15-6.38L528.92-404.31q-30 25.54-69 39.54t-78.38 14Zm0-40q79.61 0 134.42-54.81 54.81-54.8 54.81-134.42 0-79.62-54.81-134.42-54.81-54.81-134.42-54.81-79.62 0-134.42 54.81-54.81 54.8-54.81 134.42 0 79.62 54.81 134.42 54.8 54.81 134.42 54.81Z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M381.54-350.77q-95.92 0-162.58-66.65-66.65-66.66-66.65-162.58 0-95.92 66.65-162.58 66.66-66.65 162.58-66.65 95.92 0 162.58 66.65 66.65 66.66 66.65 162.58 0 41.69-14.77 80.69t-38.77 66.69l236.31 236.31q5.61 5.62 6 13.77.38 8.16-6 14.54-6.39 6.38-14.16 6.38-7.76 0-14.15-6.38L528.92-404.31q-30 25.54-69 39.54t-78.38 14Zm0-40q79.61 0 134.42-54.81 54.81-54.8 54.81-134.42 0-79.62-54.81-134.42-54.81-54.81-134.42-54.81-79.62 0-134.42 54.81-54.81 54.8-54.81 134.42 0 79.62 54.81 134.42 54.8 54.81 134.42 54.81Z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M672.31-200q-13.73 0-23.02-9.29T640-232.31V-360q0-13.73 9.29-23.02t23.02-9.29h55.38q13.73 0 23.02 9.29T760-360v127.69q0 13.73-9.29 23.02T727.69-200h-55.38Zm-220 0q-13.73 0-23.02-9.29T420-232.31v-495.38q0-13.73 9.29-23.02t23.02-9.29h55.38q13.73 0 23.02 9.29t9.29 23.02v495.38q0 13.73-9.29 23.02T507.69-200h-55.38Zm-220 0q-13.73 0-23.02-9.29T200-232.31v-302.7q0-14.3 9.29-23.49 9.29-9.19 23.02-9.19h55.38q13.73 0 23.02 9.29 9.29 9.28 9.29 23.02v302.7q0 14.3-9.29 23.49-9.29 9.19-23.02 9.19h-55.38Z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M672.31-200q-13.73 0-23.02-9.29T640-232.31V-360q0-13.73 9.29-23.02t23.02-9.29h55.38q13.73 0 23.02 9.29T760-360v127.69q0 13.73-9.29 23.02T727.69-200h-55.38Zm-220 0q-13.73 0-23.02-9.29T420-232.31v-495.38q0-13.73 9.29-23.02t23.02-9.29h55.38q13.73 0 23.02 9.29t9.29 23.02v495.38q0 13.73-9.29 23.02T507.69-200h-55.38Zm-220 0q-13.73 0-23.02-9.29T200-232.31v-302.7q0-14.3 9.29-23.49 9.29-9.19 23.02-9.19h55.38q13.73 0 23.02 9.29 9.29 9.28 9.29 23.02v302.7q0 14.3-9.29 23.49-9.29 9.19-23.02 9.19h-55.38Z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-320q-66.85 0-113.42-46.58Q320-413.15 320-480t46.58-113.42Q413.15-640 480-640t113.42 46.58Q640-546.85 640-480t-46.58 113.42Q546.85-320 480-320ZM80-460q-8.5 0-14.25-5.76T60-480.03q0-8.51 5.75-14.24T80-500h100q8.5 0 14.25 5.76t5.75 14.27q0 8.51-5.75 14.24T180-460H80Zm700 0q-8.5 0-14.25-5.76T760-480.03q0-8.51 5.75-14.24T780-500h100q8.5 0 14.25 5.76t5.75 14.27q0 8.51-5.75 14.24T880-460H780ZM479.97-760q-8.51 0-14.24-5.75T460-780v-100q0-8.5 5.76-14.25t14.27-5.75q8.51 0 14.24 5.75T500-880v100q0 8.5-5.76 14.25T479.97-760Zm0 700q-8.51 0-14.24-5.75T460-80v-100q0-8.5 5.76-14.25t14.27-5.75q8.51 0 14.24 5.75T500-180v100q0 8.5-5.76 14.25T479.97-60ZM254.46-678.77l-57.61-55.85q-5.85-5.61-5.73-13.76.11-8.16 5.96-14.77 6.38-6.62 14.15-6.62 7.77 0 14.15 6.62L282-706.31q6.38 6.62 6.38 14.16 0 7.53-6 14.15t-13.65 6.12q-7.65-.5-14.27-6.89Zm480.16 481.92L678-253.69q-6.38-6.62-6.38-14.27 0-7.66 6.38-14.04 5.23-6.62 13.08-6.12 7.84.5 14.46 6.89l57.61 55.85q5.85 5.61 5.73 13.76-.11 8.16-5.96 14.77-6.38 6.62-14.15 6.62-7.77 0-14.15-6.62ZM678-677.62q-6.62-6-6.12-13.65t6.89-14.27l55.85-57.61q5.61-5.85 13.76-5.73 8.16.11 14.77 5.96 6.62 6.38 6.62 14.15 0 7.77-6.62 14.15L706.31-678q-6.62 6.38-14.16 6.38-7.53 0-14.15-6ZM196.85-196.68q-6.62-6.78-6.62-14.55 0-7.77 6.62-14.15L253.69-282q6.62-6.38 14.27-6.38 7.66 0 14.04 6.38 5.85 5.23 5.35 13.08-.5 7.84-6.12 14.46l-55.85 57.61q-6.38 6.62-14.15 6.5-7.77-.11-14.38-6.33Z" /></svg>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M482.31-160Q349-160 255.65-253.35 162.31-346.69 162.31-480q0-98.77 56.54-181.42 56.53-82.66 160.38-118.89 12.23-4.31 21.46-2.27 9.23 2.04 15.23 7.96 6 5.93 7.66 15.24 1.65 9.3-2.5 19.53-7.77 19.08-11.27 38.85-3.5 19.77-3.5 41 0 106.92 74.54 181.46Q555.38-404 662.31-404q27.92 0 51.11-5.92 23.2-5.93 39.5-9.62 8.7-1.61 15.96.42 7.27 2.04 11.66 7.04 4.61 5 6.27 12.31 1.65 7.31-1.89 16.69-28.61 98-112.11 160.54Q589.31-160 482.31-160Z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480.13-120q-74.67 0-140.41-28.34-65.73-28.34-114.36-76.92-48.63-48.58-76.99-114.26Q120-405.19 120-479.87q0-74.67 28.34-140.41 28.34-65.73 76.92-114.36 48.58-48.63 114.26-76.99Q405.19-840 479.87-840q74.67 0 140.41 28.34 65.73 28.34 114.36 76.92 48.63 48.58 76.99 114.26Q840-554.81 840-480.13q0 74.67-28.34 140.41-28.34 65.73-76.92 114.36-48.58 48.63-114.26 76.99Q554.81-120 480.13-120ZM500-160.69q123.62-8.08 211.81-98.35T800-480q0-130.69-87.42-220.19-87.43-89.5-212.58-99.12v638.62Z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M460-460H260q-8.5 0-14.25-5.76T240-480.03q0-8.51 5.75-14.24T260-500h200v-200q0-8.5 5.76-14.25t14.27-5.75q8.51 0 14.24 5.75T500-700v200h200q8.5 0 14.25 5.76t5.75 14.27q0 8.51-5.75 14.24T700-460H500v200q0 8.5-5.76 14.25T479.97-240q-8.51 0-14.24-5.75T460-260v-200Z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M460-460H260q-8.5 0-14.25-5.76T240-480.03q0-8.51 5.75-14.24T260-500h200v-200q0-8.5 5.76-14.25t14.27-5.75q8.51 0 14.24 5.75T500-700v200h200q8.5 0 14.25 5.76t5.75 14.27q0 8.51-5.75 14.24T700-460H500v200q0 8.5-5.76 14.25T479.97-240q-8.51 0-14.24-5.75T460-260v-200Z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="m420-203.08-149.54 64.31q-32.31 13.92-61.38-5.35Q180-163.38 180-197.92v-457.46q0-27.62 18.5-46.12Q217-720 244.62-720h350.76q27.62 0 46.12 18.5Q660-683 660-655.38v457.46q0 34.54-29.08 53.8-29.07 19.27-61.38 5.35L420-203.08ZM760-220q-8.54 0-14.27-5.73T740-240v-535.39q0-9.23-7.69-16.92-7.69-7.69-16.93-7.69H320q-8.54 0-14.27-5.73T300-820q0-8.54 5.73-14.27T320-840h395.38q27.62 0 46.12 18.5Q780-803 780-775.39V-240q0 8.54-5.73 14.27T760-220Z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="m420-203.08-149.54 64.31q-32.31 13.92-61.38-5.35Q180-163.38 180-197.92v-457.46q0-27.62 18.5-46.12Q217-720 244.62-720h350.76q27.62 0 46.12 18.5Q660-683 660-655.38v457.46q0 34.54-29.08 53.8-29.07 19.27-61.38 5.35L420-203.08ZM760-220q-8.54 0-14.27-5.73T740-240v-535.39q0-9.23-7.69-16.92-7.69-7.69-16.93-7.69H320q-8.54 0-14.27-5.73T300-820q0-8.54 5.73-14.27T320-840h395.38q27.62 0 46.12 18.5Q780-803 780-775.39V-240q0 8.54-5.73 14.27T760-220Z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M180-200q-25.31 0-42.65-17.35Q120-234.69 120-260v-435.38q0-25.31 19.65-44.97Q159.31-760 184.62-760H357q12.92 0 25.12 5.23 12.19 5.23 20.88 13.92L463.85-680h349.23q8.54 0 14.27 5.73t5.73 14.27q0 8.54-5.73 14.27T813.08-640H297.85Q242-640 201-604.08q-41 35.93-41 90.54v248.92q0 8.47 4.23 13.85 4.23 5.39 11.15 9.23l76.7-256.84q6.46-20.62 23.73-33.43 17.27-12.81 38.65-12.81h512.92q32.54 0 52.2 25.97 19.65 25.96 10.19 57.03l-65.85 219.24q-5.69 19.07-21.8 30.73Q786-200 766.15-200H180Z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M180-200q-25.31 0-42.65-17.35Q120-234.69 120-260v-435.38q0-25.31 19.65-44.97Q159.31-760 184.62-760H357q12.92 0 25.12 5.23 12.19 5.23 20.88 13.92L463.85-680h349.23q8.54 0 14.27 5.73t5.73 14.27q0 8.54-5.73 14.27T813.08-640H297.85Q242-640 201-604.08q-41 35.93-41 90.54v248.92q0 8.47 4.23 13.85 4.23 5.39 11.15 9.23l76.7-256.84q6.46-20.62 23.73-33.43 17.27-12.81 38.65-12.81h512.92q32.54 0 52.2 25.97 19.65 25.96 10.19 57.03l-65.85 219.24q-5.69 19.07-21.8 30.73Q786-200 766.15-200H180Z" /></svg>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" height="128" view
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M166.78-246.78v-466.44 466.44Zm0 106q-44.3 0-75.15-30.85-30.85-30.85-30.85-75.15v-466.44q0-44.3 30.85-75.15 30.85-30.85 75.15-30.85h181q21.23 0 40.46 7.98 19.24 7.98 34.19 22.94L480-730.74h313.22q44.3 0 75.15 30.85 30.85 30.85 30.85 75.15v51.17q0 22.09-15.46 37.55-15.46 15.45-37.54 15.45-22.09 0-37.55-15.45-15.45-15.46-15.45-37.55v-51.17H436.26l-88.48-88.48h-181v466.44h256.83q22.09 0 37.54 15.45 15.46 15.46 15.46 37.55 0 22.08-15.46 37.54-15.45 15.46-37.54 15.46H166.78Zm389.83 27v-63.74q0-10.83 4.13-20.31 4.13-9.47 11.83-17.17L781-423q10.7-10.8 23.77-15.59 13.07-4.8 26.14-4.8 14.26 0 27.27 5.35 13.01 5.34 23.65 16.04l37 37q9.59 10.7 14.99 23.77t5.4 26.14q0 13.83-4.85 27.03-4.85 13.19-15.54 23.89l-208 208q-7.62 7.69-17.14 11.54-9.52 3.85-20.34 3.85h-63.74q-22.09 0-37.54-15.46-15.46-15.46-15.46-37.54Zm311.3-221.31-37-37 37 37Zm-240 203h38l118.74-119.74-18-19-19-18-119.74 118.74v38Zm138.74-138.74-19-18 37 37-18-19Z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M166.78-246.78v-466.44 466.44Zm0 106q-44.3 0-75.15-30.85-30.85-30.85-30.85-75.15v-466.44q0-44.3 30.85-75.15 30.85-30.85 75.15-30.85h181q21.23 0 40.46 7.98 19.24 7.98 34.19 22.94L480-730.74h313.22q44.3 0 75.15 30.85 30.85 30.85 30.85 75.15v51.17q0 22.09-15.46 37.55-15.46 15.45-37.54 15.45-22.09 0-37.55-15.45-15.45-15.46-15.45-37.55v-51.17H436.26l-88.48-88.48h-181v466.44h256.83q22.09 0 37.54 15.45 15.46 15.46 15.46 37.55 0 22.08-15.46 37.54-15.45 15.46-37.54 15.46H166.78Zm389.83 27v-63.74q0-10.83 4.13-20.31 4.13-9.47 11.83-17.17L781-423q10.7-10.8 23.77-15.59 13.07-4.8 26.14-4.8 14.26 0 27.27 5.35 13.01 5.34 23.65 16.04l37 37q9.59 10.7 14.99 23.77t5.4 26.14q0 13.83-4.85 27.03-4.85 13.19-15.54 23.89l-208 208q-7.62 7.69-17.14 11.54-9.52 3.85-20.34 3.85h-63.74q-22.09 0-37.54-15.46-15.46-15.46-15.46-37.54Zm311.3-221.31-37-37 37 37Zm-240 203h38l118.74-119.74-18-19-19-18-119.74 118.74v38Zm138.74-138.74-19-18 37 37-18-19Z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M375.48-307q-114.09 0-193.55-79.46-79.45-79.45-79.45-193.54 0-114.09 79.45-193.54Q261.39-853 375.48-853q114.09 0 193.54 79.46 79.46 79.45 79.46 193.54 0 45.13-12.87 83.28T601-429.7l219.48 220.05q14.96 15.52 14.96 37.32 0 21.81-15.53 36.77-14.95 14.95-37.04 14.95t-37.04-14.95L526.91-354.48q-29.43 21.74-68.15 34.61Q420.04-307 375.48-307Zm0-106q69.91 0 118.45-48.54 48.55-48.55 48.55-118.46t-48.55-118.46Q445.39-747 375.48-747t-118.46 48.54Q208.48-649.91 208.48-580t48.54 118.46Q305.57-413 375.48-413Z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M375.48-307q-114.09 0-193.55-79.46-79.45-79.45-79.45-193.54 0-114.09 79.45-193.54Q261.39-853 375.48-853q114.09 0 193.54 79.46 79.46 79.45 79.46 193.54 0 45.13-12.87 83.28T601-429.7l219.48 220.05q14.96 15.52 14.96 37.32 0 21.81-15.53 36.77-14.95 14.95-37.04 14.95t-37.04-14.95L526.91-354.48q-29.43 21.74-68.15 34.61Q420.04-307 375.48-307Zm0-106q69.91 0 118.45-48.54 48.55-48.55 48.55-118.46t-48.55-118.46Q445.39-747 375.48-747t-118.46 48.54Q208.48-649.91 208.48-580t48.54 118.46Q305.57-413 375.48-413Z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M694.7-140.78q-22.09 0-37.55-15.46-15.45-15.46-15.45-37.54v-201.13q0-22.09 15.45-37.55 15.46-15.45 37.55-15.45h71.52q22.08 0 37.54 15.45 15.46 15.46 15.46 37.55v201.13q0 22.08-15.46 37.54t-37.54 15.46H694.7Zm-250.18 0q-22.09 0-37.54-15.46-15.46-15.46-15.46-37.54v-572.44q0-22.08 15.46-37.54 15.45-15.46 37.54-15.46h70.96q22.09 0 37.54 15.46 15.46 15.46 15.46 37.54v572.44q0 22.08-15.46 37.54-15.45 15.46-37.54 15.46h-70.96Zm-250.74 0q-22.08 0-37.54-15.46t-15.46-37.54v-372.44q0-22.08 15.46-37.54t37.54-15.46h71.52q22.09 0 37.55 15.46 15.45 15.46 15.45 37.54v372.44q0 22.08-15.45 37.54-15.46 15.46-37.55 15.46h-71.52Z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M694.7-140.78q-22.09 0-37.55-15.46-15.45-15.46-15.45-37.54v-201.13q0-22.09 15.45-37.55 15.46-15.45 37.55-15.45h71.52q22.08 0 37.54 15.45 15.46 15.46 15.46 37.55v201.13q0 22.08-15.46 37.54t-37.54 15.46H694.7Zm-250.18 0q-22.09 0-37.54-15.46-15.46-15.46-15.46-37.54v-572.44q0-22.08 15.46-37.54 15.45-15.46 37.54-15.46h70.96q22.09 0 37.54 15.46 15.46 15.46 15.46 37.54v572.44q0 22.08-15.46 37.54-15.45 15.46-37.54 15.46h-70.96Zm-250.74 0q-22.08 0-37.54-15.46t-15.46-37.54v-372.44q0-22.08 15.46-37.54t37.54-15.46h71.52q22.09 0 37.55 15.46 15.45 15.46 15.45 37.54v372.44q0 22.08-15.45 37.54-15.46 15.46-37.55 15.46h-71.52Z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-386q39.26 0 66.63-27.37Q574-440.74 574-480q0-39.26-27.37-66.63Q519.26-574 480-574q-39.26 0-66.63 27.37Q386-519.26 386-480q0 39.26 27.37 66.63Q440.74-386 480-386Zm0 106q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480q0 83-58.5 141.5T480-280ZM80-427q-22.09 0-37.54-15.46Q27-457.91 27-480t15.46-37.54Q57.91-533 80-533h80q22.09 0 37.54 15.46Q213-502.09 213-480t-15.46 37.54Q182.09-427 160-427H80Zm720 0q-22.09 0-37.54-15.46Q747-457.91 747-480t15.46-37.54Q777.91-533 800-533h80q22.09 0 37.54 15.46Q933-502.09 933-480t-15.46 37.54Q902.09-427 880-427h-80ZM480-747q-22.09 0-37.54-15.46Q427-777.91 427-800v-80q0-22.09 15.46-37.54Q457.91-933 480-933t37.54 15.46Q533-902.09 533-880v80q0 22.09-15.46 37.54Q502.09-747 480-747Zm0 720q-22.09 0-37.54-15.46Q427-57.91 427-80v-80q0-22.09 15.46-37.54Q457.91-213 480-213t37.54 15.46Q533-182.09 533-160v80q0 22.09-15.46 37.54Q502.09-27 480-27ZM216.96-668.39l-43-42Q158-725.35 158.5-747.43q.5-22.09 15.46-38.61Q189.35-802 211.43-802q22.09 0 37.61 15.96l42.57 43q14.96 15.39 14.67 36.76-.28 21.37-14.67 37.32-14.96 15.96-36.83 16.03-21.87.06-37.82-15.46Zm494 494.43-42.57-43q-14.96-15.39-14.96-36.97 0-21.59 14.96-37.11 14.96-15.96 36.83-15.46 21.87.5 37.82 15.46l43 41.43q15.96 14.96 15.46 37.04-.5 22.09-15.46 38.61Q770.65-158 748.57-158q-22.09 0-37.61-15.96Zm-42-494.43Q653-683.35 653.5-705.22q.5-21.87 15.46-37.82l41.43-43q14.96-15.96 37.04-15.46 22.09.5 38.61 15.46Q802-770.65 802-748.57q0 22.09-15.96 37.61l-43 42.57q-15.39 14.96-36.76 14.67-21.37-.28-37.32-14.67Zm-495 494.43Q158-189.35 158-211.43q0-22.09 15.96-37.61l43-42.57q15.39-14.96 36.97-14.96 21.59 0 37.11 14.96 15.96 14.96 15.46 36.83-.5 21.87-15.46 37.82l-41.43 43Q234.65-158 212.57-158.5q-22.09-.5-38.61-15.46ZM480-480Z" /></svg>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480.57-111.52q-157.22 0-263.14-105.63Q111.52-322.78 111.52-480q0-128.39 77.57-229.89 77.56-101.5 214.17-129.24 18.65-5.39 33.74-1.59 15.09 3.81 25.33 13.37 10.23 9.57 13.84 23.83 3.61 14.26-1 30.35-9.65 23.74-15.6 47.08-5.96 23.35-5.96 48 0 94.01 66.13 159.81t160.61 65.8q24.78 0 49.63-5.32 24.85-5.33 46.02-14.55 15.52-4.17 28.72-.85 13.19 3.33 21.93 11.72 9.7 8.39 13.5 22.63 3.81 14.24-1.02 33.33Q814.96-276 713.72-193.76q-101.24 82.24-233.15 82.24Zm0-106q73.3 0 133.97-37.2 60.68-37.19 93.24-98.8-14.35 2.74-28.41 4.04-14.07 1.31-27.85.18-120.74-9.61-205.82-93.29-85.09-83.67-95.83-208.93-.57-13.78.46-28.13 1.02-14.35 4.32-28.13-61.04 33.13-98.8 94.09-37.76 60.95-37.76 133.69 0 108.74 76.87 185.61 76.86 76.87 185.61 76.87Zm-17.35-245.13Z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M479.95-60.78q-86.91 0-163.3-32.91-76.39-32.92-133.22-89.74-56.82-56.83-89.74-133.27-32.91-76.44-32.91-163.35t32.91-163.3q32.92-76.39 89.74-133.22 56.83-56.82 133.27-89.74 76.44-32.91 163.35-32.91t163.3 32.91q76.39 32.92 133.22 89.74 56.82 56.83 89.74 133.27 32.91 76.44 32.91 163.35t-32.91 163.3q-32.92 76.39-89.74 133.22-56.83 56.82-133.27 89.74-76.44 32.91-163.35 32.91Zm46.83-110.13Q641.26-188.17 717.24-274t75.98-206q0-118.63-75.98-204.94-75.98-86.32-190.46-103.58v617.61Z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M427-427H233.78q-22.08 0-37.54-15.46-15.46-15.45-15.46-37.54t15.46-37.54Q211.7-533 233.78-533H427v-193.22q0-22.08 15.46-37.54 15.45-15.46 37.54-15.46t37.54 15.46Q533-748.3 533-726.22V-533h193.22q22.08 0 37.54 15.46 15.46 15.45 15.46 37.54t-15.46 37.54Q748.3-427 726.22-427H533v193.22q0 22.08-15.46 37.54-15.45 15.46-37.54 15.46t-37.54-15.46Q427-211.7 427-233.78V-427Z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M427-427H233.78q-22.08 0-37.54-15.46-15.46-15.45-15.46-37.54t15.46-37.54Q211.7-533 233.78-533H427v-193.22q0-22.08 15.46-37.54 15.45-15.46 37.54-15.46t37.54 15.46Q533-748.3 533-726.22V-533h193.22q22.08 0 37.54 15.46 15.46 15.45 15.46 37.54t-15.46 37.54Q748.3-427 726.22-427H533v193.22q0 22.08-15.46 37.54-15.45 15.46-37.54 15.46t-37.54-15.46Q427-211.7 427-233.78V-427Z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M387-150.39 241.04-86.87q-53 22.65-100.87-8.48-47.87-31.13-47.87-88.83v-461.34q0-44.3 30.85-75.15 30.85-30.85 75.15-30.85h377.39q44.31 0 75.16 30.85 30.85 30.85 30.85 75.15v461.34q0 57.7-47.87 88.83-47.87 31.13-100.88 8.48L387-150.39Zm0-115.7 188.69 82.61v-462.04H198.3v462.04L387-266.09Zm427.7 88.57q-22.09 0-37.55-15.46-15.45-15.46-15.45-37.54v-601h-441q-22.09 0-37.55-15.46-15.45-15.45-15.45-37.54t15.45-37.55q15.46-15.45 37.55-15.45h441q44.3 0 75.15 30.85 30.85 30.84 30.85 75.15v601q0 22.08-15.46 37.54t-37.54 15.46Zm-427.7-468H198.3h377.39H387Z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M387-150.39 241.04-86.87q-53 22.65-100.87-8.48-47.87-31.13-47.87-88.83v-461.34q0-44.3 30.85-75.15 30.85-30.85 75.15-30.85h377.39q44.31 0 75.16 30.85 30.85 30.85 30.85 75.15v461.34q0 57.7-47.87 88.83-47.87 31.13-100.88 8.48L387-150.39Zm0-115.7 188.69 82.61v-462.04H198.3v462.04L387-266.09Zm427.7 88.57q-22.09 0-37.55-15.46-15.45-15.46-15.45-37.54v-601h-441q-22.09 0-37.55-15.46-15.45-15.45-15.45-37.54t15.45-37.55q15.46-15.45 37.55-15.45h441q44.3 0 75.15 30.85 30.85 30.84 30.85 75.15v601q0 22.08-15.46 37.54t-37.54 15.46Zm-427.7-468H198.3h377.39H387Z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M166.78-140.78q-44.3 0-75.15-30.85-30.85-30.85-30.85-75.15v-466.44q0-44.87 30.85-75.43 30.85-30.57 75.15-30.57h181q21.23 0 40.46 7.98 19.24 7.98 34.19 22.94L480-730.74h366.22q22.08 0 37.54 15.46 15.46 15.45 15.46 37.54t-15.46 37.54q-15.46 15.46-37.54 15.46H436.26l-88.48-88.48h-181v469.26l70.52-226.82q10.83-33.35 38.55-53.65 27.72-20.31 62.76-20.31h471.91q54 0 85.7 43.52 31.69 43.53 15.61 94.53l-53.92 174.43q-14.78 45.78-46.17 68.63-31.39 22.85-78.31 22.85H166.78Zm112.83-106h471.35l59-191.96H338.61l-59 191.96ZM166.78-470.91v-242.31 242.31Zm112.83 224.13 59-191.96-59 191.96Z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M166.78-140.78q-44.3 0-75.15-30.85-30.85-30.85-30.85-75.15v-466.44q0-44.87 30.85-75.43 30.85-30.57 75.15-30.57h181q21.23 0 40.46 7.98 19.24 7.98 34.19 22.94L480-730.74h366.22q22.08 0 37.54 15.46 15.46 15.45 15.46 37.54t-15.46 37.54q-15.46 15.46-37.54 15.46H436.26l-88.48-88.48h-181v469.26l70.52-226.82q10.83-33.35 38.55-53.65 27.72-20.31 62.76-20.31h471.91q54 0 85.7 43.52 31.69 43.53 15.61 94.53l-53.92 174.43q-14.78 45.78-46.17 68.63-31.39 22.85-78.31 22.85H166.78Zm112.83-106h471.35l59-191.96H338.61l-59 191.96ZM166.78-470.91v-242.31 242.31Zm112.83 224.13 59-191.96-59 191.96Z" /></svg>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" height="128" view
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M160-240v-480 480Zm0 80q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h207q16 0 30.5 6t25.5 17l57 57h320q33 0 56.5 23.5T880-640v80q0 17-11.5 28.5T840-520q-17 0-28.5-11.5T800-560v-80H447l-80-80H160v480h280q17 0 28.5 11.5T480-200q0 17-11.5 28.5T440-160H160Zm400 40v-66q0-8 3-15.5t9-13.5l209-208q9-9 20-13t22-4q12 0 23 4.5t20 13.5l37 37q8 9 12.5 20t4.5 22q0 11-4 22.5T903-300L695-92q-6 6-13.5 9T666-80h-66q-17 0-28.5-11.5T560-120Zm300-223-37-37 37 37ZM620-140h38l121-122-18-19-19-18-122 121v38Zm141-141-19-18 37 37-18-19Z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M160-240v-480 480Zm0 80q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h207q16 0 30.5 6t25.5 17l57 57h320q33 0 56.5 23.5T880-640v80q0 17-11.5 28.5T840-520q-17 0-28.5-11.5T800-560v-80H447l-80-80H160v480h280q17 0 28.5 11.5T480-200q0 17-11.5 28.5T440-160H160Zm400 40v-66q0-8 3-15.5t9-13.5l209-208q9-9 20-13t22-4q12 0 23 4.5t20 13.5l37 37q8 9 12.5 20t4.5 22q0 11-4 22.5T903-300L695-92q-6 6-13.5 9T666-80h-66q-17 0-28.5-11.5T560-120Zm300-223-37-37 37 37ZM620-140h38l121-122-18-19-19-18-122 121v38Zm141-141-19-18 37 37-18-19Z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M380-320q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l224 224q11 11 11 28t-11 28q-11 11-28 11t-28-11L532-372q-30 24-69 38t-83 14Zm0-80q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M380-320q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l224 224q11 11 11 28t-11 28q-11 11-28 11t-28-11L532-372q-30 24-69 38t-83 14Zm0-80q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M680-160q-17 0-28.5-11.5T640-200v-200q0-17 11.5-28.5T680-440h80q17 0 28.5 11.5T800-400v200q0 17-11.5 28.5T760-160h-80Zm-240 0q-17 0-28.5-11.5T400-200v-560q0-17 11.5-28.5T440-800h80q17 0 28.5 11.5T560-760v560q0 17-11.5 28.5T520-160h-80Zm-240 0q-17 0-28.5-11.5T160-200v-360q0-17 11.5-28.5T200-600h80q17 0 28.5 11.5T320-560v360q0 17-11.5 28.5T280-160h-80Z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M680-160q-17 0-28.5-11.5T640-200v-200q0-17 11.5-28.5T680-440h80q17 0 28.5 11.5T800-400v200q0 17-11.5 28.5T760-160h-80Zm-240 0q-17 0-28.5-11.5T400-200v-560q0-17 11.5-28.5T440-800h80q17 0 28.5 11.5T560-760v560q0 17-11.5 28.5T520-160h-80Zm-240 0q-17 0-28.5-11.5T160-200v-360q0-17 11.5-28.5T200-600h80q17 0 28.5 11.5T320-560v360q0 17-11.5 28.5T280-160h-80Z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-360q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35Zm0 80q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480q0 83-58.5 141.5T480-280ZM80-440q-17 0-28.5-11.5T40-480q0-17 11.5-28.5T80-520h80q17 0 28.5 11.5T200-480q0 17-11.5 28.5T160-440H80Zm720 0q-17 0-28.5-11.5T760-480q0-17 11.5-28.5T800-520h80q17 0 28.5 11.5T920-480q0 17-11.5 28.5T880-440h-80ZM480-760q-17 0-28.5-11.5T440-800v-80q0-17 11.5-28.5T480-920q17 0 28.5 11.5T520-880v80q0 17-11.5 28.5T480-760Zm0 720q-17 0-28.5-11.5T440-80v-80q0-17 11.5-28.5T480-200q17 0 28.5 11.5T520-160v80q0 17-11.5 28.5T480-40ZM226-678l-43-42q-12-11-11.5-28t11.5-29q12-12 29-12t28 12l42 43q11 12 11 28t-11 28q-11 12-27.5 11.5T226-678Zm494 495-42-43q-11-12-11-28.5t11-27.5q11-12 27.5-11.5T734-282l43 42q12 11 11.5 28T777-183q-12 12-29 12t-28-12Zm-42-495q-12-11-11.5-27.5T678-734l42-43q11-12 28-11.5t29 11.5q12 12 12 29t-12 28l-43 42q-12 11-28 11t-28-11ZM183-183q-12-12-12-29t12-28l43-42q12-11 28.5-11t27.5 11q12 11 11.5 27.5T282-226l-42 43q-11 12-28 11.5T183-183Zm297-297Z" /></svg>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-120q-151 0-255.5-104.5T120-480q0-138 90-239.5T440-838q13-2 23 3.5t16 14.5q6 9 6.5 21t-7.5 23q-17 26-25.5 55t-8.5 61q0 90 63 153t153 63q31 0 61.5-9t54.5-25q11-7 22.5-6.5T819-479q10 5 15.5 15t3.5 24q-14 138-117.5 229T480-120Zm0-80q88 0 158-48.5T740-375q-20 5-40 8t-40 3q-123 0-209.5-86.5T364-660q0-20 3-40t8-40q-78 32-126.5 102T200-480q0 116 82 198t198 82Zm-10-270Z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm40-83q119-15 199.5-104.5T800-480q0-123-80.5-212.5T520-797v634Z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M440-440H240q-17 0-28.5-11.5T200-480q0-17 11.5-28.5T240-520h200v-200q0-17 11.5-28.5T480-760q17 0 28.5 11.5T520-720v200h200q17 0 28.5 11.5T760-480q0 17-11.5 28.5T720-440H520v200q0 17-11.5 28.5T480-200q-17 0-28.5-11.5T440-240v-200Z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M440-440H240q-17 0-28.5-11.5T200-480q0-17 11.5-28.5T240-520h200v-200q0-17 11.5-28.5T480-760q17 0 28.5 11.5T520-720v200h200q17 0 28.5 11.5T760-480q0 17-11.5 28.5T720-440H520v200q0 17-11.5 28.5T480-200q-17 0-28.5-11.5T440-240v-200Z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M400-160 232-88q-40 17-76-6.5T120-161v-519q0-33 23.5-56.5T200-760h400q33 0 56.5 23.5T680-680v519q0 43-36 66.5T568-88l-168-72Zm0-88 200 86v-518H200v518l200-86Zm400 88q-17 0-28.5-11.5T760-200v-640H280q-17 0-28.5-11.5T240-880q0-17 11.5-28.5T280-920h480q33 0 56.5 23.5T840-840v640q0 17-11.5 28.5T800-160ZM400-680H200h400-200Z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M400-160 232-88q-40 17-76-6.5T120-161v-519q0-33 23.5-56.5T200-760h400q33 0 56.5 23.5T680-680v519q0 43-36 66.5T568-88l-168-72Zm0-88 200 86v-518H200v518l200-86Zm400 88q-17 0-28.5-11.5T760-200v-640H280q-17 0-28.5-11.5T240-880q0-17 11.5-28.5T280-920h480q33 0 56.5 23.5T840-840v640q0 17-11.5 28.5T800-160ZM400-680H200h400-200Z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h207q16 0 30.5 6t25.5 17l57 57h360q17 0 28.5 11.5T880-680q0 17-11.5 28.5T840-640H447l-80-80H160v480l79-263q8-26 29.5-41.5T316-560h516q41 0 64.5 32.5T909-457l-72 240q-8 26-29.5 41.5T760-160H160Zm84-80h516l72-240H316l-72 240Zm-84-262v-218 218Zm84 262 72-240-72 240Z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h207q16 0 30.5 6t25.5 17l57 57h360q17 0 28.5 11.5T880-680q0 17-11.5 28.5T840-640H447l-80-80H160v480l79-263q8-26 29.5-41.5T316-560h516q41 0 64.5 32.5T909-457l-72 240q-8 26-29.5 41.5T760-160H160Zm84-80h516l72-240H316l-72 240Zm-84-262v-218 218Zm84 262 72-240-72 240Z" /></svg>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" height="128" view
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M160-240v-480 480Zm24.62 40q-27.62 0-46.12-18.5Q120-237 120-264.62v-430.76q0-27.62 18.5-46.12Q157-760 184.62-760H357q12.92 0 25.12 5.23 12.19 5.23 20.88 13.92L463.85-680h311.53q27.62 0 46.12 18.5Q840-643 840-615.38v67.69q0 8.54-5.73 14.27T820-527.69q-8.54 0-14.27-5.73T800-547.69v-67.69q0-9.24-7.69-16.93-7.69-7.69-16.93-7.69H447.77l-80-80H184.62q-10.77 0-17.7 6.92-6.92 6.93-6.92 17.7v430.76q0 9.24 7.69 16.93 7.69 7.69 16.93 7.69h269.23q8.53 0 14.27 5.73 5.73 5.73 5.73 14.27t-5.73 14.27q-5.74 5.73-14.27 5.73H184.62Zm384.61 47.69v-42.92q0-6.46 2.23-12.04 2.23-5.58 7.46-10.81l203.62-202.61q5.92-5.93 12.31-8 6.38-2.08 12.77-2.08 6.61 0 13.38 2.58 6.77 2.57 11.92 7.73l37 37.77q4.93 5.92 7.5 12.31Q880-364 880-357.62q0 6.39-2.46 12.89-2.46 6.5-7.62 12.42L667.31-129.69q-5.23 5.23-10.81 7.46-5.58 2.23-12.04 2.23h-42.92q-13.92 0-23.12-9.19-9.19-9.19-9.19-23.12Zm275.39-205.31-37-37.76 37 37.76Zm-240 202.24h38l138.69-138.93-18.77-19-18.23-19.54-139.69 139.47v38Zm157.92-157.93-18.23-19.54 37 38.54-18.77-19Z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M160-240v-480 480Zm24.62 40q-27.62 0-46.12-18.5Q120-237 120-264.62v-430.76q0-27.62 18.5-46.12Q157-760 184.62-760H357q12.92 0 25.12 5.23 12.19 5.23 20.88 13.92L463.85-680h311.53q27.62 0 46.12 18.5Q840-643 840-615.38v67.69q0 8.54-5.73 14.27T820-527.69q-8.54 0-14.27-5.73T800-547.69v-67.69q0-9.24-7.69-16.93-7.69-7.69-16.93-7.69H447.77l-80-80H184.62q-10.77 0-17.7 6.92-6.92 6.93-6.92 17.7v430.76q0 9.24 7.69 16.93 7.69 7.69 16.93 7.69h269.23q8.53 0 14.27 5.73 5.73 5.73 5.73 14.27t-5.73 14.27q-5.74 5.73-14.27 5.73H184.62Zm384.61 47.69v-42.92q0-6.46 2.23-12.04 2.23-5.58 7.46-10.81l203.62-202.61q5.92-5.93 12.31-8 6.38-2.08 12.77-2.08 6.61 0 13.38 2.58 6.77 2.57 11.92 7.73l37 37.77q4.93 5.92 7.5 12.31Q880-364 880-357.62q0 6.39-2.46 12.89-2.46 6.5-7.62 12.42L667.31-129.69q-5.23 5.23-10.81 7.46-5.58 2.23-12.04 2.23h-42.92q-13.92 0-23.12-9.19-9.19-9.19-9.19-23.12Zm275.39-205.31-37-37.76 37 37.76Zm-240 202.24h38l138.69-138.93-18.77-19-18.23-19.54-139.69 139.47v38Zm157.92-157.93-18.23-19.54 37 38.54-18.77-19Z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M381.54-350.77q-95.92 0-162.58-66.65-66.65-66.66-66.65-162.58 0-95.92 66.65-162.58 66.66-66.65 162.58-66.65 95.92 0 162.58 66.65 66.65 66.66 66.65 162.58 0 41.69-14.77 80.69t-38.77 66.69l236.31 236.31q5.61 5.62 6 13.77.38 8.16-6 14.54-6.39 6.38-14.16 6.38-7.76 0-14.15-6.38L528.92-404.31q-30 25.54-69 39.54t-78.38 14Zm0-40q79.61 0 134.42-54.81 54.81-54.8 54.81-134.42 0-79.62-54.81-134.42-54.81-54.81-134.42-54.81-79.62 0-134.42 54.81-54.81 54.8-54.81 134.42 0 79.62 54.81 134.42 54.8 54.81 134.42 54.81Z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M381.54-350.77q-95.92 0-162.58-66.65-66.65-66.66-66.65-162.58 0-95.92 66.65-162.58 66.66-66.65 162.58-66.65 95.92 0 162.58 66.65 66.65 66.66 66.65 162.58 0 41.69-14.77 80.69t-38.77 66.69l236.31 236.31q5.61 5.62 6 13.77.38 8.16-6 14.54-6.39 6.38-14.16 6.38-7.76 0-14.15-6.38L528.92-404.31q-30 25.54-69 39.54t-78.38 14Zm0-40q79.61 0 134.42-54.81 54.81-54.8 54.81-134.42 0-79.62-54.81-134.42-54.81-54.81-134.42-54.81-79.62 0-134.42 54.81-54.81 54.8-54.81 134.42 0 79.62 54.81 134.42 54.8 54.81 134.42 54.81Z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M672.31-200q-13.73 0-23.02-9.29T640-232.31V-360q0-13.73 9.29-23.02t23.02-9.29h55.38q13.73 0 23.02 9.29T760-360v127.69q0 13.73-9.29 23.02T727.69-200h-55.38Zm-220 0q-13.73 0-23.02-9.29T420-232.31v-495.38q0-13.73 9.29-23.02t23.02-9.29h55.38q13.73 0 23.02 9.29t9.29 23.02v495.38q0 13.73-9.29 23.02T507.69-200h-55.38Zm-220 0q-13.73 0-23.02-9.29T200-232.31v-302.7q0-14.3 9.29-23.49 9.29-9.19 23.02-9.19h55.38q13.73 0 23.02 9.29 9.29 9.28 9.29 23.02v302.7q0 14.3-9.29 23.49-9.29 9.19-23.02 9.19h-55.38Z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M672.31-200q-13.73 0-23.02-9.29T640-232.31V-360q0-13.73 9.29-23.02t23.02-9.29h55.38q13.73 0 23.02 9.29T760-360v127.69q0 13.73-9.29 23.02T727.69-200h-55.38Zm-220 0q-13.73 0-23.02-9.29T420-232.31v-495.38q0-13.73 9.29-23.02t23.02-9.29h55.38q13.73 0 23.02 9.29t9.29 23.02v495.38q0 13.73-9.29 23.02T507.69-200h-55.38Zm-220 0q-13.73 0-23.02-9.29T200-232.31v-302.7q0-14.3 9.29-23.49 9.29-9.19 23.02-9.19h55.38q13.73 0 23.02 9.29 9.29 9.28 9.29 23.02v302.7q0 14.3-9.29 23.49-9.29 9.19-23.02 9.19h-55.38Z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480-360q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35Zm0 40q-66.85 0-113.42-46.58Q320-413.15 320-480t46.58-113.42Q413.15-640 480-640t113.42 46.58Q640-546.85 640-480t-46.58 113.42Q546.85-320 480-320ZM80-460q-8.5 0-14.25-5.76T60-480.03q0-8.51 5.75-14.24T80-500h100q8.5 0 14.25 5.76t5.75 14.27q0 8.51-5.75 14.24T180-460H80Zm700 0q-8.5 0-14.25-5.76T760-480.03q0-8.51 5.75-14.24T780-500h100q8.5 0 14.25 5.76t5.75 14.27q0 8.51-5.75 14.24T880-460H780ZM479.97-760q-8.51 0-14.24-5.75T460-780v-100q0-8.5 5.76-14.25t14.27-5.75q8.51 0 14.24 5.75T500-880v100q0 8.5-5.76 14.25T479.97-760Zm0 700q-8.51 0-14.24-5.75T460-80v-100q0-8.5 5.76-14.25t14.27-5.75q8.51 0 14.24 5.75T500-180v100q0 8.5-5.76 14.25T479.97-60ZM254.46-678.77l-57.61-55.85q-5.85-5.61-5.73-13.76.11-8.16 5.96-14.77 6.38-6.62 14.15-6.62 7.77 0 14.15 6.62L282-706.31q6.38 6.62 6.38 14.16 0 7.53-6 14.15t-13.65 6.12q-7.65-.5-14.27-6.89Zm480.16 481.92L678-253.69q-6.38-6.62-6.38-14.27 0-7.66 6.38-14.04 5.23-6.62 13.08-6.12 7.84.5 14.46 6.89l57.61 55.85q5.85 5.61 5.73 13.76-.11 8.16-5.96 14.77-6.38 6.62-14.15 6.62-7.77 0-14.15-6.62ZM678-677.62q-6.62-6-6.12-13.65t6.89-14.27l55.85-57.61q5.61-5.85 13.76-5.73 8.16.11 14.77 5.96 6.62 6.38 6.62 14.15 0 7.77-6.62 14.15L706.31-678q-6.62 6.38-14.16 6.38-7.53 0-14.15-6ZM196.85-196.68q-6.62-6.78-6.62-14.55 0-7.77 6.62-14.15L253.69-282q6.62-6.38 14.27-6.38 7.66 0 14.04 6.38 5.85 5.23 5.35 13.08-.5 7.84-6.12 14.46l-55.85 57.61q-6.38 6.62-14.15 6.5-7.77-.11-14.38-6.33ZM480-480Z" /></svg>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M482.31-160Q349-160 255.65-253.35 162.31-346.69 162.31-480q0-98.77 56.54-181.42 56.53-82.66 160.38-118.89 12.23-4.31 21.46-2.27 9.23 2.04 15.23 7.96 6 5.93 7.66 15.24 1.65 9.3-2.5 19.53-7.77 19.08-11.27 38.66t-3.5 41.19q0 106.67 74.66 181.33Q555.64-404 662.31-404q27.92 0 51.11-5.92 23.2-5.93 39.5-9.62 8.7-1.61 15.96.42 7.27 2.04 11.54 7.04 4.73 5 6.39 12.31 1.65 7.31-1.89 16.69-28.61 98-112.11 160.54Q589.31-160 482.31-160Zm0-40q88 0 158-48.5t102-126.5q-20 5-40 8t-40 3q-123 0-209.5-86.5T366.31-660q0-20 3-40t8-40q-78 32-126.5 102t-48.5 158q0 116 82 198t198 82Zm-10-270Z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M480.13-120q-74.67 0-140.41-28.34-65.73-28.34-114.36-76.92-48.63-48.58-76.99-114.26Q120-405.19 120-479.87q0-74.67 28.34-140.41 28.34-65.73 76.92-114.36 48.58-48.63 114.26-76.99Q405.19-840 479.87-840q74.67 0 140.41 28.34 65.73 28.34 114.36 76.92 48.63 48.58 76.99 114.26Q840-554.81 840-480.13q0 74.67-28.34 140.41-28.34 65.73-76.92 114.36-48.58 48.63-114.26 76.99Q554.81-120 480.13-120ZM500-160.69q123.62-8.08 211.81-98.35T800-480q0-130.69-87.42-220.19-87.43-89.5-212.58-99.12v638.62Z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M460-460H260q-8.5 0-14.25-5.76T240-480.03q0-8.51 5.75-14.24T260-500h200v-200q0-8.5 5.76-14.25t14.27-5.75q8.51 0 14.24 5.75T500-700v200h200q8.5 0 14.25 5.76t5.75 14.27q0 8.51-5.75 14.24T700-460H500v200q0 8.5-5.76 14.25T479.97-240q-8.51 0-14.24-5.75T460-260v-200Z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M460-460H260q-8.5 0-14.25-5.76T240-480.03q0-8.51 5.75-14.24T260-500h200v-200q0-8.5 5.76-14.25t14.27-5.75q8.51 0 14.24 5.75T500-700v200h200q8.5 0 14.25 5.76t5.75 14.27q0 8.51-5.75 14.24T700-460H500v200q0 8.5-5.76 14.25T479.97-240q-8.51 0-14.24-5.75T460-260v-200Z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="m420-203.08-149.54 64.31q-32.31 13.92-61.38-5.35Q180-163.38 180-197.92v-457.46q0-27.62 18.5-46.12Q217-720 244.62-720h350.76q27.62 0 46.12 18.5Q660-683 660-655.38v457.46q0 34.54-29.08 53.8-29.07 19.27-61.38 5.35L420-203.08Zm0-44.92 165.38 71.38q12.31 5.39 23.47-2.3 11.15-7.7 11.15-20.77v-455.69q0-9.24-7.69-16.93-7.69-7.69-16.93-7.69H244.62q-9.24 0-16.93 7.69-7.69 7.69-7.69 16.93v455.69q0 13.07 11.15 20.77 11.16 7.69 23.47 2.3L420-248Zm340 28q-8.54 0-14.27-5.73T740-240v-535.39q0-9.23-7.69-16.92-7.69-7.69-16.93-7.69H320q-8.54 0-14.27-5.73T300-820q0-8.54 5.73-14.27T320-840h395.38q27.62 0 46.12 18.5Q780-803 780-775.39V-240q0 8.54-5.73 14.27T760-220ZM420-680H220h400-200Z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="m420-203.08-149.54 64.31q-32.31 13.92-61.38-5.35Q180-163.38 180-197.92v-457.46q0-27.62 18.5-46.12Q217-720 244.62-720h350.76q27.62 0 46.12 18.5Q660-683 660-655.38v457.46q0 34.54-29.08 53.8-29.07 19.27-61.38 5.35L420-203.08Zm0-44.92 165.38 71.38q12.31 5.39 23.47-2.3 11.15-7.7 11.15-20.77v-455.69q0-9.24-7.69-16.93-7.69-7.69-16.93-7.69H244.62q-9.24 0-16.93 7.69-7.69 7.69-7.69 16.93v455.69q0 13.07 11.15 20.77 11.16 7.69 23.47 2.3L420-248Zm340 28q-8.54 0-14.27-5.73T740-240v-535.39q0-9.23-7.69-16.92-7.69-7.69-16.93-7.69H320q-8.54 0-14.27-5.73T300-820q0-8.54 5.73-14.27T320-840h395.38q27.62 0 46.12 18.5Q780-803 780-775.39V-240q0 8.54-5.73 14.27T760-220ZM420-680H220h400-200Z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M180-200q-25.31 0-42.65-17.35Q120-234.69 120-260v-435.38q0-25.31 19.65-44.97Q159.31-760 184.62-760H357q12.92 0 25.12 5.23 12.19 5.23 20.88 13.92L463.85-680h349.23q8.54 0 14.27 5.73t5.73 14.27q0 8.54-5.73 14.27T813.08-640H447.77l-80-80H184.62q-10.77 0-17.7 6.92-6.92 6.93-6.92 17.7V-240q0-10.77 4.23-8.08 4.23 2.7 11.15 6.54l76.7-256.84q6.46-20.62 23.73-33.43 17.27-12.81 38.65-12.81h512.92q32.54 0 52.2 25.97 19.65 25.96 10.19 57.03l-65.85 219.24q-5.69 19.07-21.8 30.73Q786-200 766.15-200H180Zm37.08-40h546q8.46 0 15-4.62 6.54-4.61 8.84-13.07l64.31-215.39q3.85-12.3-3.85-21.92-7.69-9.62-20-9.62H314.46q-8.46 0-15 4.62-6.54 4.62-8.84 13.08L217.08-240ZM160-498.15V-720v221.85ZM217.08-240l73.54-246.92q2.3-8.46 3.84-13.08l1.54-4.62-2.69 9.62q-2.69 9.62-6.54 21.92l-64.31 215.39q-2.31 8.46-3.84 13.07l-1.54 4.62Z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 -960 960 960" width="128" fill="#000000"><path d="M180-200q-25.31 0-42.65-17.35Q120-234.69 120-260v-435.38q0-25.31 19.65-44.97Q159.31-760 184.62-760H357q12.92 0 25.12 5.23 12.19 5.23 20.88 13.92L463.85-680h349.23q8.54 0 14.27 5.73t5.73 14.27q0 8.54-5.73 14.27T813.08-640H447.77l-80-80H184.62q-10.77 0-17.7 6.92-6.92 6.93-6.92 17.7V-240q0-10.77 4.23-8.08 4.23 2.7 11.15 6.54l76.7-256.84q6.46-20.62 23.73-33.43 17.27-12.81 38.65-12.81h512.92q32.54 0 52.2 25.97 19.65 25.96 10.19 57.03l-65.85 219.24q-5.69 19.07-21.8 30.73Q786-200 766.15-200H180Zm37.08-40h546q8.46 0 15-4.62 6.54-4.61 8.84-13.07l64.31-215.39q3.85-12.3-3.85-21.92-7.69-9.62-20-9.62H314.46q-8.46 0-15 4.62-6.54 4.62-8.84 13.08L217.08-240ZM160-498.15V-720v221.85ZM217.08-240l73.54-246.92q2.3-8.46 3.84-13.08l1.54-4.62-2.69 9.62q-2.69 9.62-6.54 21.92l-64.31 215.39q-2.31 8.46-3.84 13.07l-1.54 4.62Z" /></svg>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 2
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M21 15.2426V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5511 3 20.9925V9H9C9.55228 9 10 8.55228 10 8V2H20.0017C20.5531 2 21 2.45531 21 2.9918V6.75736L12.0012 15.7562L11.995 19.995L16.2414 20.0012L21 15.2426ZM21.7782 8.80761L23.1924 10.2218L15.4142 18L13.9979 17.9979L14 16.5858L21.7782 8.80761ZM3 7L8 2.00318V7H3Z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M21 15.2426V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5511 3 20.9925V9H9C9.55228 9 10 8.55228 10 8V2H20.0017C20.5531 2 21 2.45531 21 2.9918V6.75736L12.0012 15.7562L11.995 19.995L16.2414 20.0012L21 15.2426ZM21.7782 8.80761L23.1924 10.2218L15.4142 18L13.9979 17.9979L14 16.5858L21.7782 8.80761ZM3 7L8 2.00318V7H3Z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M16 2L21 7V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5447 3 21.0082V2.9918C3 2.44405 3.44495 2 3.9934 2H16ZM13.529 14.4464L15.7395 16.6569L17.1537 15.2426L14.9432 13.0322C15.8492 11.4983 15.6432 9.48951 14.3252 8.17157C12.7631 6.60948 10.2305 6.60948 8.66839 8.17157C7.1063 9.73367 7.1063 12.2663 8.66839 13.8284C9.98633 15.1464 11.9951 15.3524 13.529 14.4464ZM12.911 12.4142C12.13 13.1953 10.8637 13.1953 10.0826 12.4142C9.30156 11.6332 9.30156 10.3668 10.0826 9.58579C10.8637 8.80474 12.13 8.80474 12.911 9.58579C13.6921 10.3668 13.6921 11.6332 12.911 12.4142Z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M16 2L21 7V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5447 3 21.0082V2.9918C3 2.44405 3.44495 2 3.9934 2H16ZM13.529 14.4464L15.7395 16.6569L17.1537 15.2426L14.9432 13.0322C15.8492 11.4983 15.6432 9.48951 14.3252 8.17157C12.7631 6.60948 10.2305 6.60948 8.66839 8.17157C7.1063 9.73367 7.1063 12.2663 8.66839 13.8284C9.98633 15.1464 11.9951 15.3524 13.529 14.4464ZM12.911 12.4142C12.13 13.1953 10.8637 13.1953 10.0826 12.4142C9.30156 11.6332 9.30156 10.3668 10.0826 9.58579C10.8637 8.80474 12.13 8.80474 12.911 9.58579C13.6921 10.3668 13.6921 11.6332 12.911 12.4142Z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M3 12H7V21H3V12ZM17 8H21V21H17V8ZM10 2H14V21H10V2Z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M3 12H7V21H3V12ZM17 8H21V21H17V8ZM10 2H14V21H10V2Z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M12 18C8.68629 18 6 15.3137 6 12C6 8.68629 8.68629 6 12 6C15.3137 6 18 8.68629 18 12C18 15.3137 15.3137 18 12 18ZM11 1H13V4H11V1ZM11 20H13V23H11V20ZM3.51472 4.92893L4.92893 3.51472L7.05025 5.63604L5.63604 7.05025L3.51472 4.92893ZM16.9497 18.364L18.364 16.9497L20.4853 19.0711L19.0711 20.4853L16.9497 18.364ZM19.0711 3.51472L20.4853 4.92893L18.364 7.05025L16.9497 5.63604L19.0711 3.51472ZM5.63604 16.9497L7.05025 18.364L4.92893 20.4853L3.51472 19.0711L5.63604 16.9497ZM23 11V13H20V11H23ZM4 11V13H1V11H4Z" /></svg>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M11.3807 2.01886C9.91573 3.38768 9 5.3369 9 7.49999C9 11.6421 12.3579 15 16.5 15C18.6631 15 20.6123 14.0843 21.9811 12.6193C21.6613 17.8537 17.3149 22 12 22C6.47715 22 2 17.5228 2 12C2 6.68514 6.14629 2.33869 11.3807 2.01886Z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M12 21.9967C6.47715 21.9967 2 17.5196 2 11.9967C2 6.47386 6.47715 1.9967 12 1.9967C17.5228 1.9967 22 6.47386 22 11.9967C22 17.5196 17.5228 21.9967 12 21.9967ZM12 19.9967V3.9967C7.58172 3.9967 4 7.57843 4 11.9967C4 16.415 7.58172 19.9967 12 19.9967Z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M11 11V5H13V11H19V13H13V19H11V13H5V11H11Z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M11 11V5H13V11H19V13H13V19H11V13H5V11H11Z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M5 2H19C19.5523 2 20 2.44772 20 3V22.1433C20 22.4194 19.7761 22.6434 19.5 22.6434C19.4061 22.6434 19.314 22.6168 19.2344 22.5669L12 18.0313L4.76559 22.5669C4.53163 22.7136 4.22306 22.6429 4.07637 22.4089C4.02647 22.3293 4 22.2373 4 22.1433V3C4 2.44772 4.44772 2 5 2Z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M5 2H19C19.5523 2 20 2.44772 20 3V22.1433C20 22.4194 19.7761 22.6434 19.5 22.6434C19.4061 22.6434 19.314 22.6168 19.2344 22.5669L12 18.0313L4.76559 22.5669C4.53163 22.7136 4.22306 22.6429 4.07637 22.4089C4.02647 22.3293 4 22.2373 4 22.1433V3C4 2.44772 4.44772 2 5 2Z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M22 11V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V11H22ZM22 9H2V4C2 3.44772 2.44772 3 3 3H10.4142L12.4142 5H21C21.5523 5 22 5.44772 22 6V9Z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M22 11V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V11H22ZM22 9H2V4C2 3.44772 2.44772 3 3 3H10.4142L12.4142 5H21C21.5523 5 22 5.44772 22 6V9Z" /></svg>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ icon:sb_outline = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 2
|
|||||||
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M21 6.75736L19 8.75736V4H10V9H5V20H19V17.2426L21 15.2426V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5501 3 20.9932V8L9.00319 2H19.9978C20.5513 2 21 2.45531 21 2.9918V6.75736ZM21.7782 8.80761L23.1924 10.2218L15.4142 18L13.9979 17.9979L14 16.5858L21.7782 8.80761Z" /></svg>
|
icon:sb_project = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M21 6.75736L19 8.75736V4H10V9H5V20H19V17.2426L21 15.2426V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5501 3 20.9932V8L9.00319 2H19.9978C20.5513 2 21 2.45531 21 2.9918V6.75736ZM21.7782 8.80761L23.1924 10.2218L15.4142 18L13.9979 17.9979L14 16.5858L21.7782 8.80761Z" /></svg>
|
||||||
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M15 4H5V20H19V8H15V4ZM3 2.9918C3 2.44405 3.44749 2 3.9985 2H16L20.9997 7L21 20.9925C21 21.5489 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5447 3 21.0082V2.9918ZM13.529 14.4464C11.9951 15.3524 9.98633 15.1464 8.66839 13.8284C7.1063 12.2663 7.1063 9.73367 8.66839 8.17157C10.2305 6.60948 12.7631 6.60948 14.3252 8.17157C15.6432 9.48951 15.8492 11.4983 14.9432 13.0322L17.1537 15.2426L15.7395 16.6569L13.529 14.4464ZM12.911 12.4142C13.6921 11.6332 13.6921 10.3668 12.911 9.58579C12.13 8.80474 10.8637 8.80474 10.0826 9.58579C9.30156 10.3668 9.30156 11.6332 10.0826 12.4142C10.8637 13.1953 12.13 13.1953 12.911 12.4142Z" /></svg>
|
icon:sb_search = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M15 4H5V20H19V8H15V4ZM3 2.9918C3 2.44405 3.44749 2 3.9985 2H16L20.9997 7L21 20.9925C21 21.5489 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5447 3 21.0082V2.9918ZM13.529 14.4464C11.9951 15.3524 9.98633 15.1464 8.66839 13.8284C7.1063 12.2663 7.1063 9.73367 8.66839 8.17157C10.2305 6.60948 12.7631 6.60948 14.3252 8.17157C15.6432 9.48951 15.8492 11.4983 14.9432 13.0322L17.1537 15.2426L15.7395 16.6569L13.529 14.4464ZM12.911 12.4142C13.6921 11.6332 13.6921 10.3668 12.911 9.58579C12.13 8.80474 10.8637 8.80474 10.0826 9.58579C9.30156 10.3668 9.30156 11.6332 10.0826 12.4142C10.8637 13.1953 12.13 13.1953 12.911 12.4142Z" /></svg>
|
||||||
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M3 12H7V21H3V12ZM17 8H21V21H17V8ZM10 2H14V21H10V2Z" /></svg>
|
icon:sb_stats = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M3 12H7V21H3V12ZM17 8H21V21H17V8ZM10 2H14V21H10V2Z" /></svg>
|
||||||
|
icon:theme_light = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M12 18C8.68629 18 6 15.3137 6 12C6 8.68629 8.68629 6 12 6C15.3137 6 18 8.68629 18 12C18 15.3137 15.3137 18 12 18ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16ZM11 1H13V4H11V1ZM11 20H13V23H11V20ZM3.51472 4.92893L4.92893 3.51472L7.05025 5.63604L5.63604 7.05025L3.51472 4.92893ZM16.9497 18.364L18.364 16.9497L20.4853 19.0711L19.0711 20.4853L16.9497 18.364ZM19.0711 3.51472L20.4853 4.92893L18.364 7.05025L16.9497 5.63604L19.0711 3.51472ZM5.63604 16.9497L7.05025 18.364L4.92893 20.4853L3.51472 19.0711L5.63604 16.9497ZM23 11V13H20V11H23ZM4 11V13H1V11H4Z" /></svg>
|
||||||
|
icon:theme_dark = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M10 7C10 10.866 13.134 14 17 14C18.9584 14 20.729 13.1957 21.9995 11.8995C22 11.933 22 11.9665 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C12.0335 2 12.067 2 12.1005 2.00049C10.8043 3.27098 10 5.04157 10 7ZM4 12C4 16.4183 7.58172 20 12 20C15.0583 20 17.7158 18.2839 19.062 15.7621C18.3945 15.9187 17.7035 16 17 16C12.0294 16 8 11.9706 8 7C8 6.29648 8.08133 5.60547 8.2379 4.938C5.71611 6.28423 4 8.9417 4 12Z" /></svg>
|
||||||
|
icon:theme_auto = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M12 21.9967C6.47715 21.9967 2 17.5196 2 11.9967C2 6.47386 6.47715 1.9967 12 1.9967C17.5228 1.9967 22 6.47386 22 11.9967C22 17.5196 17.5228 21.9967 12 21.9967ZM12 19.9967C16.4183 19.9967 20 16.415 20 11.9967C20 7.57843 16.4183 3.9967 12 3.9967C7.58172 3.9967 4 7.57843 4 11.9967C4 16.415 7.58172 19.9967 12 19.9967ZM12 17.9967V5.9967C15.3137 5.9967 18 8.683 18 11.9967C18 15.3104 15.3137 17.9967 12 17.9967Z" /></svg>
|
||||||
icon:add = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M11 11V5H13V11H19V13H13V19H11V13H5V11H11Z" /></svg>
|
icon:add = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M11 11V5H13V11H19V13H13V19H11V13H5V11H11Z" /></svg>
|
||||||
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M5 2H19C19.5523 2 20 2.44772 20 3V22.1433C20 22.4194 19.7761 22.6434 19.5 22.6434C19.4061 22.6434 19.314 22.6168 19.2344 22.5669L12 18.0313L4.76559 22.5669C4.53163 22.7136 4.22306 22.6429 4.07637 22.4089C4.02647 22.3293 4 22.2373 4 22.1433V3C4 2.44772 4.44772 2 5 2ZM18 4H6V19.4324L12 15.6707L18 19.4324V4Z" /></svg>
|
icon:bookmarks = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M5 2H19C19.5523 2 20 2.44772 20 3V22.1433C20 22.4194 19.7761 22.6434 19.5 22.6434C19.4061 22.6434 19.314 22.6168 19.2344 22.5669L12 18.0313L4.76559 22.5669C4.53163 22.7136 4.22306 22.6429 4.07637 22.4089C4.02647 22.3293 4 22.2373 4 22.1433V3C4 2.44772 4.44772 2 5 2ZM18 4H6V19.4324L12 15.6707L18 19.4324V4Z" /></svg>
|
||||||
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M12.4142 5H21C21.5523 5 22 5.44772 22 6V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H10.4142L12.4142 5ZM20 11H4V19H20V11ZM20 9V7H11.5858L9.58579 5H4V9H20Z" /></svg>
|
icon:browse = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000000" height="128" width="128"><path d="M12.4142 5H21C21.5523 5 22 5.44772 22 6V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H10.4142L12.4142 5ZM20 11H4V19H20V11ZM20 9V7H11.5858L9.58579 5H4V9H20Z" /></svg>
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Cyberpunk Night
|
|
||||||
author = Anders Lemvigh
|
|
||||||
url = https://github.com/alemvigh
|
|
||||||
license = CC BY-SA 4.0
|
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 0, 0, 0
|
|
||||||
text = 150, 150, 150
|
|
||||||
link = 77, 77, 255
|
|
||||||
headertext = 255, 255, 255
|
|
||||||
headertag = 50, 0, 180
|
|
||||||
emphasis = 0, 255, 255
|
|
||||||
dialog = 0, 255, 0
|
|
||||||
altdialog = 0, 140, 255
|
|
||||||
note = 150, 150, 150
|
|
||||||
hidden = 77, 77, 100
|
|
||||||
shortcode = 255, 255, 0
|
|
||||||
keyword = 255, 100, 255
|
|
||||||
tag = 255, 150, 10
|
|
||||||
value = 255, 150, 10
|
|
||||||
spellcheckline = 242, 72, 23
|
|
||||||
errorline = 186, 218, 4
|
|
||||||
replacetag = 0, 0, 180
|
|
||||||
modifier = 144, 142, 176
|
|
||||||
optional = 180, 180, 180
|
|
||||||
texthighlight = 255, 255, 132, 96
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Default Dark
|
|
||||||
author = Veronica Berglyd Olsen
|
|
||||||
credit = Veronica Berglyd Olsen
|
|
||||||
url = https://github.com/vkbo/novelWriter
|
|
||||||
license = CC BY-SA 4.0
|
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
|
||||||
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = 2a2a2a : 42, 42, 42
|
|
||||||
# Foreground = cccccc : 204, 204, 204
|
|
||||||
# Comment = 969696 : 150, 150, 150
|
|
||||||
# Red = e64250 : 230, 66, 80
|
|
||||||
# Orange = f99157 : 249, 145, 87
|
|
||||||
# Yellow = ffff84 : 255, 255, 132
|
|
||||||
# Green = 99cc99 : 153, 204, 153
|
|
||||||
# Blue = 288ed7 : 102, 153, 204
|
|
||||||
# Purple = 8c56d7 : 140, 86, 215
|
|
||||||
##
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 42, 42, 42
|
|
||||||
text = 204, 204, 204
|
|
||||||
link = 102, 153, 204
|
|
||||||
headertext = 153, 204, 153
|
|
||||||
headertag = 153, 204, 153, 160
|
|
||||||
emphasis = 249, 145, 87
|
|
||||||
dialog = 102, 153, 204
|
|
||||||
altdialog = 102, 153, 204
|
|
||||||
note = 255, 255, 216
|
|
||||||
hidden = 150, 150, 150
|
|
||||||
shortcode = 153, 204, 153
|
|
||||||
keyword = 230, 66, 80
|
|
||||||
tag = 153, 204, 153
|
|
||||||
value = 102, 153, 204
|
|
||||||
optional = 153, 204, 153
|
|
||||||
spellcheckline = 230, 66, 80
|
|
||||||
errorline = 153, 204, 153
|
|
||||||
replacetag = 153, 204, 153
|
|
||||||
modifier = 153, 204, 153
|
|
||||||
texthighlight = 255, 255, 132, 96
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Default Light
|
|
||||||
author = Veronica Berglyd Olsen
|
|
||||||
credit = Veronica Berglyd Olsen
|
|
||||||
url = https://github.com/vkbo/novelWriter
|
|
||||||
license = CC BY-SA 4.0
|
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
|
||||||
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = ffffff : 255, 255, 255
|
|
||||||
# Foreground = 000000 : 0, 0, 0
|
|
||||||
# Comment = 646464 : 100, 100, 100
|
|
||||||
# Red = c83232 : 200, 50, 50
|
|
||||||
# Orange = ae6e1e : 174, 110, 30
|
|
||||||
# Yellow = 969600 : 150, 150, 0
|
|
||||||
# Green = 006400 : 0, 100, 0
|
|
||||||
# Blue = 0000c8 : 0, 0, 200
|
|
||||||
# Purple = 6400ae : 100, 0, 174
|
|
||||||
##
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 255, 255, 255
|
|
||||||
text = 0, 0, 0
|
|
||||||
link = 0, 0, 200
|
|
||||||
headertext = 0, 100, 0
|
|
||||||
headertag = 0, 100, 0, 160
|
|
||||||
emphasis = 174, 110, 30
|
|
||||||
dialog = 0, 0, 200
|
|
||||||
altdialog = 0, 0, 200
|
|
||||||
note = 100, 100, 0
|
|
||||||
hidden = 100, 100, 100
|
|
||||||
shortcode = 0, 100, 0
|
|
||||||
keyword = 200, 50, 50
|
|
||||||
tag = 0, 100, 0
|
|
||||||
value = 0, 0, 200
|
|
||||||
optional = 0, 100, 0
|
|
||||||
spellcheckline = 200, 50, 50
|
|
||||||
errorline = 0, 100, 0
|
|
||||||
replacetag = 0, 100, 0
|
|
||||||
modifier = 0, 100, 0
|
|
||||||
texthighlight = 150, 150, 0, 96
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Dracula
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Zeno Rocha
|
|
||||||
url = https://draculatheme.com
|
|
||||||
license = MIT
|
|
||||||
licenseurl = https://github.com/dracula/dracula-theme/blob/main/LICENSE
|
|
||||||
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = 282a36 : 40, 42, 54
|
|
||||||
# Foreground = f8f8f2 : 248, 248, 242
|
|
||||||
# Comment = 6272a4 : 98, 114, 164
|
|
||||||
# Cyan = 8be9fd : 139, 233, 253
|
|
||||||
# Green = 50fa7b : 80, 250, 123
|
|
||||||
# Orange = ffb86c : 255, 184, 108
|
|
||||||
# Pink = ff79c6 : 255, 121, 198
|
|
||||||
# Purple = bd93f9 : 189, 147, 249
|
|
||||||
# Red = ff5555 : 255, 85, 85
|
|
||||||
# Yellow = f1fa8c : 241, 250, 140
|
|
||||||
##
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
# See: https://spec.draculatheme.com/
|
|
||||||
background = 40, 42, 54
|
|
||||||
text = 248, 248, 242
|
|
||||||
link = 255, 121, 198
|
|
||||||
headertext = 189, 147, 249
|
|
||||||
headertag = 189, 147, 249, 160
|
|
||||||
emphasis = 255, 184, 108
|
|
||||||
dialog = 80, 250, 123
|
|
||||||
altdialog = 241, 250, 140
|
|
||||||
note = 255, 204, 233
|
|
||||||
hidden = 98, 114, 164
|
|
||||||
shortcode = 139, 233, 253
|
|
||||||
keyword = 255, 121, 198
|
|
||||||
tag = 255, 184, 108
|
|
||||||
value = 255, 184, 108
|
|
||||||
optional = 80, 250, 123
|
|
||||||
spellcheckline = 255, 85, 85
|
|
||||||
errorline = 80, 250, 123
|
|
||||||
replacetag = 241, 250, 140
|
|
||||||
modifier = 139, 233, 253
|
|
||||||
texthighlight = 241, 250, 140, 96
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Grey Dark
|
|
||||||
author = Veronica Berglyd Olsen
|
|
||||||
credit = Veronica Berglyd Olsen
|
|
||||||
url = https://github.com/vkbo/novelWriter
|
|
||||||
license = CC BY-SA 4.0
|
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 54, 54, 54
|
|
||||||
text = 200, 200, 200
|
|
||||||
link = 200, 200, 200
|
|
||||||
headertext = 225, 225, 225
|
|
||||||
headertag = 225, 225, 225, 160
|
|
||||||
emphasis = 200, 200, 200
|
|
||||||
dialog = 200, 200, 200
|
|
||||||
altdialog = 200, 200, 200
|
|
||||||
note = 200, 200, 200
|
|
||||||
hidden = 150, 150, 150
|
|
||||||
shortcode = 225, 225, 225
|
|
||||||
keyword = 225, 225, 225
|
|
||||||
tag = 200, 200, 200
|
|
||||||
value = 200, 200, 200
|
|
||||||
optional = 225, 225, 225
|
|
||||||
spellcheckline = 200, 46, 0
|
|
||||||
errorline = 46, 200, 0
|
|
||||||
replacetag = 225, 225, 225
|
|
||||||
modifier = 225, 225, 225
|
|
||||||
texthighlight = 255, 255, 255, 64
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Grey Light
|
|
||||||
author = Veronica Berglyd Olsen
|
|
||||||
credit = Veronica Berglyd Olsen
|
|
||||||
url = https://github.com/vkbo/novelWriter
|
|
||||||
license = CC BY-SA 4.0
|
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 255, 255, 255
|
|
||||||
text = 20, 20, 20
|
|
||||||
link = 20, 20, 20
|
|
||||||
headertext = 0, 0, 0
|
|
||||||
headertag = 0, 0, 0, 160
|
|
||||||
emphasis = 20, 20, 20
|
|
||||||
dialog = 20, 20, 20
|
|
||||||
altdialog = 20, 20, 20
|
|
||||||
note = 20, 20, 20
|
|
||||||
hidden = 100, 100, 100
|
|
||||||
shortcode = 0, 0, 0
|
|
||||||
keyword = 0, 0, 0
|
|
||||||
tag = 20, 20, 20
|
|
||||||
value = 20, 20, 20
|
|
||||||
optional = 0, 0, 0
|
|
||||||
spellcheckline = 200, 0, 0
|
|
||||||
errorline = 0, 150, 0
|
|
||||||
replacetag = 0, 0, 0
|
|
||||||
modifier = 0, 0, 0
|
|
||||||
texthighlight = 0, 0, 0, 64
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
##
|
|
||||||
# Theme: Light Owl
|
|
||||||
# Source: https://github.com/sdras/night-owl-vscode-theme
|
|
||||||
# Credit: Sarah Drasner
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = fbfbfb : 251, 251, 251
|
|
||||||
# Current Line = e0e0e0 : 224, 224, 224
|
|
||||||
# Selection = e0e0e0 : 224, 224, 224
|
|
||||||
# Foreground = 403f52 : 64, 63, 82
|
|
||||||
# Comment = 989fb1 : 152, 159, 177
|
|
||||||
# Red = de3d3a : 222, 61, 58
|
|
||||||
# Orange = e0af05 : 224, 175, 5
|
|
||||||
# Yellow = daaa01 : 218, 170, 1
|
|
||||||
# Green = 08916a : 8, 145, 106
|
|
||||||
# Aqua = 2aa298 : 42, 162, 152
|
|
||||||
# Blue = 288ed7 : 40, 142, 215
|
|
||||||
# Purple = 964ac1 : 150, 74, 193
|
|
||||||
##
|
|
||||||
|
|
||||||
[Main]
|
|
||||||
name = Light Owl
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Sarah Drasner (color theme)
|
|
||||||
url = https://github.com/sdras/night-owl-vscode-theme
|
|
||||||
license = MIT License
|
|
||||||
licenseurl = https://github.com/sdras/night-owl-vscode-theme/blob/master/LICENSE
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 251, 251, 251
|
|
||||||
text = 64, 63, 82
|
|
||||||
link = 40, 142, 215
|
|
||||||
headertext = 40, 142, 215
|
|
||||||
headertag = 40, 142, 215, 160
|
|
||||||
emphasis = 224, 175, 5
|
|
||||||
dialog = 8, 145, 106
|
|
||||||
altdialog = 218, 170, 1
|
|
||||||
note = 128, 118, 75
|
|
||||||
hidden = 152, 159, 177
|
|
||||||
shortcode = 40, 142, 215
|
|
||||||
keyword = 222, 61, 58
|
|
||||||
tag = 150, 74, 193
|
|
||||||
value = 224, 175, 5
|
|
||||||
optional = 40, 142, 215
|
|
||||||
spellcheckline = 222, 61, 58
|
|
||||||
errorline = 8, 145, 106
|
|
||||||
replacetag = 42, 162, 152
|
|
||||||
modifier = 8, 145, 106
|
|
||||||
texthighlight = 218, 170, 1, 96
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
##
|
|
||||||
# Theme: Night Owl
|
|
||||||
# Source: https://github.com/sdras/night-owl-vscode-theme
|
|
||||||
# Credit: Sarah Drasner
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = 011627 : 1, 22, 39
|
|
||||||
# Current Line = 32374d : 50, 55, 77
|
|
||||||
# Selection = 32374d : 50, 55, 77
|
|
||||||
# Foreground = d6deeb : 214, 222, 235
|
|
||||||
# Comment = 637777 : 99, 119, 119
|
|
||||||
# Red = f78c6c : 247, 140, 108
|
|
||||||
# Orange = ecc48d : 236, 196, 141
|
|
||||||
# Yellow = ffeb95 : 255, 235, 149
|
|
||||||
# Green = addb67 : 173, 219, 103
|
|
||||||
# Aqua = 7fdbca : 127, 219, 202
|
|
||||||
# Blue = 82aaff : 130, 170, 255
|
|
||||||
# Purple = c792ea : 199, 146, 234
|
|
||||||
##
|
|
||||||
|
|
||||||
[Main]
|
|
||||||
name = Night Owl
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Sarah Drasner (color theme)
|
|
||||||
url = https://github.com/sdras/night-owl-vscode-theme
|
|
||||||
license = MIT License
|
|
||||||
licenseurl = https://github.com/sdras/night-owl-vscode-theme/blob/master/LICENSE
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 1, 22, 39
|
|
||||||
text = 214, 222, 235
|
|
||||||
link = 130, 170, 255
|
|
||||||
headertext = 130, 170, 255
|
|
||||||
headertag = 130, 170, 255, 160
|
|
||||||
emphasis = 236, 196, 141
|
|
||||||
dialog = 173, 219, 103
|
|
||||||
altdialog = 255, 235, 149
|
|
||||||
note = 255, 249, 202
|
|
||||||
hidden = 99, 119, 119
|
|
||||||
shortcode = 130, 170, 255
|
|
||||||
keyword = 247, 140, 108
|
|
||||||
tag = 199, 146, 234
|
|
||||||
value = 255, 235, 149
|
|
||||||
optional = 130, 170, 255
|
|
||||||
spellcheckline = 247, 140, 108
|
|
||||||
errorline = 173, 219, 103
|
|
||||||
replacetag = 127, 219, 202
|
|
||||||
modifier = 173, 219, 103
|
|
||||||
texthighlight = 255, 235, 149, 96
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Snazzy Light
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Florian Reuschel (color theme)
|
|
||||||
url = https://github.com/loilo/vscode-snazzy-light
|
|
||||||
license = MIT License
|
|
||||||
licenseurl = https://github.com/loilo/vscode-snazzy-light/blob/master/LICENSE
|
|
||||||
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = fafbfc : 250, 251, 252
|
|
||||||
# Foreground = 565869 : 86, 88, 105
|
|
||||||
# Comment = 9194a2 : 145, 148, 162
|
|
||||||
# Yellow = cf9c00 : 207, 156, 0
|
|
||||||
# Red = ff5c57 : 255, 92, 87
|
|
||||||
# Pink = f767bb : 247, 103, 187
|
|
||||||
# Blue = 09a1ed : 9, 161, 237
|
|
||||||
# Cyan = 13bbb7 : 19, 187, 183
|
|
||||||
# Green = 2dae58 : 45, 174, 88
|
|
||||||
##
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 250, 251, 252
|
|
||||||
text = 86, 88, 105
|
|
||||||
link = 9, 161, 237
|
|
||||||
headertext = 45, 174, 88
|
|
||||||
headertag = 45, 174, 88, 160
|
|
||||||
emphasis = 247, 103, 187
|
|
||||||
dialog = 9, 161, 237
|
|
||||||
altdialog = 207, 156, 0
|
|
||||||
note = 120, 187, 185
|
|
||||||
hidden = 145, 148, 162
|
|
||||||
shortcode = 247, 103, 187
|
|
||||||
keyword = 9, 161, 237
|
|
||||||
tag = 45, 174, 88
|
|
||||||
value = 207, 156, 0
|
|
||||||
optional = 207, 156, 0
|
|
||||||
spellcheckline = 255, 92, 87
|
|
||||||
errorline = 45, 174, 88
|
|
||||||
replacetag = 19, 187, 183
|
|
||||||
modifier = 247, 103, 187
|
|
||||||
texthighlight = 207, 156, 0, 96
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Solarized Dark
|
|
||||||
author = nullbasis
|
|
||||||
credit = Ethan Schoonover
|
|
||||||
url = https://ethanschoonover.com/solarized/
|
|
||||||
license = MIT
|
|
||||||
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 7, 54, 66
|
|
||||||
text = 253, 246, 227
|
|
||||||
link = 38, 139, 210
|
|
||||||
headertext = 147, 161, 161
|
|
||||||
headertag = 42, 161, 152
|
|
||||||
emphasis = 38, 139, 210
|
|
||||||
dialog = 42, 161, 152
|
|
||||||
altdialog = 42, 161, 152
|
|
||||||
note = 101, 161, 156
|
|
||||||
hidden = 147, 161, 161
|
|
||||||
shortcode = 147, 161, 161
|
|
||||||
keyword = 133, 153, 0
|
|
||||||
tag = 203, 75, 22
|
|
||||||
value = 203, 75, 22
|
|
||||||
optional = 147, 161, 161
|
|
||||||
spellcheckline = 203, 75, 22
|
|
||||||
errorline = 220, 50, 47
|
|
||||||
replacetag = 133, 153, 0
|
|
||||||
modifier = 181, 137, 0
|
|
||||||
texthighlight = 181, 137, 0, 96
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Solarized Light
|
|
||||||
author = nullbasis
|
|
||||||
credit = Ethan Schoonover
|
|
||||||
url = https://ethanschoonover.com/solarized/
|
|
||||||
license = MIT
|
|
||||||
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 253, 246, 227
|
|
||||||
text = 0, 43, 54
|
|
||||||
link = 38, 139, 210
|
|
||||||
headertext = 88, 110, 117
|
|
||||||
headertag = 42, 161, 152
|
|
||||||
emphasis = 38, 139, 210
|
|
||||||
dialog = 42, 161, 152
|
|
||||||
altdialog = 42, 161, 152
|
|
||||||
note = 27, 102, 96
|
|
||||||
hidden = 88, 110, 117
|
|
||||||
shortcode = 88, 110, 117
|
|
||||||
keyword = 133, 153, 0
|
|
||||||
tag = 203, 75, 22
|
|
||||||
value = 203, 75, 22
|
|
||||||
optional = 88, 110, 117
|
|
||||||
spellcheckline = 203, 75, 22
|
|
||||||
errorline = 220, 50, 47
|
|
||||||
replacetag = 133, 153, 0
|
|
||||||
modifier = 181, 137, 0
|
|
||||||
texthighlight = 181, 137, 0, 96
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Tango
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = 30302f : 48, 48, 47
|
|
||||||
# Foreground = eeeeec : 238, 238, 236
|
|
||||||
# Comment = 8f8f8d : 143, 143, 141
|
|
||||||
# Red = ef2929 : 239, 41, 41
|
|
||||||
# Orange = c4a000 : 196, 160, 0
|
|
||||||
# Yellow = fce94f : 252, 233, 79
|
|
||||||
# Green = 8ae234 : 138, 226, 52
|
|
||||||
# Cyan = 34e2e2 : 52, 226, 226
|
|
||||||
# Blue = 3465a4 : 114, 159, 207
|
|
||||||
# Purple = ad7fa8 : 173, 127, 168
|
|
||||||
##
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 48, 48, 47
|
|
||||||
text = 238, 238, 236
|
|
||||||
link = 114, 159, 207
|
|
||||||
headertext = 114, 159, 207
|
|
||||||
headertag = 114, 159, 207, 160
|
|
||||||
emphasis = 196, 160, 0
|
|
||||||
dialog = 138, 226, 52
|
|
||||||
altdialog = 252, 233, 79
|
|
||||||
note = 252, 242, 164
|
|
||||||
hidden = 143, 143, 141
|
|
||||||
shortcode = 114, 159, 207
|
|
||||||
keyword = 239, 41, 41
|
|
||||||
tag = 173, 127, 168
|
|
||||||
value = 239, 41, 41
|
|
||||||
optional = 114, 159, 207
|
|
||||||
spellcheckline = 239, 41, 41
|
|
||||||
errorline = 138, 226, 52
|
|
||||||
replacetag = 52, 226, 226
|
|
||||||
modifier = 114, 159, 207
|
|
||||||
texthighlight = 252, 233, 79, 96
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
##
|
|
||||||
# Theme: Tomorrow
|
|
||||||
# Source: https://github.com/chriskempson/tomorrow-theme
|
|
||||||
# Credit: Chris Kempson
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = ffffff : 255, 255, 255
|
|
||||||
# Current Line = efefef : 239, 239, 239
|
|
||||||
# Selection = d6d6d6 : 214, 214, 214
|
|
||||||
# Foreground = 4d4d4c : 77, 77, 76
|
|
||||||
# Comment = 8e908c : 142, 144, 140
|
|
||||||
# Red = c82829 : 240, 40, 41
|
|
||||||
# Orange = f5871f : 245, 135, 31
|
|
||||||
# Yellow = eab700 : 234, 183, 0
|
|
||||||
# Green = 718c00 : 113, 140, 0
|
|
||||||
# Aqua = 3e999f : 62, 153, 159
|
|
||||||
# Blue = 4271ae : 66, 113, 174
|
|
||||||
# Purple = 8959a8 : 137, 89, 168
|
|
||||||
##
|
|
||||||
|
|
||||||
[Main]
|
|
||||||
name = Tomorrow
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Chris Kempson (color theme)
|
|
||||||
url = https://github.com/chriskempson/tomorrow-theme
|
|
||||||
license = MIT License
|
|
||||||
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 255, 255, 255
|
|
||||||
text = 77, 77, 76
|
|
||||||
link = 66, 113, 174
|
|
||||||
headertext = 66, 113, 174
|
|
||||||
headertag = 66, 113, 174, 160
|
|
||||||
emphasis = 245, 135, 31
|
|
||||||
dialog = 113, 140, 0
|
|
||||||
altdialog = 234, 183, 0
|
|
||||||
note = 115, 90, 0
|
|
||||||
hidden = 142, 144, 140
|
|
||||||
shortcode = 66, 113, 174
|
|
||||||
keyword = 240, 40, 41
|
|
||||||
tag = 137, 89, 168
|
|
||||||
value = 234, 183, 0
|
|
||||||
optional = 66, 113, 174
|
|
||||||
spellcheckline = 240, 40, 41
|
|
||||||
errorline = 113, 140, 0
|
|
||||||
replacetag = 62, 153, 159
|
|
||||||
modifier = 245, 135, 31
|
|
||||||
texthighlight = 234, 183, 0, 96
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
##
|
|
||||||
# Theme: Tomorrow Night
|
|
||||||
# Source: https://github.com/chriskempson/tomorrow-theme
|
|
||||||
# Credit: Chris Kempson
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = 1d1f21 : 29, 31, 33
|
|
||||||
# Current Line = 282a2e : 40, 42, 46
|
|
||||||
# Selection = 373b41 : 55, 59. 65
|
|
||||||
# Foreground = c5c8c6 : 197, 200, 198
|
|
||||||
# Comment = 969896 : 150, 152, 150
|
|
||||||
# Red = cc6666 : 204, 102, 102
|
|
||||||
# Orange = de935f : 222, 147, 95
|
|
||||||
# Yellow = f0c674 : 240, 198, 116
|
|
||||||
# Green = b5bd68 : 181, 189, 104
|
|
||||||
# Aqua = 8abeb7 : 138, 190, 183
|
|
||||||
# Blue = 81a2be : 129, 162, 190
|
|
||||||
# Purple = b294bb : 178, 148, 187
|
|
||||||
##
|
|
||||||
|
|
||||||
[Main]
|
|
||||||
name = Tomorrow Night
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Chris Kempson (color theme)
|
|
||||||
url = https://github.com/chriskempson/tomorrow-theme
|
|
||||||
license = MIT License
|
|
||||||
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 29, 31, 33
|
|
||||||
text = 197, 200, 198
|
|
||||||
link = 197, 200, 198, 160
|
|
||||||
headertext = 129, 162, 190
|
|
||||||
headertag = 94, 119, 139
|
|
||||||
emphasis = 222, 147, 95
|
|
||||||
dialog = 181, 189, 104
|
|
||||||
altdialog = 240, 198, 116
|
|
||||||
note = 240, 219, 178
|
|
||||||
hidden = 150, 152, 150
|
|
||||||
shortcode = 129, 162, 190
|
|
||||||
keyword = 204, 102, 102
|
|
||||||
tag = 178, 148, 187
|
|
||||||
value = 240, 198, 116
|
|
||||||
optional = 129, 162, 190
|
|
||||||
spellcheckline = 204, 102, 102
|
|
||||||
errorline = 181, 189, 104
|
|
||||||
replacetag = 138, 190, 183
|
|
||||||
modifier = 222, 147, 95
|
|
||||||
texthighlight = 240, 198, 116, 96
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
##
|
|
||||||
# Theme: Tomorrow Night Blue
|
|
||||||
# Source: https://github.com/chriskempson/tomorrow-theme
|
|
||||||
# Credit: Chris Kempson
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = 002451 : 0, 36, 81
|
|
||||||
# Current Line = 00346e : 0, 52, 110
|
|
||||||
# Selection = 003f8e : 0, 63, 142
|
|
||||||
# Foreground = ffffff : 255, 255, 255
|
|
||||||
# Comment = 7285b7 : 114, 133, 183
|
|
||||||
# Red = ff9da4 : 255, 157, 164
|
|
||||||
# Orange = ffc58f : 255, 197, 143
|
|
||||||
# Yellow = ffeead : 255, 238, 173
|
|
||||||
# Green = d1f1a9 : 209, 241, 169
|
|
||||||
# Aqua = 99ffff : 153, 255, 255
|
|
||||||
# Blue = bbdaff : 187, 218, 255
|
|
||||||
# Purple = ebbbff : 235, 187, 255
|
|
||||||
##
|
|
||||||
|
|
||||||
[Main]
|
|
||||||
name = Tomorrow Night Blue
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Chris Kempson (color theme)
|
|
||||||
url = https://github.com/chriskempson/tomorrow-theme
|
|
||||||
license = MIT License
|
|
||||||
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 0, 36, 81
|
|
||||||
text = 255, 255, 255
|
|
||||||
link = 187, 218, 255
|
|
||||||
headertext = 187, 218, 255
|
|
||||||
headertag = 187, 218, 255, 160
|
|
||||||
emphasis = 255, 197, 143
|
|
||||||
dialog = 209, 241, 169
|
|
||||||
altdialog = 255, 238, 173
|
|
||||||
note = 255, 247, 214
|
|
||||||
hidden = 114, 133, 183
|
|
||||||
shortcode = 187, 218, 255
|
|
||||||
keyword = 255, 157, 164
|
|
||||||
tag = 235, 187, 255
|
|
||||||
value = 255, 238, 173
|
|
||||||
optional = 187, 218, 255
|
|
||||||
spellcheckline = 255, 157, 164
|
|
||||||
errorline = 209, 241, 169
|
|
||||||
replacetag = 153, 255, 255
|
|
||||||
modifier = 255, 197, 143
|
|
||||||
texthighlight = 255, 238, 173, 96
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
##
|
|
||||||
# Theme: Tomorrow Night Bright
|
|
||||||
# Source: https://github.com/chriskempson/tomorrow-theme
|
|
||||||
# Credit: Chris Kempson
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = 000000 : 0, 0, 0
|
|
||||||
# Current Line = 2a2a2a : 42, 42, 42
|
|
||||||
# Selection = 424242 : 66, 66, 66
|
|
||||||
# Foreground = eaeaea : 234, 234, 234
|
|
||||||
# Comment = 969896 : 150, 152, 150
|
|
||||||
# Red = d54e53 : 213, 78, 83
|
|
||||||
# Orange = e78c45 : 231, 140, 69
|
|
||||||
# Yellow = e7c547 : 231, 197, 71
|
|
||||||
# Green = b9ca4a : 185, 202, 74
|
|
||||||
# Aqua = 70c0b1 : 112, 192, 177
|
|
||||||
# Blue = 7aa6da : 122, 166, 218
|
|
||||||
# Purple = c397d8 : 195, 151, 216
|
|
||||||
##
|
|
||||||
|
|
||||||
[Main]
|
|
||||||
name = Tomorrow Night Bright
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Chris Kempson (color theme)
|
|
||||||
url = https://github.com/chriskempson/tomorrow-theme
|
|
||||||
license = MIT License
|
|
||||||
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 0, 0, 0
|
|
||||||
text = 234, 234, 234
|
|
||||||
link = 122, 166, 218
|
|
||||||
headertext = 122, 166, 218
|
|
||||||
headertag = 122, 166, 218, 160
|
|
||||||
emphasis = 231, 140, 69
|
|
||||||
dialog = 185, 202, 74
|
|
||||||
altdialog = 231, 197, 71
|
|
||||||
note = 231, 214, 150
|
|
||||||
hidden = 150, 152, 150
|
|
||||||
shortcode = 122, 166, 218
|
|
||||||
keyword = 213, 78, 83
|
|
||||||
tag = 195, 151, 216
|
|
||||||
value = 231, 197, 71
|
|
||||||
optional = 122, 166, 218
|
|
||||||
spellcheckline = 213, 78, 83
|
|
||||||
errorline = 185, 202, 74
|
|
||||||
replacetag = 112, 192, 177
|
|
||||||
modifier = 231, 140, 69
|
|
||||||
texthighlight = 231, 197, 71, 128
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
##
|
|
||||||
# Theme: Tomorrow Night Eighties
|
|
||||||
# Source: https://github.com/chriskempson/tomorrow-theme
|
|
||||||
# Credit: Chris Kempson
|
|
||||||
##
|
|
||||||
# Colours:
|
|
||||||
# Background = 2d2d2d : 45, 45, 45
|
|
||||||
# Current Line = 393939 : 57, 57, 57
|
|
||||||
# Selection = 515151 : 81, 81, 81
|
|
||||||
# Foreground = cccccc : 204, 204, 204
|
|
||||||
# Comment = 999999 : 153, 153, 153
|
|
||||||
# Red = f2777a : 242, 119, 122
|
|
||||||
# Orange = f99157 : 249, 145, 57
|
|
||||||
# Yellow = ffcc66 : 255, 204, 102
|
|
||||||
# Green = 99cc99 : 153, 204, 153
|
|
||||||
# Aqua = 66cccc : 102, 204, 204
|
|
||||||
# Blue = 6699cc : 102, 153, 204
|
|
||||||
# Purple = cc99cc : 204, 153, 204
|
|
||||||
##
|
|
||||||
|
|
||||||
[Main]
|
|
||||||
name = Tomorrow Night Eighties
|
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
|
||||||
credit = Chris Kempson (color theme)
|
|
||||||
url = https://github.com/chriskempson/tomorrow-theme
|
|
||||||
license = MIT License
|
|
||||||
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
|
||||||
|
|
||||||
[Syntax]
|
|
||||||
background = 45, 45, 45
|
|
||||||
text = 204, 204, 204
|
|
||||||
link = 102, 153, 204
|
|
||||||
headertext = 102, 153, 204
|
|
||||||
headertag = 102, 153, 204, 160
|
|
||||||
emphasis = 249, 145, 57
|
|
||||||
dialog = 153, 204, 153
|
|
||||||
altdialog = 255, 204, 102
|
|
||||||
note = 255, 230, 179
|
|
||||||
hidden = 153, 153, 153
|
|
||||||
shortcode = 102, 153, 204
|
|
||||||
keyword = 242, 119, 122
|
|
||||||
tag = 204, 153, 204
|
|
||||||
value = 255, 204, 102
|
|
||||||
optional = 102, 153, 204
|
|
||||||
spellcheckline = 242, 119, 122
|
|
||||||
errorline = 153, 204, 153
|
|
||||||
replacetag = 102, 204, 204
|
|
||||||
modifier = 249, 145, 57
|
|
||||||
texthighlight = 255, 204, 102, 96
|
|
||||||
@@ -75,8 +75,8 @@ more contributions are listed on the project's Members page.</p>
|
|||||||
<li><b>Material Symbols</b> icons by Google Inc (Apache 2.0)</li>
|
<li><b>Material Symbols</b> icons by Google Inc (Apache 2.0)</li>
|
||||||
<li><b>Remix</b> icons by RemixIcon (Apache 2.0)</li>
|
<li><b>Remix</b> icons by RemixIcon (Apache 2.0)</li>
|
||||||
<li><b>Font Awesome</b> icons by Fonticons Inc (CC BY 4.0)</li>
|
<li><b>Font Awesome</b> icons by Fonticons Inc (CC BY 4.0)</li>
|
||||||
<li><b>Tomorrow</b> syntax themes by Chris Kempson (MIT License)</li>
|
<li><b>Tomorrow</b> themes by Chris Kempson (MIT License)</li>
|
||||||
<li><b>Owl</b> syntax themes by Sarah Drasner (MIT License)</li>
|
<li><b>Owl</b> themes by Sarah Drasner (MIT License)</li>
|
||||||
<li><b>Solarized</b> themes by Ethan Schoonover (MIT License)</li>
|
<li><b>Solarized</b> themes by Ethan Schoonover (MIT License)</li>
|
||||||
<li><b>Cyberpunk Night</b> theme by Anders Lemvigh (CC BY-SA 4.0)</li>
|
<li><b>Cyberpunk Night</b> theme by Anders Lemvigh (CC BY-SA 4.0)</li>
|
||||||
<li><b>Dracula</b> theme by Zeno Rocha (MIT License)</li>
|
<li><b>Dracula</b> theme by Zeno Rocha (MIT License)</li>
|
||||||
|
|||||||
@@ -1,48 +1,71 @@
|
|||||||
[Main]
|
[Main]
|
||||||
name = Cyberpunk Night
|
name = Cyberpunk Night
|
||||||
|
mode = dark
|
||||||
description = A taste of the future 80s
|
description = A taste of the future 80s
|
||||||
author = Anders Lemvigh
|
author = Anders Lemvigh
|
||||||
url = https://github.com/alemvigh
|
url = https://github.com/alemvigh
|
||||||
license = CC BY-SA 4.0
|
license = CC BY-SA 4.0
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||||
|
|
||||||
[Icons]
|
[Base]
|
||||||
default = 136, 136, 136
|
default = #888888
|
||||||
faded = 97, 97, 97
|
faded = #616161
|
||||||
red = 242, 72, 23
|
red = #f24817
|
||||||
orange = 255, 150, 10
|
orange = #ff960a
|
||||||
yellow = 255, 255, 0
|
yellow = #ffff00
|
||||||
green = 0, 255, 0
|
green = #00ff00
|
||||||
aqua = 0, 255, 255
|
cyan = #00ffff
|
||||||
blue = 77, 77, 255
|
blue = #4d4dff
|
||||||
purple = 50, 0, 180
|
purple = #320064
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
root = 77, 77, 255
|
root = #4d4dff
|
||||||
folder = 255, 255, 0
|
folder = #ffff00
|
||||||
file = 136, 136, 136
|
file = #888888
|
||||||
title = 0, 255, 0
|
title = #00ff00
|
||||||
chapter = 242, 72, 23
|
chapter = #f24817
|
||||||
scene = 77, 77, 255
|
scene = #4d4dff
|
||||||
note = 255, 255, 0
|
note = #ffff00
|
||||||
|
|
||||||
[Palette]
|
[Palette]
|
||||||
window = 0, 0, 0
|
window = #000000
|
||||||
windowtext = 150, 150, 150
|
windowtext = #969696
|
||||||
base = 0, 0, 0
|
base = #000000
|
||||||
alternatebase = 40, 40, 40
|
alternatebase = #282828
|
||||||
text = 150, 150, 150
|
text = #969696
|
||||||
tooltipbase = 40, 20, 70
|
tooltipbase = #281446
|
||||||
tooltiptext = 255, 255, 255
|
tooltiptext = #ffffff
|
||||||
button = 5, 0, 10
|
button = #05000a
|
||||||
buttontext = 150, 150, 150
|
buttontext = #969696
|
||||||
brighttext = 255, 255, 255
|
brighttext = #ffffff
|
||||||
highlight = 50, 30, 80
|
highlight = #321e50
|
||||||
highlightedtext = 255, 255, 255
|
highlightedtext = #ffffff
|
||||||
link = 77, 77, 255
|
link = #4d4dff
|
||||||
linkvisited = 50, 0, 80
|
linkvisited = #320050
|
||||||
|
|
||||||
[GUI]
|
[GUI]
|
||||||
helptext = 97, 97, 97
|
helptext = #616161
|
||||||
fadedtext = 97, 97, 97
|
fadedtext = #616161
|
||||||
errortext = 242, 72, 23
|
errortext = #f24817
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #000000
|
||||||
|
text = #969696
|
||||||
|
link = #4d4dff
|
||||||
|
headertext = #ffffff
|
||||||
|
headertag = #320064
|
||||||
|
emphasis = #00ffff
|
||||||
|
dialog = #00ff00
|
||||||
|
altdialog = #008cff
|
||||||
|
note = #969696
|
||||||
|
hidden = #4d4d64
|
||||||
|
shortcode = #ffff00
|
||||||
|
keyword = #ff64ff
|
||||||
|
tag = #ff960a
|
||||||
|
value = #ff960a
|
||||||
|
spellcheckline = #f24817
|
||||||
|
errorline = #bada04
|
||||||
|
replacetag = #0000b4
|
||||||
|
modifier = #908eb0
|
||||||
|
optional = #b4b4b4
|
||||||
|
texthighlight = #ffff8460
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
[Main]
|
|
||||||
name = Qt Default Theme
|
|
||||||
description = Qt standard colours
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
[Main]
|
[Main]
|
||||||
name = Default Dark Theme
|
name = Default Dark Theme
|
||||||
|
mode = dark
|
||||||
description = The novelWriter standard dark theme
|
description = The novelWriter standard dark theme
|
||||||
author = Veronica Berglyd Olsen
|
author = Veronica Berglyd Olsen
|
||||||
credit = Veronica Berglyd Olsen
|
credit = Veronica Berglyd Olsen
|
||||||
@@ -7,43 +8,65 @@ url = https://github.com/vkbo/novelWriter
|
|||||||
license = CC BY-SA 4.0
|
license = CC BY-SA 4.0
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||||
|
|
||||||
[Icons]
|
[Base]
|
||||||
default = 184, 184, 184
|
default = #cccccc
|
||||||
faded = 148, 148, 148
|
faded = #949494
|
||||||
red = 242, 119, 122
|
red = #f2777a
|
||||||
orange = 249, 145, 57
|
orange = #f99139
|
||||||
yellow = 255, 204, 102
|
yellow = #ffcc66
|
||||||
green = 153, 204, 153
|
green = #99cc99
|
||||||
aqua = 102, 204, 204
|
cyan = #66cccc
|
||||||
blue = 102, 153, 204
|
blue = #6699cc
|
||||||
purple = 204, 153, 204
|
purple = #cc99cc
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
root = 102, 153, 204
|
root = blue
|
||||||
folder = 255, 204, 102
|
folder = yellow
|
||||||
file = 184, 184, 184
|
file = default
|
||||||
title = 153, 204, 153
|
title = green
|
||||||
chapter = 242, 119, 122
|
chapter = red
|
||||||
scene = 102, 153, 204
|
scene = blue
|
||||||
note = 255, 204, 102
|
note = yellow
|
||||||
|
|
||||||
[Palette]
|
[Palette]
|
||||||
window = 54, 54, 54
|
window = #363636
|
||||||
windowtext = 204, 204, 204
|
windowtext = default
|
||||||
base = 62, 62, 62
|
base = #3e3e3e
|
||||||
alternatebase = 78, 78, 78
|
alternatebase = #4e4e4e
|
||||||
text = 204, 204, 204
|
text = default
|
||||||
tooltipbase = 255, 255, 192
|
tooltipbase = #ffffc0
|
||||||
tooltiptext = 21, 21, 13
|
tooltiptext = #15150d
|
||||||
button = 62, 62, 62
|
button = #3e3e3e
|
||||||
buttontext = 204, 204, 204
|
buttontext = default
|
||||||
brighttext = 62, 62, 62
|
brighttext = #3e3e3e
|
||||||
highlight = 44, 152, 247
|
highlight = #2c98f7
|
||||||
highlightedtext = 255, 255, 255
|
highlightedtext = #ffffff
|
||||||
link = 102, 153, 204
|
link = blue
|
||||||
linkvisited = 102, 153, 204
|
linkvisited = blue
|
||||||
|
|
||||||
[GUI]
|
[GUI]
|
||||||
helptext = 164, 164, 164
|
helptext = #a4a4a4
|
||||||
fadedtext = 148, 148, 148
|
fadedtext = faded
|
||||||
errortext = 255, 164, 164
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #363636
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = green
|
||||||
|
headertag = green:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = blue
|
||||||
|
altdialog = blue
|
||||||
|
note = yellow
|
||||||
|
hidden = faded
|
||||||
|
shortcode = green
|
||||||
|
keyword = red
|
||||||
|
tag = green
|
||||||
|
value = blue
|
||||||
|
optional = green
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = green
|
||||||
|
modifier = green
|
||||||
|
texthighlight = yellow:72
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
[Main]
|
[Main]
|
||||||
name = Default Light Theme
|
name = Default Light Theme
|
||||||
|
mode = light
|
||||||
description = The novelWriter standard light theme
|
description = The novelWriter standard light theme
|
||||||
author = Veronica Berglyd Olsen
|
author = Veronica Berglyd Olsen
|
||||||
credit = Veronica Berglyd Olsen
|
credit = Veronica Berglyd Olsen
|
||||||
@@ -7,43 +8,65 @@ url = https://github.com/vkbo/novelWriter
|
|||||||
license = CC BY-SA 4.0
|
license = CC BY-SA 4.0
|
||||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||||
|
|
||||||
[Icons]
|
[Base]
|
||||||
default = 72, 72, 72
|
default = #303030
|
||||||
faded = 108, 108, 108
|
faded = #6c6c6c
|
||||||
red = 240, 40, 41
|
red = #a62a2d
|
||||||
orange = 245, 135, 31
|
orange = #b36829
|
||||||
yellow = 234, 183, 0
|
yellow = #a68542
|
||||||
green = 113, 140, 0
|
green = #296629
|
||||||
aqua = 62, 153, 159
|
cyan = #269999
|
||||||
blue = 66, 113, 174
|
blue = #3a70a6
|
||||||
purple = 137, 89, 168
|
purple = #b35ab3
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
root = 66, 113, 174
|
root = blue
|
||||||
folder = 234, 183, 0
|
folder = yellow
|
||||||
file = 72, 72, 72
|
file = default
|
||||||
title = 113, 140, 0
|
title = green
|
||||||
chapter = 240, 40, 41
|
chapter = red
|
||||||
scene = 66, 113, 174
|
scene = blue
|
||||||
note = 234, 183, 0
|
note = yellow
|
||||||
|
|
||||||
[Palette]
|
[Palette]
|
||||||
window = 239, 239, 239
|
window = #efefef
|
||||||
windowtext = 0, 0, 0
|
windowtext = #000000
|
||||||
base = 255, 255, 255
|
base = #ffffff
|
||||||
alternatebase = 224, 224, 224
|
alternatebase = #e0e0e0
|
||||||
text = 0, 0, 0
|
text = #000000
|
||||||
tooltipbase = 255, 255, 220
|
tooltipbase = #ffffc0
|
||||||
tooltiptext = 0, 0, 0
|
tooltiptext = #15150d
|
||||||
button = 239, 239, 239
|
button = #efefef
|
||||||
buttontext = 0, 0, 0
|
buttontext = #000000
|
||||||
brighttext = 255, 255, 255
|
brighttext = #ffffff
|
||||||
highlight = 48, 135, 198
|
highlight = #3087c6
|
||||||
highlightedtext = 255, 255, 255
|
highlightedtext = #ffffff
|
||||||
link = 66, 113, 174
|
link = blue
|
||||||
linkvisited = 66, 113, 174
|
linkvisited = blue
|
||||||
|
|
||||||
[GUI]
|
[GUI]
|
||||||
helptext = 92, 92, 92
|
helptext = #5c5c5c
|
||||||
fadedtext = 108, 108, 108
|
fadedtext = #6c6c6c
|
||||||
errortext = 255, 92, 92
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #ffffff
|
||||||
|
text = #000000
|
||||||
|
link = blue
|
||||||
|
headertext = green
|
||||||
|
headertag = green:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = blue
|
||||||
|
altdialog = blue
|
||||||
|
note = yellow
|
||||||
|
hidden = faded
|
||||||
|
shortcode = green
|
||||||
|
keyword = red
|
||||||
|
tag = green
|
||||||
|
value = blue
|
||||||
|
optional = green
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = green
|
||||||
|
modifier = green
|
||||||
|
texthighlight = #c8c80060
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
[Main]
|
[Main]
|
||||||
name = Dracula
|
name = Dracula
|
||||||
|
mode = dark
|
||||||
description = A dark theme with bright colours
|
description = A dark theme with bright colours
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
credit = Zeno Rocha
|
credit = Zeno Rocha
|
||||||
@@ -9,9 +10,10 @@ licenseurl = https://github.com/dracula/dracula-theme/blob/main/LICENSE
|
|||||||
|
|
||||||
##
|
##
|
||||||
# Colours:
|
# Colours:
|
||||||
|
# See: https://spec.draculatheme.com/
|
||||||
# Background = 282a36 : 40, 42, 54
|
# Background = 282a36 : 40, 42, 54
|
||||||
# Foreground = f8f8f2 : 248, 248, 242
|
# Foreground = f8f8f2 : 248, 248, 242
|
||||||
# Current Line = 44475A : 68, 71, 90
|
# Current Line = 44475a : 68, 71, 90
|
||||||
# Comment = 6272a4 : 98, 114, 164
|
# Comment = 6272a4 : 98, 114, 164
|
||||||
# Cyan = 8be9fd : 139, 233, 253
|
# Cyan = 8be9fd : 139, 233, 253
|
||||||
# Green = 50fa7b : 80, 250, 123
|
# Green = 50fa7b : 80, 250, 123
|
||||||
@@ -22,43 +24,65 @@ licenseurl = https://github.com/dracula/dracula-theme/blob/main/LICENSE
|
|||||||
# Yellow = f1fa8c : 241, 250, 140
|
# Yellow = f1fa8c : 241, 250, 140
|
||||||
##
|
##
|
||||||
|
|
||||||
[Icons]
|
[Base]
|
||||||
default = 230, 230, 224
|
default = #e6e6e0
|
||||||
faded = 98, 114, 164
|
faded = #6272a4
|
||||||
red = 255, 85, 85
|
red = #ff5555
|
||||||
orange = 255, 184, 108
|
orange = #ffb86c
|
||||||
yellow = 241, 250, 140
|
yellow = #f1fa8c
|
||||||
green = 80, 250, 123
|
green = #50fa7b
|
||||||
aqua = 139, 233, 253
|
cyan = #8be9fd
|
||||||
blue = 147, 207, 249
|
blue = #93cff9
|
||||||
purple = 189, 147, 249
|
purple = #bd93f9
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
root = 189, 147, 249
|
root = #bd93f9
|
||||||
folder = 241, 250, 140
|
folder = #f1fa8c
|
||||||
file = 230, 230, 224
|
file = #e6e6e0
|
||||||
title = 80, 250, 123
|
title = #50fa7b
|
||||||
chapter = 255, 85, 85
|
chapter = #ff5555
|
||||||
scene = 139, 233, 253
|
scene = #8be9fd
|
||||||
note = 241, 250, 140
|
note = #f1fa8c
|
||||||
|
|
||||||
[Palette]
|
[Palette]
|
||||||
window = 68, 71, 90
|
window = #44475a
|
||||||
windowtext = 248, 248, 242
|
windowtext = #f8f8f2
|
||||||
base = 40, 42, 54
|
base = #282a36
|
||||||
alternatebase = 51, 54, 69
|
alternatebase = #333645
|
||||||
text = 248, 248, 242
|
text = #f8f8f2
|
||||||
tooltipbase = 241, 250, 140
|
tooltipbase = #f1fa8c
|
||||||
tooltiptext = 40, 42, 54
|
tooltiptext = #282a36
|
||||||
button = 80, 83, 105
|
button = #505369
|
||||||
buttontext = 248, 248, 242
|
buttontext = #f8f8f2
|
||||||
brighttext = 68, 71, 90
|
brighttext = #44475a
|
||||||
highlight = 166, 129, 218
|
highlight = #a681da
|
||||||
highlightedtext = 248, 248, 242
|
highlightedtext = #f8f8f2
|
||||||
link = 139, 233, 253
|
link = #8be9fd
|
||||||
linkvisited = 139, 233, 253
|
linkvisited = #8be9fd
|
||||||
|
|
||||||
[GUI]
|
[GUI]
|
||||||
helptext = 204, 172, 249
|
helptext = #ccacf9
|
||||||
fadedtext = 98, 114, 164
|
fadedtext = #6272a4
|
||||||
errortext = 255, 85, 85
|
errortext = #ff5555
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #282a36
|
||||||
|
text = #f8f8f2
|
||||||
|
link = #ff79c6
|
||||||
|
headertext = #bd93f9
|
||||||
|
headertag = #bd93f9a0
|
||||||
|
emphasis = #ffb86c
|
||||||
|
dialog = #50fa7b
|
||||||
|
altdialog = #f1fa8c
|
||||||
|
note = #ffcce9
|
||||||
|
hidden = #6272a4
|
||||||
|
shortcode = #8be9fd
|
||||||
|
keyword = #ff79c6
|
||||||
|
tag = #ffb86c
|
||||||
|
value = #ffb86c
|
||||||
|
optional = #50fa7b
|
||||||
|
spellcheckline = #ff5555
|
||||||
|
errorline = #50fa7b
|
||||||
|
replacetag = #f1fa8c
|
||||||
|
modifier = #8be9fd
|
||||||
|
texthighlight = #f1fa8c60
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
[Main]
|
||||||
|
name = Grey Dark
|
||||||
|
mode = dark
|
||||||
|
author = Veronica Berglyd Olsen
|
||||||
|
credit = Veronica Berglyd Olsen
|
||||||
|
url = https://github.com/vkbo/novelWriter
|
||||||
|
license = CC BY-SA 4.0
|
||||||
|
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #cccccc
|
||||||
|
faded = #949494
|
||||||
|
red = #f2777a
|
||||||
|
orange = #f99139
|
||||||
|
yellow = #ffcc66
|
||||||
|
green = #99cc99
|
||||||
|
cyan = #66cccc
|
||||||
|
blue = #6699cc
|
||||||
|
purple = #cc99cc
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #363636
|
||||||
|
windowtext = default
|
||||||
|
base = #3e3e3e
|
||||||
|
alternatebase = #4e4e4e
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #3e3e3e
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #3e3e3e
|
||||||
|
highlight = #2c98f7
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #a4a4a4
|
||||||
|
fadedtext = faded
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #363636
|
||||||
|
text = #c8c8c8
|
||||||
|
link = #c8c8c8
|
||||||
|
headertext = #e1e1e1
|
||||||
|
headertag = #e1e1e1a0
|
||||||
|
emphasis = #c8c8c8
|
||||||
|
dialog = #c8c8c8
|
||||||
|
altdialog = #c8c8c8
|
||||||
|
note = #c8c8c8
|
||||||
|
hidden = faded
|
||||||
|
shortcode = #e1e1e1
|
||||||
|
keyword = #e1e1e1
|
||||||
|
tag = #c8c8c8
|
||||||
|
value = #c8c8c8
|
||||||
|
optional = #e1e1e1
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = #e1e1e1
|
||||||
|
modifier = #e1e1e1
|
||||||
|
texthighlight = #ffffff40
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
[Main]
|
||||||
|
name = Grey Light
|
||||||
|
mode = light
|
||||||
|
author = Veronica Berglyd Olsen
|
||||||
|
credit = Veronica Berglyd Olsen
|
||||||
|
url = https://github.com/vkbo/novelWriter
|
||||||
|
license = CC BY-SA 4.0
|
||||||
|
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #303030
|
||||||
|
faded = #6c6c6c
|
||||||
|
red = #a62a2d
|
||||||
|
orange = #b36829
|
||||||
|
yellow = #a68542
|
||||||
|
green = #296629
|
||||||
|
cyan = #269999
|
||||||
|
blue = #3a70a6
|
||||||
|
purple = #b35ab3
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #efefef
|
||||||
|
windowtext = default
|
||||||
|
base = #ffffff
|
||||||
|
alternatebase = #e0e0e0
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #efefef
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #ffffff
|
||||||
|
highlight = #3087c6
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #5c5c5c
|
||||||
|
fadedtext = faded
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #ffffff
|
||||||
|
text = #141414
|
||||||
|
link = #141414
|
||||||
|
headertext = #000000
|
||||||
|
headertag = #000000a0
|
||||||
|
emphasis = #141414
|
||||||
|
dialog = #141414
|
||||||
|
altdialog = #141414
|
||||||
|
note = #141414
|
||||||
|
hidden = faded
|
||||||
|
shortcode = #000000
|
||||||
|
keyword = #000000
|
||||||
|
tag = #141414
|
||||||
|
value = #141414
|
||||||
|
optional = #000000
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = #000000
|
||||||
|
modifier = #000000
|
||||||
|
texthighlight = #00000040
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
[Main]
|
||||||
|
name = Light Owl
|
||||||
|
mode = light
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
credit = Sarah Drasner (color theme)
|
||||||
|
url = https://github.com/sdras/night-owl-vscode-theme
|
||||||
|
license = MIT License
|
||||||
|
licenseurl = https://github.com/sdras/night-owl-vscode-theme/blob/master/LICENSE
|
||||||
|
|
||||||
|
##
|
||||||
|
# Theme: Light Owl
|
||||||
|
# Source: https://github.com/sdras/night-owl-vscode-theme
|
||||||
|
# Credit: Sarah Drasner
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = #fbfbfb
|
||||||
|
# Current Line = #e0e0e0
|
||||||
|
# Selection = #e0e0e0
|
||||||
|
# Foreground = #403f52
|
||||||
|
# Comment = #989fb1
|
||||||
|
# Red = #de3d3a
|
||||||
|
# Orange = #e0af05
|
||||||
|
# Yellow = #daaa01
|
||||||
|
# Green = #08916a
|
||||||
|
# Aqua = #2aa298
|
||||||
|
# Blue = #288ed7
|
||||||
|
# Purple = #964ac1
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #403f52
|
||||||
|
faded = #989fb1
|
||||||
|
red = #de3d3a
|
||||||
|
orange = #e0af05
|
||||||
|
yellow = #daaa01
|
||||||
|
green = #08916a
|
||||||
|
cyan = #2aa298
|
||||||
|
blue = #288ed7
|
||||||
|
purple = #964ac1
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #e0e0e0
|
||||||
|
windowtext = default
|
||||||
|
base = #fbfbfb
|
||||||
|
alternatebase = #e0e0e0
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #e0e0e0
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #e0e0e0
|
||||||
|
highlight = #3087c6
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = blue
|
||||||
|
fadedtext = faded
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #fbfbfb
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #80764b
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = orange
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = green
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
[Main]
|
||||||
|
name = Night Owl
|
||||||
|
mode = dark
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
credit = Sarah Drasner (color theme)
|
||||||
|
url = https://github.com/sdras/night-owl-vscode-theme
|
||||||
|
license = MIT License
|
||||||
|
licenseurl = https://github.com/sdras/night-owl-vscode-theme/blob/master/LICENSE
|
||||||
|
|
||||||
|
##
|
||||||
|
# Theme: Night Owl
|
||||||
|
# Source: https://github.com/sdras/night-owl-vscode-theme
|
||||||
|
# Credit: Sarah Drasner
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = #011627
|
||||||
|
# Current Line = #32374d
|
||||||
|
# Selection = #32374d
|
||||||
|
# Foreground = #d6deeb
|
||||||
|
# Comment = #637777
|
||||||
|
# Red = #f78c6c
|
||||||
|
# Orange = #ecc48d
|
||||||
|
# Yellow = #ffeb95
|
||||||
|
# Green = #addb67
|
||||||
|
# Aqua = #7fdbca
|
||||||
|
# Blue = #82aaff
|
||||||
|
# Purple = #c792ea
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #d6deeb
|
||||||
|
faded = #637777
|
||||||
|
red = #f78c6c
|
||||||
|
orange = #ecc48d
|
||||||
|
yellow = #addb67
|
||||||
|
green = #addb67
|
||||||
|
cyan = #7fdbca
|
||||||
|
blue = #82aaff
|
||||||
|
purple = #c792ea
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #32374d
|
||||||
|
windowtext = default
|
||||||
|
base = #011627
|
||||||
|
alternatebase = #32374d
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #32374d
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #32374d
|
||||||
|
highlight = #2c98f7
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = blue
|
||||||
|
fadedtext = faded
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #011627
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #fff9ca
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = orange
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = green
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -1,48 +1,84 @@
|
|||||||
[Main]
|
[Main]
|
||||||
name = Snazzy Light
|
name = Snazzy Light
|
||||||
|
mode = light
|
||||||
author = Veronica Berglyd Olsen (adaptation)
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
credit = Florian Reuschel (color theme)
|
credit = Florian Reuschel (color theme)
|
||||||
url = https://github.com/loilo/vscode-snazzy-light
|
url = https://github.com/loilo/vscode-snazzy-light
|
||||||
license = MIT License
|
license = MIT License
|
||||||
licenseurl = https://github.com/loilo/vscode-snazzy-light/blob/master/LICENSE
|
licenseurl = https://github.com/loilo/vscode-snazzy-light/blob/master/LICENSE
|
||||||
|
|
||||||
[Icons]
|
##
|
||||||
default = 86, 88, 105
|
# Colours:
|
||||||
faded = 84, 85, 84
|
# Background = fafbfc : 250, 251, 252
|
||||||
red = 255, 92, 87
|
# Foreground = 565869 : 86, 88, 105
|
||||||
orange = 245, 185, 0
|
# Comment = 9194a2 : 145, 148, 162
|
||||||
yellow = 207, 156, 0
|
# Yellow = cf9c00 : 207, 156, 0
|
||||||
green = 45, 174, 88
|
# Red = ff5c57 : 255, 92, 87
|
||||||
aqua = 19, 187, 183
|
# Pink = f767bb : 247, 103, 187
|
||||||
blue = 9, 161, 237
|
# Blue = 09a1ed : 9, 161, 237
|
||||||
purple = 247, 103, 187
|
# Cyan = 13bbb7 : 19, 187, 183
|
||||||
|
# Green = 2dae58 : 45, 174, 88
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #565869
|
||||||
|
faded = #545554
|
||||||
|
red = #ff5c57
|
||||||
|
orange = #f5b900
|
||||||
|
yellow = #cf9c00
|
||||||
|
green = #2dae58
|
||||||
|
cyan = #13bbb7
|
||||||
|
blue = #09a1ed
|
||||||
|
purple = #f767bb
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
root = 9, 161, 237
|
root = #09a1ed
|
||||||
folder = 207, 156, 0
|
folder = #cf9c00
|
||||||
file = 84, 85, 84
|
file = #545554
|
||||||
title = 45, 174, 88
|
title = #2dae58
|
||||||
chapter = 255, 92, 87
|
chapter = #ff5c57
|
||||||
scene = 9, 161, 237
|
scene = #09a1ed
|
||||||
note = 207, 156, 0
|
note = #cf9c00
|
||||||
|
|
||||||
[Palette]
|
[Palette]
|
||||||
window = 243, 244, 245
|
window = #f3f4f5
|
||||||
windowtext = 86, 88, 105
|
windowtext = #565869
|
||||||
base = 250, 251, 252
|
base = #fafbfc
|
||||||
alternatebase = 234, 234, 235
|
alternatebase = #eaeaeb
|
||||||
text = 86, 88, 105
|
text = #565869
|
||||||
tooltipbase = 245, 233, 194
|
tooltipbase = #f5e9c2
|
||||||
tooltiptext = 86, 88, 105
|
tooltiptext = #565869
|
||||||
button = 250, 251, 252
|
button = #fafbfc
|
||||||
buttontext = 86, 88, 105
|
buttontext = #565869
|
||||||
brighttext = 255, 255, 255
|
brighttext = #ffffff
|
||||||
highlight = 9, 161, 237
|
highlight = #09a1ed
|
||||||
highlightedtext = 255, 255, 255
|
highlightedtext = #ffffff
|
||||||
link = 9, 161, 237
|
link = #09a1ed
|
||||||
linkvisited = 9, 161, 237
|
linkvisited = #09a1ed
|
||||||
|
|
||||||
[GUI]
|
[GUI]
|
||||||
helptext = 9, 161, 237
|
helptext = #09a1ed
|
||||||
fadedtext = 84, 85, 84
|
fadedtext = #545554
|
||||||
errortext = 255, 92, 87
|
errortext = #ff5c57
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #fafbfc
|
||||||
|
text = #565869
|
||||||
|
link = #09a1ed
|
||||||
|
headertext = #2dae58
|
||||||
|
headertag = #2dae58a0
|
||||||
|
emphasis = #f767bb
|
||||||
|
dialog = #09a1ed
|
||||||
|
altdialog = #cf9c00
|
||||||
|
note = #78bbb9
|
||||||
|
hidden = #9194a2
|
||||||
|
shortcode = #f767bb
|
||||||
|
keyword = #09a1ed
|
||||||
|
tag = #2dae58
|
||||||
|
value = #cf9c00
|
||||||
|
optional = #cf9c00
|
||||||
|
spellcheckline = #ff5c57
|
||||||
|
errorline = #2dae58
|
||||||
|
replacetag = #13bbb7
|
||||||
|
modifier = #f767bb
|
||||||
|
texthighlight = #cf9c0060
|
||||||
|
|||||||
@@ -1,48 +1,90 @@
|
|||||||
[Main]
|
[Main]
|
||||||
name = Solarized Dark
|
name = Solarized Dark
|
||||||
|
mode = dark
|
||||||
author = nullbasis
|
author = nullbasis
|
||||||
credit = Ethan Schoonover
|
credit = Ethan Schoonover
|
||||||
url = https://ethanschoonover.com/solarized/
|
url = https://ethanschoonover.com/solarized/
|
||||||
license = MIT
|
license = MIT
|
||||||
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
|
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
|
||||||
|
|
||||||
[Icons]
|
##
|
||||||
default = 230, 223, 206
|
# base03: #002b36
|
||||||
faded = 166, 161, 149
|
# base02: #073642
|
||||||
red = 220, 50, 47
|
# base01: #586e75
|
||||||
orange = 203, 75, 22
|
# base00: #657b83
|
||||||
yellow = 181, 137, 0
|
# base0: #839496
|
||||||
green = 133, 153, 0
|
# base1: #93a1a1
|
||||||
aqua = 42, 161, 152
|
# base2: #eee8d5
|
||||||
blue = 38, 139, 210
|
# base3: #fdf6e3
|
||||||
purple = 211, 54, 130
|
# yellow: #b58900
|
||||||
|
# orange: #cb4b16
|
||||||
|
# red: #dc322f
|
||||||
|
# magenta: #d33682
|
||||||
|
# violet: #6c71c4
|
||||||
|
# blue: #268bd2
|
||||||
|
# cyan: #2aa198
|
||||||
|
# green: #859900
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #e6dfce
|
||||||
|
faded = #a6a195
|
||||||
|
red = #dc322f
|
||||||
|
orange = #cb4b16
|
||||||
|
yellow = #b58900
|
||||||
|
green = #859900
|
||||||
|
cyan = #2aa198
|
||||||
|
blue = #268bd2
|
||||||
|
purple = #6c71c4
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
root = 42, 161, 152
|
root = #2aa198
|
||||||
folder = 42, 161, 152
|
folder = #2aa198
|
||||||
file = 230, 223, 206
|
file = #e6dfce
|
||||||
title = 133, 153, 0
|
title = #859900
|
||||||
chapter = 220, 50, 47
|
chapter = #dc322f
|
||||||
scene = 38, 139, 210
|
scene = #268bd2
|
||||||
note = 181, 137, 0
|
note = #b58900
|
||||||
|
|
||||||
[Palette]
|
[Palette]
|
||||||
window = 0, 43, 54
|
window = #002b36
|
||||||
windowtext = 253, 246, 227
|
windowtext = #fdf6e3
|
||||||
base = 7, 54, 66
|
base = #073642
|
||||||
alternatebase = 88, 110, 117
|
alternatebase = #586e75
|
||||||
text = 253, 246, 227
|
text = #fdf6e3
|
||||||
tooltipbase = 133, 153, 0
|
tooltipbase = #859900
|
||||||
tooltiptext = 0, 43, 54
|
tooltiptext = #002b36
|
||||||
button = 7, 54, 66
|
button = #073642
|
||||||
buttontext = 253, 246, 227
|
buttontext = #fdf6e3
|
||||||
brighttext = 7, 54, 66
|
brighttext = #073642
|
||||||
highlight = 42, 161, 152
|
highlight = #2aa198
|
||||||
highlightedtext = 0, 43, 54
|
highlightedtext = #002b36
|
||||||
link = 38, 139, 210
|
link = #268bd2
|
||||||
linkvisited = 38, 139, 210
|
linkvisited = #268bd2
|
||||||
|
|
||||||
[GUI]
|
[GUI]
|
||||||
helptext = 101, 123, 131
|
helptext = #657b83
|
||||||
fadedtext = 101, 123, 131
|
fadedtext = #657b83
|
||||||
errortext = 220, 50, 47
|
errortext = #dc322f
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #073642
|
||||||
|
text = #fdf6e3
|
||||||
|
link = #268bd2
|
||||||
|
headertext = #93a1a1
|
||||||
|
headertag = #2aa198
|
||||||
|
emphasis = #268bd2
|
||||||
|
dialog = #2aa198
|
||||||
|
altdialog = #2aa198
|
||||||
|
note = #65a19c
|
||||||
|
hidden = #93a1a1
|
||||||
|
shortcode = #93a1a1
|
||||||
|
keyword = #859900
|
||||||
|
tag = #cb4b16
|
||||||
|
value = #cb4b16
|
||||||
|
optional = #93a1a1
|
||||||
|
spellcheckline = #cb4b16
|
||||||
|
errorline = #dc322f
|
||||||
|
replacetag = #859900
|
||||||
|
modifier = #b58900
|
||||||
|
texthighlight = #b5890060
|
||||||
|
|||||||
@@ -1,48 +1,90 @@
|
|||||||
[Main]
|
[Main]
|
||||||
name = Solarized Light
|
name = Solarized Light
|
||||||
|
mode = light
|
||||||
author = nullbasis
|
author = nullbasis
|
||||||
credit = Ethan Schoonover
|
credit = Ethan Schoonover
|
||||||
url = https://ethanschoonover.com/solarized/
|
url = https://ethanschoonover.com/solarized/
|
||||||
license = MIT
|
license = MIT
|
||||||
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
|
licenseurl = https://github.com/altercation/solarized/blob/master/LICENSE
|
||||||
|
|
||||||
[Icons]
|
##
|
||||||
default = 59, 68, 71
|
# base03: #002b36
|
||||||
faded = 78, 91, 95
|
# base02: #073642
|
||||||
red = 220, 50, 47
|
# base01: #586e75
|
||||||
orange = 203, 75, 22
|
# base00: #657b83
|
||||||
yellow = 181, 137, 0
|
# base0: #839496
|
||||||
green = 133, 153, 0
|
# base1: #93a1a1
|
||||||
aqua = 42, 161, 152
|
# base2: #eee8d5
|
||||||
blue = 38, 139, 210
|
# base3: #fdf6e3
|
||||||
purple = 211, 54, 130
|
# yellow: #b58900
|
||||||
|
# orange: #cb4b16
|
||||||
|
# red: #dc322f
|
||||||
|
# magenta: #d33682
|
||||||
|
# violet: #6c71c4
|
||||||
|
# blue: #268bd2
|
||||||
|
# cyan: #2aa198
|
||||||
|
# green: #859900
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #3b4447
|
||||||
|
faded = #4e5b5f
|
||||||
|
red = #dc322f
|
||||||
|
orange = #cb4b16
|
||||||
|
yellow = #b58900
|
||||||
|
green = #859900
|
||||||
|
cyan = #2aa198
|
||||||
|
blue = #268bd2
|
||||||
|
purple = #6c71c4
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
root = 42, 161, 152
|
root = #2aa198
|
||||||
folder = 42, 161, 152
|
folder = #2aa198
|
||||||
file = 59, 68, 71
|
file = #3b4447
|
||||||
title = 133, 153, 0
|
title = #859900
|
||||||
chapter = 220, 50, 47
|
chapter = #dc322f
|
||||||
scene = 38, 139, 210
|
scene = #268bd2
|
||||||
note = 181, 137, 0
|
note = #b58900
|
||||||
|
|
||||||
[Palette]
|
[Palette]
|
||||||
window = 238, 232, 213
|
window = #eee8d5
|
||||||
windowtext = 0, 43, 54
|
windowtext = #002b36
|
||||||
base = 253, 246, 227
|
base = #fdf6e3
|
||||||
alternatebase = 147, 161, 161
|
alternatebase = #93a1a1
|
||||||
text = 0, 43, 54
|
text = #002b36
|
||||||
tooltipbase = 133, 153, 0
|
tooltipbase = #859900
|
||||||
tooltiptext = 0, 43, 54
|
tooltiptext = #002b36
|
||||||
button = 238, 232, 213
|
button = #eee8d5
|
||||||
buttontext = 0, 43, 54
|
buttontext = #002b36
|
||||||
brighttext = 253, 246, 227
|
brighttext = #fdf6e3
|
||||||
highlight = 42, 161, 152
|
highlight = #2aa198
|
||||||
highlightedtext = 253, 246, 227
|
highlightedtext = #fdf6e3
|
||||||
link = 38, 139, 210
|
link = #268bd2
|
||||||
linkvisited = 38, 139, 210
|
linkvisited = #268bd2
|
||||||
|
|
||||||
[GUI]
|
[GUI]
|
||||||
helptext = 78, 91, 95
|
helptext = #4e5b5f
|
||||||
fadedtext = 78, 91, 95
|
fadedtext = #4e5b5f
|
||||||
errortext = 220, 50, 47
|
errortext = #dc322f
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #fdf6e3
|
||||||
|
text = #002b36
|
||||||
|
link = #268bd2
|
||||||
|
headertext = #586e75
|
||||||
|
headertag = #2aa198
|
||||||
|
emphasis = #268bd2
|
||||||
|
dialog = #2aa198
|
||||||
|
altdialog = #2aa198
|
||||||
|
note = #1b6660
|
||||||
|
hidden = #586e75
|
||||||
|
shortcode = #586e75
|
||||||
|
keyword = #859900
|
||||||
|
tag = #cb4b16
|
||||||
|
value = #cb4b16
|
||||||
|
optional = #586e75
|
||||||
|
spellcheckline = #cb4b16
|
||||||
|
errorline = #dc322f
|
||||||
|
replacetag = #859900
|
||||||
|
modifier = #b58900
|
||||||
|
texthighlight = #b5890060
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
[Main]
|
||||||
|
name = Tango Dark
|
||||||
|
mode = dark
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = 30302f : 48, 48, 47
|
||||||
|
# Foreground = eeeeec : 238, 238, 236
|
||||||
|
# Comment = 8f8f8d : 143, 143, 141
|
||||||
|
# Red = ef2929 : 239, 41, 41
|
||||||
|
# Orange = c4a000 : 196, 160, 0
|
||||||
|
# Yellow = fce94f : 252, 233, 79
|
||||||
|
# Green = 8ae234 : 138, 226, 52
|
||||||
|
# Cyan = 34e2e2 : 52, 226, 226
|
||||||
|
# Blue = 3465a4 : 114, 159, 207
|
||||||
|
# Purple = ad7fa8 : 173, 127, 168
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #eeeeec
|
||||||
|
faded = #babdb6
|
||||||
|
red = #ef2929
|
||||||
|
orange = #fcaf3e
|
||||||
|
yellow = #fce94f
|
||||||
|
green = #8ae234
|
||||||
|
cyan = #34e2e2
|
||||||
|
blue = #729fcf
|
||||||
|
purple = #ad7fa8
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #555753
|
||||||
|
windowtext = default
|
||||||
|
base = #2e3436
|
||||||
|
alternatebase = #888a85
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #555753
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #555753
|
||||||
|
highlight = #2c98f7
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #e9b96e
|
||||||
|
fadedtext = faded
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #2e3436
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #fcf2a4
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = red
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = blue
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
[Main]
|
||||||
|
name = Tango Light
|
||||||
|
mode = light
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = #eeeeec
|
||||||
|
# Foreground = #2e3436
|
||||||
|
# Comment = 8f8f8d : 143, 143, 141
|
||||||
|
# Red = #a40000
|
||||||
|
# Orange = c4a000 : 196, 160, 0
|
||||||
|
# Yellow = fce94f : 252, 233, 79
|
||||||
|
# Green = 8ae234 : 138, 226, 52
|
||||||
|
# Cyan = 34e2e2 : 52, 226, 226
|
||||||
|
# Blue = 3465a4 : 114, 159, 207
|
||||||
|
# Purple = ad7fa8 : 173, 127, 168
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #2e3436
|
||||||
|
faded = #888a85
|
||||||
|
red = #a40000
|
||||||
|
orange = #ce5c00
|
||||||
|
yellow = #c4a000
|
||||||
|
green = #4e9a06
|
||||||
|
cyan = #069a9a
|
||||||
|
blue = #204a87
|
||||||
|
purple = #5c3566
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #d3d7cf
|
||||||
|
windowtext = default
|
||||||
|
base = #eeeeec
|
||||||
|
alternatebase = #e0e0e0
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #d3d7cf
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #d3d7cf
|
||||||
|
highlight = #3087c6
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #8f5902
|
||||||
|
fadedtext = faded
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #eeeeec
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #a78800
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = red
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = blue
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
[Main]
|
||||||
|
name = Tomorrow
|
||||||
|
mode = light
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
credit = Chris Kempson (color theme)
|
||||||
|
url = https://github.com/chriskempson/tomorrow-theme
|
||||||
|
license = MIT License
|
||||||
|
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
||||||
|
|
||||||
|
##
|
||||||
|
# Theme: Tomorrow
|
||||||
|
# Source: https://github.com/chriskempson/tomorrow-theme
|
||||||
|
# Credit: Chris Kempson
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = #ffffff
|
||||||
|
# Current Line = #efefef
|
||||||
|
# Selection = #d6d6d6
|
||||||
|
# Foreground = #4d4d4c
|
||||||
|
# Comment = #8e908c
|
||||||
|
# Red = #c82829
|
||||||
|
# Orange = #f5871f
|
||||||
|
# Yellow = #eab700
|
||||||
|
# Green = #718c00
|
||||||
|
# Aqua = #3e999f
|
||||||
|
# Blue = #4271ae
|
||||||
|
# Purple = #8959a8
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #484848
|
||||||
|
faded = #6c6c6c
|
||||||
|
red = #c82829
|
||||||
|
orange = #f5871f
|
||||||
|
yellow = #eab700
|
||||||
|
green = #718c00
|
||||||
|
cyan = #3e999f
|
||||||
|
blue = #4271ae
|
||||||
|
purple = #8959a8
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #efefef
|
||||||
|
windowtext = #000000
|
||||||
|
base = #ffffff
|
||||||
|
alternatebase = #d6d6d6
|
||||||
|
text = #000000
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #efefef
|
||||||
|
buttontext = #000000
|
||||||
|
brighttext = #efefef
|
||||||
|
highlight = blue
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #5c5c5c
|
||||||
|
fadedtext = faded
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #ffffff
|
||||||
|
text = #4d4d4c
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #b38c00
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = yellow
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = orange
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
[Main]
|
||||||
|
name = Tomorrow Night
|
||||||
|
mode = dark
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
credit = Chris Kempson (color theme)
|
||||||
|
url = https://github.com/chriskempson/tomorrow-theme
|
||||||
|
license = MIT License
|
||||||
|
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
||||||
|
|
||||||
|
##
|
||||||
|
# Theme: Tomorrow Night
|
||||||
|
# Source: https://github.com/chriskempson/tomorrow-theme
|
||||||
|
# Credit: Chris Kempson
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = #1d1f21
|
||||||
|
# Current Line = #282a2e
|
||||||
|
# Selection = #373b41
|
||||||
|
# Foreground = #c5c8c6
|
||||||
|
# Comment = #969896
|
||||||
|
# Red = #cc6666
|
||||||
|
# Orange = #de935f
|
||||||
|
# Yellow = #f0c674
|
||||||
|
# Green = #b5bd68
|
||||||
|
# Aqua = #8abeb7
|
||||||
|
# Blue = #81a2be
|
||||||
|
# Purple = #b294bb
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #c5c8c6
|
||||||
|
faded = #969896
|
||||||
|
red = #cc6666
|
||||||
|
orange = #de935f
|
||||||
|
yellow = #f0c674
|
||||||
|
green = #b5bd68
|
||||||
|
cyan = #8abeb7
|
||||||
|
blue = #81a2be
|
||||||
|
purple = #b294bb
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #282a2e
|
||||||
|
windowtext = default
|
||||||
|
base = #1d1f21
|
||||||
|
alternatebase = #373b41
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #1d1f21
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #1d1f21
|
||||||
|
highlight = #2c98f7
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #a4a4a4
|
||||||
|
fadedtext = #949494
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #1d1f21
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #f0dbb2
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = yellow
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = orange
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
[Main]
|
||||||
|
name = Tomorrow Night Blue
|
||||||
|
mode = dark
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
credit = Chris Kempson (color theme)
|
||||||
|
url = https://github.com/chriskempson/tomorrow-theme
|
||||||
|
license = MIT License
|
||||||
|
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
||||||
|
|
||||||
|
##
|
||||||
|
# Theme: Tomorrow Night Blue
|
||||||
|
# Source: https://github.com/chriskempson/tomorrow-theme
|
||||||
|
# Credit: Chris Kempson
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = #002451
|
||||||
|
# Current Line = #00346e
|
||||||
|
# Selection = #003f8e
|
||||||
|
# Foreground = #ffffff
|
||||||
|
# Comment = #7285b7
|
||||||
|
# Red = #ff9da4
|
||||||
|
# Orange = #ffc58f
|
||||||
|
# Yellow = #ffeead
|
||||||
|
# Green = #d1f1a9
|
||||||
|
# Aqua = #99ffff
|
||||||
|
# Blue = #bbdaff
|
||||||
|
# Purple = #ebbbff
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #ffffff
|
||||||
|
faded = #7285b7
|
||||||
|
red = #ff9da4
|
||||||
|
orange = #ffc58f
|
||||||
|
yellow = #ffeead
|
||||||
|
green = #d1f1a9
|
||||||
|
cyan = #99ffff
|
||||||
|
blue = #bbdaff
|
||||||
|
purple = #ebbbff
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #00346e
|
||||||
|
windowtext = default
|
||||||
|
base = #002451
|
||||||
|
alternatebase = #003f8e
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #002451
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #002451
|
||||||
|
highlight = #2c98f7
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #a4a4a4
|
||||||
|
fadedtext = #949494
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #002451
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #fff4cc
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = yellow
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = orange
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
[Main]
|
||||||
|
name = Tomorrow Night Bright
|
||||||
|
mode = dark
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
credit = Chris Kempson (color theme)
|
||||||
|
url = https://github.com/chriskempson/tomorrow-theme
|
||||||
|
license = MIT License
|
||||||
|
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
||||||
|
|
||||||
|
##
|
||||||
|
# Theme: Tomorrow Night Bright
|
||||||
|
# Source: https://github.com/chriskempson/tomorrow-theme
|
||||||
|
# Credit: Chris Kempson
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = #000000
|
||||||
|
# Current Line = #2a2a2a
|
||||||
|
# Selection = #424242
|
||||||
|
# Foreground = #eaeaea
|
||||||
|
# Comment = #969896
|
||||||
|
# Red = #d54e53
|
||||||
|
# Orange = #e78c45
|
||||||
|
# Yellow = #e7c547
|
||||||
|
# Green = #b9ca4a
|
||||||
|
# Aqua = #70c0b1
|
||||||
|
# Blue = #7aa6da
|
||||||
|
# Purple = #c397d8
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #eaeaea
|
||||||
|
faded = #969896
|
||||||
|
red = #d54e53
|
||||||
|
orange = #e78c45
|
||||||
|
yellow = #e7c547
|
||||||
|
green = #b9ca4a
|
||||||
|
cyan = #70c0b1
|
||||||
|
blue = #7aa6da
|
||||||
|
purple = #c397d8
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #2a2a2a
|
||||||
|
windowtext = default
|
||||||
|
base = #000000
|
||||||
|
alternatebase = #424242
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #000000
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #000000
|
||||||
|
highlight = #2c98f7
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #a4a4a4
|
||||||
|
fadedtext = #949494
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #000000
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #e7d696
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = yellow
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = orange
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
[Main]
|
||||||
|
name = Tomorrow Night Eighties
|
||||||
|
mode = dark
|
||||||
|
author = Veronica Berglyd Olsen (adaptation)
|
||||||
|
credit = Chris Kempson (color theme)
|
||||||
|
url = https://github.com/chriskempson/tomorrow-theme
|
||||||
|
license = MIT License
|
||||||
|
licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.md
|
||||||
|
|
||||||
|
##
|
||||||
|
# Theme: Tomorrow Night Eighties
|
||||||
|
# Source: https://github.com/chriskempson/tomorrow-theme
|
||||||
|
# Credit: Chris Kempson
|
||||||
|
##
|
||||||
|
# Colours:
|
||||||
|
# Background = #2d2d2d
|
||||||
|
# Current Line = #393939
|
||||||
|
# Selection = #515151
|
||||||
|
# Foreground = #cccccc
|
||||||
|
# Comment = #999999
|
||||||
|
# Red = #f2777a
|
||||||
|
# Orange = #f99157
|
||||||
|
# Yellow = #ffcc66
|
||||||
|
# Green = #99cc99
|
||||||
|
# Aqua = #66cccc
|
||||||
|
# Blue = #6699cc
|
||||||
|
# Purple = #cc99cc
|
||||||
|
##
|
||||||
|
|
||||||
|
[Base]
|
||||||
|
default = #cccccc
|
||||||
|
faded = #999999
|
||||||
|
red = #f2777a
|
||||||
|
orange = #f99157
|
||||||
|
yellow = #ffcc66
|
||||||
|
green = #99cc99
|
||||||
|
cyan = #66cccc
|
||||||
|
blue = #6699cc
|
||||||
|
purple = #cc99cc
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
root = blue
|
||||||
|
folder = yellow
|
||||||
|
file = default
|
||||||
|
title = green
|
||||||
|
chapter = red
|
||||||
|
scene = blue
|
||||||
|
note = yellow
|
||||||
|
|
||||||
|
[Palette]
|
||||||
|
window = #393939
|
||||||
|
windowtext = default
|
||||||
|
base = #2d2d2d
|
||||||
|
alternatebase = #515151
|
||||||
|
text = default
|
||||||
|
tooltipbase = #ffffc0
|
||||||
|
tooltiptext = #15150d
|
||||||
|
button = #2d2d2d
|
||||||
|
buttontext = default
|
||||||
|
brighttext = #2d2d2d
|
||||||
|
highlight = #2c98f7
|
||||||
|
highlightedtext = #ffffff
|
||||||
|
link = blue
|
||||||
|
linkvisited = blue
|
||||||
|
|
||||||
|
[GUI]
|
||||||
|
helptext = #a4a4a4
|
||||||
|
fadedtext = #949494
|
||||||
|
errortext = red
|
||||||
|
|
||||||
|
[Syntax]
|
||||||
|
background = #2d2d2d
|
||||||
|
text = default
|
||||||
|
link = blue
|
||||||
|
headertext = blue
|
||||||
|
headertag = blue:160
|
||||||
|
emphasis = orange
|
||||||
|
dialog = green
|
||||||
|
altdialog = yellow
|
||||||
|
note = #ffe6b3
|
||||||
|
hidden = faded
|
||||||
|
shortcode = blue
|
||||||
|
keyword = red
|
||||||
|
tag = purple
|
||||||
|
value = yellow
|
||||||
|
optional = blue
|
||||||
|
spellcheckline = red
|
||||||
|
errorline = green
|
||||||
|
replacetag = cyan
|
||||||
|
modifier = orange
|
||||||
|
texthighlight = yellow:96
|
||||||
@@ -31,6 +31,7 @@ import xml.etree.ElementTree as ET
|
|||||||
|
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Any, Literal, TypeGuard, TypeVar
|
from typing import TYPE_CHECKING, Any, Literal, TypeGuard, TypeVar
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
@@ -676,6 +677,9 @@ def openExternalPath(path: Path) -> bool:
|
|||||||
# Classes
|
# Classes
|
||||||
##
|
##
|
||||||
|
|
||||||
|
_T_Enum = TypeVar("_T_Enum", bound=Enum)
|
||||||
|
|
||||||
|
|
||||||
class NWConfigParser(ConfigParser):
|
class NWConfigParser(ConfigParser):
|
||||||
"""Common: Adapted Config Parser
|
"""Common: Adapted Config Parser
|
||||||
|
|
||||||
@@ -736,3 +740,10 @@ class NWConfigParser(ConfigParser):
|
|||||||
for i in range(min(len(data), len(result))):
|
for i in range(min(len(data), len(result))):
|
||||||
result[i] = checkInt(data[i].strip(), result[i])
|
result[i] = checkInt(data[i].strip(), result[i])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def rdEnum(self, section: str, option: str, default: _T_Enum) -> _T_Enum:
|
||||||
|
"""Read enum value."""
|
||||||
|
if self.has_option(section, option):
|
||||||
|
data = self.get(section, option, fallback="")
|
||||||
|
return type(default).__members__.get(data.upper(), default)
|
||||||
|
return default
|
||||||
|
|||||||
+31
-28
@@ -45,6 +45,7 @@ from novelwriter.common import (
|
|||||||
formatTimeStamp, processDialogSymbols, simplified
|
formatTimeStamp, processDialogSymbols, simplified
|
||||||
)
|
)
|
||||||
from novelwriter.constants import nwFiles, nwHtmlUnicode, nwQuotes, nwUnicode
|
from novelwriter.constants import nwFiles, nwHtmlUnicode, nwQuotes, nwUnicode
|
||||||
|
from novelwriter.enum import nwTheme
|
||||||
from novelwriter.error import formatException, logException
|
from novelwriter.error import formatException, logException
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -55,8 +56,8 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
DEF_GUI = "default"
|
DEF_GUI_DARK = "default_dark"
|
||||||
DEF_SYNTAX = "default_light"
|
DEF_GUI_LIGHT = "default_light"
|
||||||
DEF_ICONS = "material_rounded_normal"
|
DEF_ICONS = "material_rounded_normal"
|
||||||
DEF_TREECOL = "theme"
|
DEF_TREECOL = "theme"
|
||||||
|
|
||||||
@@ -69,22 +70,22 @@ class Config:
|
|||||||
"_manuals", "_nwLangPath", "_qLocale", "_qtLangPath", "_qtTrans", "_recentPaths",
|
"_manuals", "_nwLangPath", "_qLocale", "_qtLangPath", "_qtTrans", "_recentPaths",
|
||||||
"_recentProjects", "_splash", "allowOpenDial", "altDialogClose", "altDialogOpen",
|
"_recentProjects", "_splash", "allowOpenDial", "altDialogClose", "altDialogOpen",
|
||||||
"appHandle", "appName", "askBeforeBackup", "askBeforeExit", "autoSaveDoc", "autoSaveProj",
|
"appHandle", "appName", "askBeforeBackup", "askBeforeExit", "autoSaveDoc", "autoSaveProj",
|
||||||
"autoScroll", "autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "dialogLine",
|
"autoScroll", "autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "darkTheme",
|
||||||
"dialogStyle", "doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash",
|
"dialogLine", "dialogStyle", "doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash",
|
||||||
"doReplaceDots", "doReplaceSQuote", "emphLabels", "fmtApostrophe", "fmtDQuoteClose",
|
"doReplaceDots", "doReplaceSQuote", "emphLabels", "fmtApostrophe", "fmtDQuoteClose",
|
||||||
"fmtDQuoteOpen", "fmtPadAfter", "fmtPadBefore", "fmtPadThin", "fmtSQuoteClose",
|
"fmtDQuoteOpen", "fmtPadAfter", "fmtPadBefore", "fmtPadThin", "fmtSQuoteClose",
|
||||||
"fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", "guiSyntax", "guiTheme",
|
"fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", "hasEnchant", "hideFocusFooter",
|
||||||
"hasEnchant", "hideFocusFooter", "hideHScroll", "hideVScroll", "highlightEmph", "hostName",
|
"hideHScroll", "hideVScroll", "highlightEmph", "hostName", "iconColDocs", "iconColTree",
|
||||||
"iconColDocs", "iconColTree", "iconTheme", "incNotesWCount", "isDebug", "kernelVer",
|
"iconTheme", "incNotesWCount", "isDebug", "kernelVer", "lastNotes", "lightTheme",
|
||||||
"lastNotes", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak", "narratorDialog",
|
"mainPanePos", "mainWinSize", "memInfo", "narratorBreak", "narratorDialog", "nativeFont",
|
||||||
"nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", "outlinePanePos",
|
"osDarwin", "osLinux", "osType", "osUnknown", "osWindows", "outlinePanePos",
|
||||||
"prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop", "searchMatchCap",
|
"prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop", "searchMatchCap",
|
||||||
"searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord", "searchRegEx",
|
"searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord", "searchRegEx",
|
||||||
"searchWord", "showEditToolBar", "showFullPath", "showLineEndings", "showMultiSpaces",
|
"searchWord", "showEditToolBar", "showFullPath", "showLineEndings", "showMultiSpaces",
|
||||||
"showSessionTime", "showTabsNSpaces", "showViewerPanel", "spellLanguage", "stopWhenIdle",
|
"showSessionTime", "showTabsNSpaces", "showViewerPanel", "spellLanguage", "stopWhenIdle",
|
||||||
"tabWidth", "textFont", "textMargin", "textWidth", "useCharCount", "userIdleTime",
|
"tabWidth", "textFont", "textMargin", "textWidth", "themeMode", "useCharCount",
|
||||||
"verPyQtString", "verPyQtValue", "verPyString", "verQtString", "verQtValue",
|
"userIdleTime", "verPyQtString", "verPyQtValue", "verPyString", "verQtString",
|
||||||
"viewComments", "viewPanePos", "viewSynopsis", "welcomeWinSize",
|
"verQtValue", "viewComments", "viewPanePos", "viewSynopsis", "welcomeWinSize",
|
||||||
)
|
)
|
||||||
|
|
||||||
LANG_NW = 1
|
LANG_NW = 1
|
||||||
@@ -153,14 +154,15 @@ class Config:
|
|||||||
|
|
||||||
# General GUI Settings
|
# General GUI Settings
|
||||||
self.guiLocale = self._qLocale.name()
|
self.guiLocale = self._qLocale.name()
|
||||||
self.guiTheme = DEF_GUI # GUI theme
|
self.lightTheme = DEF_GUI_LIGHT # Light GUI theme
|
||||||
self.guiSyntax = DEF_SYNTAX # Syntax theme
|
self.darkTheme = DEF_GUI_DARK # Dark GUI theme
|
||||||
self.guiFont = QFont() # Main GUI font
|
self.themeMode = nwTheme.AUTO # Colour theme mode
|
||||||
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
self.guiFont = QFont() # Main GUI font
|
||||||
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
|
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
||||||
self.lastNotes = "0x0" # The latest release notes that have been shown
|
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
|
||||||
self.nativeFont = True # Use native font dialog
|
self.lastNotes = "0x0" # The latest release notes that have been shown
|
||||||
self.useCharCount = False # Use character count as primary count
|
self.nativeFont = True # Use native font dialog
|
||||||
|
self.useCharCount = False # Use character count as primary count
|
||||||
|
|
||||||
# Icons
|
# Icons
|
||||||
self.iconTheme = DEF_ICONS # Icons theme
|
self.iconTheme = DEF_ICONS # Icons theme
|
||||||
@@ -403,7 +405,7 @@ class Config:
|
|||||||
else:
|
else:
|
||||||
font = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
font = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
||||||
self.guiFont = fontMatcher(font)
|
self.guiFont = fontMatcher(font)
|
||||||
logger.debug("GUI font set to: %s", describeFont(font))
|
logger.debug("Main font set to: %s", describeFont(font))
|
||||||
QApplication.setFont(self.guiFont)
|
QApplication.setFont(self.guiFont)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -551,11 +553,10 @@ class Config:
|
|||||||
self._confPath.mkdir(exist_ok=True)
|
self._confPath.mkdir(exist_ok=True)
|
||||||
self._dataPath.mkdir(exist_ok=True)
|
self._dataPath.mkdir(exist_ok=True)
|
||||||
|
|
||||||
# Also create the syntax, themes and icons folders if possible
|
# Also create the themes and icons folders if possible
|
||||||
if self._dataPath.is_dir():
|
if self._dataPath.is_dir():
|
||||||
(self._dataPath / "cache").mkdir(exist_ok=True)
|
(self._dataPath / "cache").mkdir(exist_ok=True)
|
||||||
(self._dataPath / "icons").mkdir(exist_ok=True)
|
(self._dataPath / "icons").mkdir(exist_ok=True)
|
||||||
(self._dataPath / "syntax").mkdir(exist_ok=True)
|
|
||||||
(self._dataPath / "themes").mkdir(exist_ok=True)
|
(self._dataPath / "themes").mkdir(exist_ok=True)
|
||||||
|
|
||||||
self._recentPaths.loadCache()
|
self._recentPaths.loadCache()
|
||||||
@@ -626,8 +627,9 @@ class Config:
|
|||||||
# Main
|
# Main
|
||||||
sec = "Main"
|
sec = "Main"
|
||||||
self.setGuiFont(conf.rdStr(sec, "font", ""))
|
self.setGuiFont(conf.rdStr(sec, "font", ""))
|
||||||
self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme)
|
self.lightTheme = conf.rdStr(sec, "lighttheme", self.lightTheme)
|
||||||
self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax)
|
self.darkTheme = conf.rdStr(sec, "darktheme", self.darkTheme)
|
||||||
|
self.themeMode = conf.rdEnum(sec, "thememode", self.themeMode)
|
||||||
self.iconTheme = conf.rdStr(sec, "icons", self.iconTheme)
|
self.iconTheme = conf.rdStr(sec, "icons", self.iconTheme)
|
||||||
self.iconColTree = conf.rdStr(sec, "iconcoltree", self.iconColTree)
|
self.iconColTree = conf.rdStr(sec, "iconcoltree", self.iconColTree)
|
||||||
self.iconColDocs = conf.rdBool(sec, "iconcoldocs", self.iconColDocs)
|
self.iconColDocs = conf.rdBool(sec, "iconcoldocs", self.iconColDocs)
|
||||||
@@ -721,7 +723,7 @@ class Config:
|
|||||||
# Check Values
|
# Check Values
|
||||||
# ============
|
# ============
|
||||||
|
|
||||||
self._prepareFont(self.guiFont, "GUI")
|
self._prepareFont(self.guiFont, "main")
|
||||||
self._prepareFont(self.textFont, "document")
|
self._prepareFont(self.textFont, "document")
|
||||||
|
|
||||||
# If we're using straight quotes, disable auto-replace
|
# If we're using straight quotes, disable auto-replace
|
||||||
@@ -751,8 +753,9 @@ class Config:
|
|||||||
|
|
||||||
conf["Main"] = {
|
conf["Main"] = {
|
||||||
"font": self.guiFont.toString(),
|
"font": self.guiFont.toString(),
|
||||||
"theme": str(self.guiTheme),
|
"lighttheme": str(self.lightTheme),
|
||||||
"syntax": str(self.guiSyntax),
|
"darktheme": str(self.darkTheme),
|
||||||
|
"thememode": self.themeMode.name,
|
||||||
"icons": str(self.iconTheme),
|
"icons": str(self.iconTheme),
|
||||||
"iconcoltree": str(self.iconColTree),
|
"iconcoltree": str(self.iconColTree),
|
||||||
"iconcoldocs": str(self.iconColDocs),
|
"iconcoldocs": str(self.iconColDocs),
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ from typing import Final
|
|||||||
from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
||||||
|
|
||||||
from novelwriter.enum import (
|
from novelwriter.enum import (
|
||||||
nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
|
nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape,
|
||||||
|
nwTheme
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -449,10 +450,20 @@ class nwLabels:
|
|||||||
"orange": QT_TRANSLATE_NOOP("Constant", "Orange"),
|
"orange": QT_TRANSLATE_NOOP("Constant", "Orange"),
|
||||||
"yellow": QT_TRANSLATE_NOOP("Constant", "Yellow"),
|
"yellow": QT_TRANSLATE_NOOP("Constant", "Yellow"),
|
||||||
"green": QT_TRANSLATE_NOOP("Constant", "Green"),
|
"green": QT_TRANSLATE_NOOP("Constant", "Green"),
|
||||||
"aqua": QT_TRANSLATE_NOOP("Constant", "Aqua"),
|
"cyan": QT_TRANSLATE_NOOP("Constant", "Cyan"),
|
||||||
"blue": QT_TRANSLATE_NOOP("Constant", "Blue"),
|
"blue": QT_TRANSLATE_NOOP("Constant", "Blue"),
|
||||||
"purple": QT_TRANSLATE_NOOP("Constant", "Purple"),
|
"purple": QT_TRANSLATE_NOOP("Constant", "Purple"),
|
||||||
}
|
}
|
||||||
|
THEME_MODE_ICON: Final[dict[nwTheme, str]] = {
|
||||||
|
nwTheme.AUTO: "theme_auto",
|
||||||
|
nwTheme.LIGHT: "theme_light",
|
||||||
|
nwTheme.DARK: "theme_dark",
|
||||||
|
}
|
||||||
|
THEME_MODE_LABEL: Final[dict[nwTheme, str]] = {
|
||||||
|
nwTheme.AUTO: QT_TRANSLATE_NOOP("Constant", "System Theme"),
|
||||||
|
nwTheme.LIGHT: QT_TRANSLATE_NOOP("Constant", "Light Theme"),
|
||||||
|
nwTheme.DARK: QT_TRANSLATE_NOOP("Constant", "Dark Theme"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class nwHeadFmt:
|
class nwHeadFmt:
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ from PyQt6.QtWidgets import (
|
|||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.common import compact, describeFont, processDialogSymbols, uniqueCompact
|
from novelwriter.common import compact, describeFont, processDialogSymbols, uniqueCompact
|
||||||
from novelwriter.config import DEF_GUI, DEF_ICONS, DEF_SYNTAX, DEF_TREECOL
|
from novelwriter.config import DEF_GUI_DARK, DEF_GUI_LIGHT, DEF_ICONS, DEF_TREECOL
|
||||||
from novelwriter.constants import nwLabels, nwQuotes, nwUnicode, trConst
|
from novelwriter.constants import nwLabels, nwQuotes, nwUnicode, trConst
|
||||||
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
||||||
from novelwriter.extensions.configlayout import NColorLabel, NScrollableForm
|
from novelwriter.extensions.configlayout import NColorLabel, NScrollableForm
|
||||||
@@ -165,22 +165,34 @@ class GuiPreferences(NDialog):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Colour Theme
|
# Colour Theme
|
||||||
self.guiTheme = NComboBox(self)
|
self.lightTheme = NComboBox(self)
|
||||||
self.guiTheme.setMinimumWidth(200)
|
self.lightTheme.setMinimumWidth(200)
|
||||||
for theme, name in SHARED.theme.listThemes():
|
self.darkTheme = NComboBox(self)
|
||||||
self.guiTheme.addItem(name, theme)
|
self.darkTheme.setMinimumWidth(200)
|
||||||
self.guiTheme.setCurrentData(CONFIG.guiTheme, DEF_GUI)
|
for key, theme in SHARED.theme.colourThemes.items():
|
||||||
|
if theme.dark:
|
||||||
|
self.darkTheme.addItem(theme.name, key)
|
||||||
|
else:
|
||||||
|
self.lightTheme.addItem(theme.name, key)
|
||||||
|
|
||||||
|
self.lightTheme.setCurrentData(CONFIG.lightTheme, DEF_GUI_LIGHT)
|
||||||
|
self.darkTheme.setCurrentData(CONFIG.darkTheme, DEF_GUI_DARK)
|
||||||
|
|
||||||
self.mainForm.addRow(
|
self.mainForm.addRow(
|
||||||
self.tr("Colour theme"), self.guiTheme,
|
self.tr("Light colour theme"), self.lightTheme,
|
||||||
|
self.tr("User interface colour theme."), stretch=(3, 2)
|
||||||
|
)
|
||||||
|
self.mainForm.addRow(
|
||||||
|
self.tr("Dark colour theme"), self.darkTheme,
|
||||||
self.tr("User interface colour theme."), stretch=(3, 2)
|
self.tr("User interface colour theme."), stretch=(3, 2)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Icon Theme
|
# Icon Theme
|
||||||
self.iconTheme = NComboBox(self)
|
self.iconTheme = NComboBox(self)
|
||||||
self.iconTheme.setMinimumWidth(200)
|
self.iconTheme.setMinimumWidth(200)
|
||||||
for theme, name in SHARED.theme.iconCache.listThemes():
|
for key, theme in SHARED.theme.iconCache.iconThemes.items():
|
||||||
self.iconTheme.addItem(name, theme)
|
self.iconTheme.addItem(theme.name, key)
|
||||||
|
|
||||||
self.iconTheme.setCurrentData(CONFIG.iconTheme, DEF_ICONS)
|
self.iconTheme.setCurrentData(CONFIG.iconTheme, DEF_ICONS)
|
||||||
|
|
||||||
self.mainForm.addRow(
|
self.mainForm.addRow(
|
||||||
@@ -242,18 +254,6 @@ class GuiPreferences(NDialog):
|
|||||||
self.sidebar.addButton(title, section)
|
self.sidebar.addButton(title, section)
|
||||||
self.mainForm.addGroupLabel(title, section)
|
self.mainForm.addGroupLabel(title, section)
|
||||||
|
|
||||||
# Document Colour Theme
|
|
||||||
self.guiSyntax = NComboBox(self)
|
|
||||||
self.guiSyntax.setMinimumWidth(200)
|
|
||||||
for syntax, name in SHARED.theme.listSyntax():
|
|
||||||
self.guiSyntax.addItem(name, syntax)
|
|
||||||
self.guiSyntax.setCurrentData(CONFIG.guiSyntax, DEF_SYNTAX)
|
|
||||||
|
|
||||||
self.mainForm.addRow(
|
|
||||||
self.tr("Document colour theme"), self.guiSyntax,
|
|
||||||
self.tr("Colour theme for the editor and viewer."), stretch=(3, 2)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Document Font Family
|
# Document Font Family
|
||||||
self.textFont = QLineEdit(self)
|
self.textFont = QLineEdit(self)
|
||||||
self.textFont.setReadOnly(True)
|
self.textFont.setReadOnly(True)
|
||||||
@@ -966,18 +966,23 @@ class GuiPreferences(NDialog):
|
|||||||
|
|
||||||
# Appearance
|
# Appearance
|
||||||
guiLocale = self.guiLocale.currentData()
|
guiLocale = self.guiLocale.currentData()
|
||||||
guiTheme = self.guiTheme.currentData()
|
lightTheme = self.lightTheme.currentData()
|
||||||
|
darkTheme = self.darkTheme.currentData()
|
||||||
iconTheme = self.iconTheme.currentData()
|
iconTheme = self.iconTheme.currentData()
|
||||||
useCharCount = self.useCharCount.isChecked()
|
useCharCount = self.useCharCount.isChecked()
|
||||||
|
|
||||||
updateTheme |= CONFIG.guiTheme != guiTheme
|
updateTheme |= CONFIG.lightTheme != lightTheme
|
||||||
|
updateTheme |= CONFIG.darkTheme != darkTheme
|
||||||
updateTheme |= CONFIG.iconTheme != iconTheme
|
updateTheme |= CONFIG.iconTheme != iconTheme
|
||||||
needsRestart |= CONFIG.guiLocale != guiLocale
|
needsRestart |= CONFIG.guiLocale != guiLocale
|
||||||
needsRestart |= CONFIG.guiFont != self._guiFont
|
needsRestart |= CONFIG.guiFont != self._guiFont
|
||||||
refreshTree |= CONFIG.useCharCount != useCharCount
|
refreshTree |= CONFIG.useCharCount != useCharCount
|
||||||
|
updateSyntax |= CONFIG.lightTheme != lightTheme
|
||||||
|
updateSyntax |= CONFIG.darkTheme != darkTheme
|
||||||
|
|
||||||
CONFIG.guiLocale = guiLocale
|
CONFIG.guiLocale = guiLocale
|
||||||
CONFIG.guiTheme = guiTheme
|
CONFIG.lightTheme = lightTheme
|
||||||
|
CONFIG.darkTheme = darkTheme
|
||||||
CONFIG.iconTheme = iconTheme
|
CONFIG.iconTheme = iconTheme
|
||||||
CONFIG.hideVScroll = self.hideVScroll.isChecked()
|
CONFIG.hideVScroll = self.hideVScroll.isChecked()
|
||||||
CONFIG.hideHScroll = self.hideHScroll.isChecked()
|
CONFIG.hideHScroll = self.hideHScroll.isChecked()
|
||||||
@@ -986,11 +991,6 @@ class GuiPreferences(NDialog):
|
|||||||
CONFIG.setGuiFont(self._guiFont)
|
CONFIG.setGuiFont(self._guiFont)
|
||||||
|
|
||||||
# Document Style
|
# Document Style
|
||||||
guiSyntax = self.guiSyntax.currentData()
|
|
||||||
|
|
||||||
updateSyntax |= CONFIG.guiSyntax != guiSyntax
|
|
||||||
|
|
||||||
CONFIG.guiSyntax = guiSyntax
|
|
||||||
CONFIG.showFullPath = self.showFullPath.isChecked()
|
CONFIG.showFullPath = self.showFullPath.isChecked()
|
||||||
CONFIG.incNotesWCount = self.incNotesWCount.isChecked()
|
CONFIG.incNotesWCount = self.incNotesWCount.isChecked()
|
||||||
CONFIG.setTextFont(self._textFont)
|
CONFIG.setTextFont(self._textFont)
|
||||||
|
|||||||
@@ -156,6 +156,13 @@ class nwFocus(Enum):
|
|||||||
OUTLINE = 3
|
OUTLINE = 3
|
||||||
|
|
||||||
|
|
||||||
|
class nwTheme(Enum):
|
||||||
|
|
||||||
|
AUTO = 0
|
||||||
|
LIGHT = 1
|
||||||
|
DARK = 2
|
||||||
|
|
||||||
|
|
||||||
class nwOutline(Enum):
|
class nwOutline(Enum):
|
||||||
|
|
||||||
TITLE = 0
|
TITLE = 0
|
||||||
|
|||||||
@@ -27,12 +27,13 @@ import logging
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from PyQt6.QtCore import QEvent, QPoint, QSize, pyqtSignal
|
from PyQt6.QtCore import QEvent, QPoint, QSize, pyqtSignal, pyqtSlot
|
||||||
from PyQt6.QtWidgets import QMenu, QVBoxLayout, QWidget
|
from PyQt6.QtWidgets import QMenu, QVBoxLayout, QWidget
|
||||||
|
|
||||||
from novelwriter import SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.common import qtLambda
|
from novelwriter.common import qtLambda
|
||||||
from novelwriter.enum import nwView
|
from novelwriter.constants import nwLabels, trConst
|
||||||
|
from novelwriter.enum import nwTheme, nwView
|
||||||
from novelwriter.extensions.eventfilters import StatusTipFilter
|
from novelwriter.extensions.eventfilters import StatusTipFilter
|
||||||
from novelwriter.extensions.modified import NIconToolButton
|
from novelwriter.extensions.modified import NIconToolButton
|
||||||
from novelwriter.gui.theme import STYLES_BIG_TOOLBUTTON
|
from novelwriter.gui.theme import STYLES_BIG_TOOLBUTTON
|
||||||
@@ -77,9 +78,9 @@ class GuiSideBar(QWidget):
|
|||||||
self.tbOutline.setToolTip("{0} [Ctrl+Shift+T]".format(self.tr("Novel Outline View")))
|
self.tbOutline.setToolTip("{0} [Ctrl+Shift+T]".format(self.tr("Novel Outline View")))
|
||||||
self.tbOutline.clicked.connect(qtLambda(self.requestViewChange.emit, nwView.OUTLINE))
|
self.tbOutline.clicked.connect(qtLambda(self.requestViewChange.emit, nwView.OUTLINE))
|
||||||
|
|
||||||
self.tbBuild = NIconToolButton(self, iSz)
|
self.tbTheme = NIconToolButton(self, iSz)
|
||||||
self.tbBuild.setToolTip("{0} [F5]".format(self.tr("Build Manuscript")))
|
self.tbTheme.setToolTip(self.tr("Switch Colour Theme"))
|
||||||
self.tbBuild.clicked.connect(self.mainGui.showBuildManuscriptDialog)
|
self.tbTheme.clicked.connect(self._cycleColurTheme)
|
||||||
|
|
||||||
self.tbDetails = NIconToolButton(self, iSz)
|
self.tbDetails = NIconToolButton(self, iSz)
|
||||||
self.tbDetails.setToolTip("{0} [Shift+F6]".format(self.tr("Novel Details")))
|
self.tbDetails.setToolTip("{0} [Shift+F6]".format(self.tr("Novel Details")))
|
||||||
@@ -89,6 +90,10 @@ class GuiSideBar(QWidget):
|
|||||||
self.tbStats.setToolTip("{0} [F6]".format(self.tr("Writing Statistics")))
|
self.tbStats.setToolTip("{0} [F6]".format(self.tr("Writing Statistics")))
|
||||||
self.tbStats.clicked.connect(self.mainGui.showWritingStatsDialog)
|
self.tbStats.clicked.connect(self.mainGui.showWritingStatsDialog)
|
||||||
|
|
||||||
|
self.tbBuild = NIconToolButton(self, iSz)
|
||||||
|
self.tbBuild.setToolTip("{0} [F5]".format(self.tr("Build Manuscript")))
|
||||||
|
self.tbBuild.clicked.connect(self.mainGui.showBuildManuscriptDialog)
|
||||||
|
|
||||||
# Settings Menu
|
# Settings Menu
|
||||||
self.tbSettings = NIconToolButton(self, iSz)
|
self.tbSettings = NIconToolButton(self, iSz)
|
||||||
self.tbSettings.setToolTip(self.tr("Settings"))
|
self.tbSettings.setToolTip(self.tr("Settings"))
|
||||||
@@ -111,6 +116,7 @@ class GuiSideBar(QWidget):
|
|||||||
self.outerBox.addStretch(1)
|
self.outerBox.addStretch(1)
|
||||||
self.outerBox.addWidget(self.tbDetails)
|
self.outerBox.addWidget(self.tbDetails)
|
||||||
self.outerBox.addWidget(self.tbStats)
|
self.outerBox.addWidget(self.tbStats)
|
||||||
|
self.outerBox.addWidget(self.tbTheme)
|
||||||
self.outerBox.addWidget(self.tbSettings)
|
self.outerBox.addWidget(self.tbSettings)
|
||||||
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
self.outerBox.setContentsMargins(0, 0, 0, 0)
|
||||||
self.outerBox.setSpacing(6)
|
self.outerBox.setSpacing(6)
|
||||||
@@ -133,6 +139,7 @@ class GuiSideBar(QWidget):
|
|||||||
self.tbBuild.setStyleSheet(buttonStyle)
|
self.tbBuild.setStyleSheet(buttonStyle)
|
||||||
self.tbDetails.setStyleSheet(buttonStyle)
|
self.tbDetails.setStyleSheet(buttonStyle)
|
||||||
self.tbStats.setStyleSheet(buttonStyle)
|
self.tbStats.setStyleSheet(buttonStyle)
|
||||||
|
self.tbTheme.setStyleSheet(buttonStyle)
|
||||||
self.tbSettings.setStyleSheet(buttonStyle)
|
self.tbSettings.setStyleSheet(buttonStyle)
|
||||||
|
|
||||||
self.tbProject.setThemeIcon("sb_project")
|
self.tbProject.setThemeIcon("sb_project")
|
||||||
@@ -144,6 +151,36 @@ class GuiSideBar(QWidget):
|
|||||||
self.tbStats.setThemeIcon("sb_stats")
|
self.tbStats.setThemeIcon("sb_stats")
|
||||||
self.tbSettings.setThemeIcon("settings")
|
self.tbSettings.setThemeIcon("settings")
|
||||||
|
|
||||||
|
self._setThemeModeIcon()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Private Slots
|
||||||
|
##
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def _cycleColurTheme(self) -> None:
|
||||||
|
"""Go to nex colour theme."""
|
||||||
|
match CONFIG.themeMode:
|
||||||
|
case nwTheme.AUTO:
|
||||||
|
CONFIG.themeMode = nwTheme.LIGHT
|
||||||
|
case nwTheme.LIGHT:
|
||||||
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
|
case nwTheme.DARK:
|
||||||
|
CONFIG.themeMode = nwTheme.AUTO
|
||||||
|
self.mainGui.checkThemeUpdate()
|
||||||
|
self._setThemeModeIcon()
|
||||||
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Internal Functions
|
||||||
|
##
|
||||||
|
|
||||||
|
def _setThemeModeIcon(self) -> None:
|
||||||
|
"""Set the theme button icon."""
|
||||||
|
self.tbTheme.setThemeIcon(nwLabels.THEME_MODE_ICON[CONFIG.themeMode])
|
||||||
|
self.tbTheme.setToolTip(trConst(nwLabels.THEME_MODE_LABEL[CONFIG.themeMode]))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -143,9 +143,9 @@ class GuiMainStatus(QStatusBar):
|
|||||||
self.idlePixmap = SHARED.theme.getPixmap("timer_off", (iPx, iPx))
|
self.idlePixmap = SHARED.theme.getPixmap("timer_off", (iPx, iPx))
|
||||||
self.timeIcon.setPixmap(self.timePixmap)
|
self.timeIcon.setPixmap(self.timePixmap)
|
||||||
|
|
||||||
colNone = SHARED.theme.getIconColor("default").darker(150)
|
colNone = SHARED.theme.getBaseColor("default").darker(150)
|
||||||
colSaved = SHARED.theme.getIconColor("green").darker(150)
|
colSaved = SHARED.theme.getBaseColor("green").darker(150)
|
||||||
colUnsaved = SHARED.theme.getIconColor("red").darker(150)
|
colUnsaved = SHARED.theme.getBaseColor("red").darker(150)
|
||||||
self.docIcon.setColors(colNone, colSaved, colUnsaved)
|
self.docIcon.setColors(colNone, colSaved, colUnsaved)
|
||||||
self.projIcon.setColors(colNone, colSaved, colUnsaved)
|
self.projIcon.setColors(colNone, colSaved, colUnsaved)
|
||||||
|
|
||||||
|
|||||||
+334
-319
@@ -26,21 +26,23 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from configparser import ConfigParser
|
||||||
|
from dataclasses import dataclass
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from typing import TYPE_CHECKING, Final
|
from typing import TYPE_CHECKING, Final
|
||||||
|
|
||||||
from PyQt6.QtCore import QSize, Qt
|
from PyQt6.QtCore import QSize, Qt
|
||||||
from PyQt6.QtGui import (
|
from PyQt6.QtGui import (
|
||||||
QColor, QFont, QFontDatabase, QFontMetrics, QIcon, QPainter, QPainterPath,
|
QColor, QFont, QFontDatabase, QFontMetrics, QGuiApplication, QIcon,
|
||||||
QPalette, QPixmap
|
QPainter, QPainterPath, QPalette, QPixmap
|
||||||
)
|
)
|
||||||
from PyQt6.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
from novelwriter import CONFIG
|
from novelwriter import CONFIG
|
||||||
from novelwriter.common import NWConfigParser, minmax
|
from novelwriter.common import checkInt, minmax
|
||||||
from novelwriter.config import DEF_GUI, DEF_ICONS, DEF_SYNTAX
|
from novelwriter.config import DEF_GUI_DARK, DEF_GUI_LIGHT, DEF_ICONS
|
||||||
from novelwriter.constants import nwLabels
|
from novelwriter.constants import nwLabels
|
||||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType, nwTheme
|
||||||
from novelwriter.error import logException
|
from novelwriter.error import logException
|
||||||
from novelwriter.types import QtBlack, QtHexArgb, QtPaintAntiAlias, QtTransparent
|
from novelwriter.types import QtBlack, QtHexArgb, QtPaintAntiAlias, QtTransparent
|
||||||
|
|
||||||
@@ -54,9 +56,18 @@ STYLES_MIN_TOOLBUTTON = "minimalToolButton"
|
|||||||
STYLES_BIG_TOOLBUTTON = "bigToolButton"
|
STYLES_BIG_TOOLBUTTON = "bigToolButton"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ThemeEntry:
|
||||||
|
|
||||||
|
name: str
|
||||||
|
dark: bool
|
||||||
|
path: Path
|
||||||
|
|
||||||
|
|
||||||
class ThemeMeta:
|
class ThemeMeta:
|
||||||
|
|
||||||
name: str = ""
|
name: str = ""
|
||||||
|
mode: str = ""
|
||||||
description: str = ""
|
description: str = ""
|
||||||
author: str = ""
|
author: str = ""
|
||||||
credit: str = ""
|
credit: str = ""
|
||||||
@@ -96,21 +107,20 @@ class GuiTheme:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
"_availSyntax", "_availThemes", "_guiPalette", "_styleSheets", "_syntaxList", "_themeList",
|
"_allThemes", "_currentTheme", "_darkThemes", "_guiPalette", "_lightThemes", "_meta",
|
||||||
"baseButtonHeight", "baseIconHeight", "baseIconSize", "buttonIconSize", "errorText",
|
"_qColors", "_styleSheets", "_svgColors", "_syntaxList", "baseButtonHeight",
|
||||||
"fadedText", "fontPixelSize", "fontPointSize", "getDecoration", "getHeaderDecoration",
|
"baseIconHeight", "baseIconSize", "buttonIconSize", "errorText", "fadedText",
|
||||||
"getHeaderDecorationNarrow", "getIcon", "getIconColor", "getItemIcon", "getPixmap",
|
"fontPixelSize", "fontPointSize", "getDecoration", "getHeaderDecoration",
|
||||||
"getToggleIcon", "guiFont", "guiFontB", "guiFontBU", "guiFontFixed", "guiFontSmall",
|
"getHeaderDecorationNarrow", "getIcon", "getItemIcon", "getPixmap", "getToggleIcon",
|
||||||
"helpText", "iconCache", "isDarkTheme", "syntaxMeta", "syntaxTheme", "textNHeight",
|
"guiFont", "guiFontB", "guiFontBU", "guiFontFixed", "guiFontSmall", "helpText",
|
||||||
"textNWidth", "themeMeta",
|
"iconCache", "isDarkTheme", "syntaxTheme", "textNHeight", "textNWidth",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
|
||||||
self.iconCache = GuiIcons(self)
|
# Theme Objects
|
||||||
|
self.iconCache = GuiIcons(self)
|
||||||
# GUI Theme
|
self.syntaxTheme = SyntaxColors()
|
||||||
self.themeMeta = ThemeMeta()
|
|
||||||
self.isDarkTheme = False
|
self.isDarkTheme = False
|
||||||
|
|
||||||
# Special Text Colours
|
# Special Text Colours
|
||||||
@@ -118,23 +128,19 @@ class GuiTheme:
|
|||||||
self.fadedText = QColor(0, 0, 0)
|
self.fadedText = QColor(0, 0, 0)
|
||||||
self.errorText = QColor(255, 0, 0)
|
self.errorText = QColor(255, 0, 0)
|
||||||
|
|
||||||
# Syntax Theme
|
# Theme Data
|
||||||
self.syntaxMeta = ThemeMeta()
|
self._meta = ThemeMeta()
|
||||||
self.syntaxTheme = SyntaxColors()
|
self._currentTheme = ""
|
||||||
|
|
||||||
# Load Themes
|
|
||||||
self._guiPalette = QPalette()
|
self._guiPalette = QPalette()
|
||||||
self._themeList: list[tuple[str, str]] = []
|
self._allThemes: dict[str, ThemeEntry] = {}
|
||||||
self._syntaxList: list[tuple[str, str]] = []
|
|
||||||
self._availThemes: dict[str, Path] = {}
|
|
||||||
self._availSyntax: dict[str, Path] = {}
|
|
||||||
self._styleSheets: dict[str, str] = {}
|
self._styleSheets: dict[str, str] = {}
|
||||||
|
self._svgColors: dict[str, bytes] = {}
|
||||||
|
self._qColors: dict[str, QColor] = {}
|
||||||
|
|
||||||
# Icon Functions
|
# Icon Functions
|
||||||
self.getIcon = self.iconCache.getIcon
|
self.getIcon = self.iconCache.getIcon
|
||||||
self.getPixmap = self.iconCache.getPixmap
|
self.getPixmap = self.iconCache.getPixmap
|
||||||
self.getItemIcon = self.iconCache.getItemIcon
|
self.getItemIcon = self.iconCache.getItemIcon
|
||||||
self.getIconColor = self.iconCache.getIconColor
|
|
||||||
self.getToggleIcon = self.iconCache.getToggleIcon
|
self.getToggleIcon = self.iconCache.getToggleIcon
|
||||||
self.getDecoration = self.iconCache.getDecoration
|
self.getDecoration = self.iconCache.getDecoration
|
||||||
self.getHeaderDecoration = self.iconCache.getHeaderDecoration
|
self.getHeaderDecoration = self.iconCache.getHeaderDecoration
|
||||||
@@ -178,19 +184,19 @@ class GuiTheme:
|
|||||||
logger.debug("Text 'N' Height: %d", self.textNHeight)
|
logger.debug("Text 'N' Height: %d", self.textNHeight)
|
||||||
logger.debug("Text 'N' Width: %d", self.textNWidth)
|
logger.debug("Text 'N' Width: %d", self.textNWidth)
|
||||||
|
|
||||||
# Process Themes
|
|
||||||
_listConf(self._availSyntax, CONFIG.assetPath("syntax"), ".conf")
|
|
||||||
_listConf(self._availThemes, CONFIG.assetPath("themes"), ".conf")
|
|
||||||
_listConf(self._availSyntax, CONFIG.dataPath("syntax"), ".conf")
|
|
||||||
_listConf(self._availThemes, CONFIG.dataPath("themes"), ".conf")
|
|
||||||
|
|
||||||
self.loadTheme()
|
|
||||||
self.loadSyntax()
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Methods
|
# Properties
|
||||||
|
##
|
||||||
|
|
||||||
|
@property
|
||||||
|
def colourThemes(self) -> dict[str, ThemeEntry]:
|
||||||
|
"""Return a dictionary of all themes."""
|
||||||
|
return self._allThemes
|
||||||
|
|
||||||
|
##
|
||||||
|
# Getters
|
||||||
##
|
##
|
||||||
|
|
||||||
def getTextWidth(self, text: str, font: QFont | None = None) -> int:
|
def getTextWidth(self, text: str, font: QFont | None = None) -> int:
|
||||||
@@ -203,30 +209,105 @@ class GuiTheme:
|
|||||||
qMetrics = QFontMetrics(self.guiFont)
|
qMetrics = QFontMetrics(self.guiFont)
|
||||||
return ceil(qMetrics.boundingRect(text).width())
|
return ceil(qMetrics.boundingRect(text).width())
|
||||||
|
|
||||||
|
def getBaseColor(self, name: str) -> QColor:
|
||||||
|
"""Return a base color."""
|
||||||
|
return QColor(self._qColors.get(name) or QtBlack)
|
||||||
|
|
||||||
|
def getRawBaseColor(self, name: str) -> bytes:
|
||||||
|
"""Return a base color."""
|
||||||
|
return self._svgColors.get(name, self._svgColors.get("default", b"#000000"))
|
||||||
|
|
||||||
##
|
##
|
||||||
# Theme Methods
|
# Theme Methods
|
||||||
##
|
##
|
||||||
|
|
||||||
def loadTheme(self) -> bool:
|
def initThemes(self) -> None:
|
||||||
"""Load the currently specified GUI theme."""
|
"""Initialise themes."""
|
||||||
theme = CONFIG.guiTheme
|
CONFIG.splashMessage("Scanning for colour themes ...")
|
||||||
if theme not in self._availThemes:
|
themes: list[Path] = []
|
||||||
logger.error("Could not find GUI theme '%s'", theme)
|
_listContent(themes, CONFIG.assetPath("themes"), ".conf")
|
||||||
theme = DEF_GUI
|
_listContent(themes, CONFIG.dataPath("themes"), ".conf")
|
||||||
CONFIG.guiTheme = theme
|
self._scanThemes(themes)
|
||||||
|
|
||||||
if not (file := self._availThemes.get(theme)):
|
self.iconCache.initIcons()
|
||||||
|
self.loadTheme()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def isDesktopDarkMode(self) -> bool:
|
||||||
|
"""Check if the desktop is in dark mode."""
|
||||||
|
if CONFIG.verQtValue >= 0x060500 and (hint := QGuiApplication.styleHints()):
|
||||||
|
return hint.colorScheme() == Qt.ColorScheme.Dark
|
||||||
|
|
||||||
|
palette = QPalette()
|
||||||
|
text = palette.windowText().color()
|
||||||
|
window = palette.window().color()
|
||||||
|
return text.lightnessF() > window.lightnessF()
|
||||||
|
|
||||||
|
def parseColor(self, value: str, default: QColor = QtBlack) -> QColor:
|
||||||
|
"""Parse a string as a colour value."""
|
||||||
|
if value in self._qColors:
|
||||||
|
# Named colour
|
||||||
|
return self._qColors[value]
|
||||||
|
elif value.startswith("#") and len(value) == 7:
|
||||||
|
# Assume #RRGGBB
|
||||||
|
return QColor.fromString(value)
|
||||||
|
elif value.startswith("#") and len(value) == 9:
|
||||||
|
# Assume #RRGGBBAA and convert to #AARRGGBB
|
||||||
|
return QColor.fromString(f"#{value[7:9]}{value[1:7]}")
|
||||||
|
elif ":" in value:
|
||||||
|
# Colour name and alpha
|
||||||
|
name, _, alpha = value.partition(":")
|
||||||
|
color = QColor(self._qColors.get(name.strip(), default))
|
||||||
|
color.setAlpha(checkInt(alpha, 255))
|
||||||
|
return color
|
||||||
|
elif "," in value:
|
||||||
|
# Integer red, green, blue, alpha
|
||||||
|
data = value.split(",")
|
||||||
|
result = [0, 0, 0, 255]
|
||||||
|
for i in range(min(len(data), 4)):
|
||||||
|
result[i] = checkInt(data[i].strip(), result[i])
|
||||||
|
return QColor(*result)
|
||||||
|
return default
|
||||||
|
|
||||||
|
def loadTheme(self, force: bool = False) -> bool:
|
||||||
|
"""Load the currently specified GUI theme. The boolean return
|
||||||
|
can be used to determine if the GUI needs refreshing.
|
||||||
|
"""
|
||||||
|
match CONFIG.themeMode:
|
||||||
|
case nwTheme.LIGHT:
|
||||||
|
darkMode = False
|
||||||
|
case nwTheme.DARK:
|
||||||
|
darkMode = True
|
||||||
|
case _:
|
||||||
|
darkMode = self.isDesktopDarkMode()
|
||||||
|
|
||||||
|
theme = CONFIG.darkTheme if darkMode else CONFIG.lightTheme
|
||||||
|
if theme not in self._allThemes:
|
||||||
|
logger.error("Could not find theme '%s'", theme)
|
||||||
|
if darkMode:
|
||||||
|
theme = DEF_GUI_DARK
|
||||||
|
CONFIG.darkTheme = DEF_GUI_DARK
|
||||||
|
else:
|
||||||
|
theme = DEF_GUI_LIGHT
|
||||||
|
CONFIG.lightTheme = DEF_GUI_LIGHT
|
||||||
|
|
||||||
|
if theme == self._currentTheme and not force:
|
||||||
|
logger.info("Theme '%s' is already loaded", theme)
|
||||||
|
return False
|
||||||
|
|
||||||
|
entry = self._allThemes.get(theme)
|
||||||
|
if not entry:
|
||||||
logger.error("Could not load GUI theme")
|
logger.error("Could not load GUI theme")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
CONFIG.splashMessage("Loading GUI theme ...")
|
CONFIG.splashMessage(f"Loading colour theme: {entry.name}")
|
||||||
logger.info("Loading GUI theme '%s'", theme)
|
logger.info("Loading GUI theme '%s'", theme)
|
||||||
parser = NWConfigParser()
|
parser = ConfigParser()
|
||||||
try:
|
try:
|
||||||
with open(file, mode="r", encoding="utf-8") as fo:
|
parser.read(entry.path, encoding="utf-8")
|
||||||
parser.read_file(fo)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error("Could not read file: %s", file)
|
logger.error("Could not read file: %s", entry.path)
|
||||||
logException()
|
logException()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -237,39 +318,40 @@ class GuiTheme:
|
|||||||
sec = "Main"
|
sec = "Main"
|
||||||
meta = ThemeMeta()
|
meta = ThemeMeta()
|
||||||
if parser.has_section(sec):
|
if parser.has_section(sec):
|
||||||
meta.name = parser.rdStr(sec, "name", "")
|
meta.name = parser.get(sec, "name", fallback="")
|
||||||
meta.description = parser.rdStr(sec, "description", "N/A")
|
meta.mode = parser.get(sec, "mode", fallback="light")
|
||||||
meta.author = parser.rdStr(sec, "author", "N/A")
|
meta.description = parser.get(sec, "description", fallback="N/A")
|
||||||
meta.credit = parser.rdStr(sec, "credit", "N/A")
|
meta.author = parser.get(sec, "author", fallback="N/A")
|
||||||
meta.url = parser.rdStr(sec, "url", "")
|
meta.credit = parser.get(sec, "credit", fallback="N/A")
|
||||||
meta.license = parser.rdStr(sec, "license", "N/A")
|
meta.url = parser.get(sec, "url", fallback="")
|
||||||
meta.licenseUrl = parser.rdStr(sec, "licenseurl", "")
|
meta.license = parser.get(sec, "license", fallback="N/A")
|
||||||
|
meta.licenseUrl = parser.get(sec, "licenseurl", fallback="")
|
||||||
|
|
||||||
self.themeMeta = meta
|
self._meta = meta
|
||||||
|
|
||||||
# Icons
|
# Base
|
||||||
sec = "Icons"
|
sec = "Base"
|
||||||
if parser.has_section(sec):
|
if parser.has_section(sec):
|
||||||
self.iconCache.setIconColor("default", self._parseColor(parser, sec, "default"))
|
self._setBaseColor("default", self._readColor(parser, sec, "default"))
|
||||||
self.iconCache.setIconColor("faded", self._parseColor(parser, sec, "faded"))
|
self._setBaseColor("faded", self._readColor(parser, sec, "faded"))
|
||||||
self.iconCache.setIconColor("red", self._parseColor(parser, sec, "red"))
|
self._setBaseColor("red", self._readColor(parser, sec, "red"))
|
||||||
self.iconCache.setIconColor("orange", self._parseColor(parser, sec, "orange"))
|
self._setBaseColor("orange", self._readColor(parser, sec, "orange"))
|
||||||
self.iconCache.setIconColor("yellow", self._parseColor(parser, sec, "yellow"))
|
self._setBaseColor("yellow", self._readColor(parser, sec, "yellow"))
|
||||||
self.iconCache.setIconColor("green", self._parseColor(parser, sec, "green"))
|
self._setBaseColor("green", self._readColor(parser, sec, "green"))
|
||||||
self.iconCache.setIconColor("aqua", self._parseColor(parser, sec, "aqua"))
|
self._setBaseColor("cyan", self._readColor(parser, sec, "cyan"))
|
||||||
self.iconCache.setIconColor("blue", self._parseColor(parser, sec, "blue"))
|
self._setBaseColor("blue", self._readColor(parser, sec, "blue"))
|
||||||
self.iconCache.setIconColor("purple", self._parseColor(parser, sec, "purple"))
|
self._setBaseColor("purple", self._readColor(parser, sec, "purple"))
|
||||||
|
|
||||||
# Project
|
# Project
|
||||||
sec = "Project"
|
sec = "Project"
|
||||||
if parser.has_section(sec):
|
if parser.has_section(sec):
|
||||||
self.iconCache.setIconColor("root", self._parseColor(parser, sec, "root"))
|
self._setBaseColor("root", self._readColor(parser, sec, "root"))
|
||||||
self.iconCache.setIconColor("folder", self._parseColor(parser, sec, "folder"))
|
self._setBaseColor("folder", self._readColor(parser, sec, "folder"))
|
||||||
self.iconCache.setIconColor("file", self._parseColor(parser, sec, "file"))
|
self._setBaseColor("file", self._readColor(parser, sec, "file"))
|
||||||
self.iconCache.setIconColor("title", self._parseColor(parser, sec, "title"))
|
self._setBaseColor("title", self._readColor(parser, sec, "title"))
|
||||||
self.iconCache.setIconColor("chapter", self._parseColor(parser, sec, "chapter"))
|
self._setBaseColor("chapter", self._readColor(parser, sec, "chapter"))
|
||||||
self.iconCache.setIconColor("scene", self._parseColor(parser, sec, "scene"))
|
self._setBaseColor("scene", self._readColor(parser, sec, "scene"))
|
||||||
self.iconCache.setIconColor("note", self._parseColor(parser, sec, "note"))
|
self._setBaseColor("note", self._readColor(parser, sec, "note"))
|
||||||
|
|
||||||
# Palette
|
# Palette
|
||||||
sec = "Palette"
|
sec = "Palette"
|
||||||
@@ -292,16 +374,40 @@ class GuiTheme:
|
|||||||
# GUI
|
# GUI
|
||||||
sec = "GUI"
|
sec = "GUI"
|
||||||
if parser.has_section(sec):
|
if parser.has_section(sec):
|
||||||
self.helpText = self._parseColor(parser, sec, "helptext")
|
self.helpText = self._readColor(parser, sec, "helptext")
|
||||||
self.fadedText = self._parseColor(parser, sec, "fadedtext")
|
self.fadedText = self._readColor(parser, sec, "fadedtext")
|
||||||
self.errorText = self._parseColor(parser, sec, "errortext")
|
self.errorText = self._readColor(parser, sec, "errortext")
|
||||||
|
|
||||||
|
# Syntax
|
||||||
|
sec = "Syntax"
|
||||||
|
self.syntaxTheme = SyntaxColors()
|
||||||
|
if parser.has_section(sec):
|
||||||
|
self.syntaxTheme.back = self._readColor(parser, sec, "background")
|
||||||
|
self.syntaxTheme.text = self._readColor(parser, sec, "text")
|
||||||
|
self.syntaxTheme.link = self._readColor(parser, sec, "link")
|
||||||
|
self.syntaxTheme.head = self._readColor(parser, sec, "headertext")
|
||||||
|
self.syntaxTheme.headH = self._readColor(parser, sec, "headertag")
|
||||||
|
self.syntaxTheme.emph = self._readColor(parser, sec, "emphasis")
|
||||||
|
self.syntaxTheme.dialN = self._readColor(parser, sec, "dialog")
|
||||||
|
self.syntaxTheme.dialA = self._readColor(parser, sec, "altdialog")
|
||||||
|
self.syntaxTheme.hidden = self._readColor(parser, sec, "hidden")
|
||||||
|
self.syntaxTheme.note = self._readColor(parser, sec, "note")
|
||||||
|
self.syntaxTheme.code = self._readColor(parser, sec, "shortcode")
|
||||||
|
self.syntaxTheme.key = self._readColor(parser, sec, "keyword")
|
||||||
|
self.syntaxTheme.tag = self._readColor(parser, sec, "tag")
|
||||||
|
self.syntaxTheme.val = self._readColor(parser, sec, "value")
|
||||||
|
self.syntaxTheme.opt = self._readColor(parser, sec, "optional")
|
||||||
|
self.syntaxTheme.spell = self._readColor(parser, sec, "spellcheckline")
|
||||||
|
self.syntaxTheme.error = self._readColor(parser, sec, "errorline")
|
||||||
|
self.syntaxTheme.repTag = self._readColor(parser, sec, "replacetag")
|
||||||
|
self.syntaxTheme.mod = self._readColor(parser, sec, "modifier")
|
||||||
|
self.syntaxTheme.mark = self._readColor(parser, sec, "texthighlight")
|
||||||
|
|
||||||
# Update Dependant Colours
|
# Update Dependant Colours
|
||||||
# Based on: https://github.com/qt/qtbase/blob/dev/src/gui/kernel/qplatformtheme.cpp
|
# Based on: https://github.com/qt/qtbase/blob/dev/src/gui/kernel/qplatformtheme.cpp
|
||||||
text = self._guiPalette.text().color()
|
text = self._guiPalette.text().color()
|
||||||
window = self._guiPalette.window().color()
|
window = self._guiPalette.window().color()
|
||||||
highlight = self._guiPalette.highlight().color()
|
highlight = self._guiPalette.highlight().color()
|
||||||
isDark = text.lightnessF() > window.lightnessF()
|
|
||||||
|
|
||||||
QtColActive = QPalette.ColorGroup.Active
|
QtColActive = QPalette.ColorGroup.Active
|
||||||
QtColInactive = QPalette.ColorGroup.Inactive
|
QtColInactive = QPalette.ColorGroup.Inactive
|
||||||
@@ -321,8 +427,8 @@ class GuiTheme:
|
|||||||
darkOff = dark.darker(150)
|
darkOff = dark.darker(150)
|
||||||
shadowOff = ref.darker(150)
|
shadowOff = ref.darker(150)
|
||||||
|
|
||||||
grey = QColor(120, 120, 120) if isDark else QColor(140, 140, 140)
|
grey = QColor(120, 120, 120) if darkMode else QColor(140, 140, 140)
|
||||||
dimmed = QColor(130, 130, 130) if isDark else QColor(190, 190, 190)
|
dimmed = QColor(130, 130, 130) if darkMode else QColor(190, 190, 190)
|
||||||
|
|
||||||
placeholder = QColor(text)
|
placeholder = QColor(text)
|
||||||
placeholder.setAlpha(128)
|
placeholder.setAlpha(128)
|
||||||
@@ -351,117 +457,30 @@ class GuiTheme:
|
|||||||
self._guiPalette.setBrush(QtColInactive, QPalette.ColorRole.Accent, highlight)
|
self._guiPalette.setBrush(QtColInactive, QPalette.ColorRole.Accent, highlight)
|
||||||
self._guiPalette.setBrush(QtColDisabled, QPalette.ColorRole.Accent, grey)
|
self._guiPalette.setBrush(QtColDisabled, QPalette.ColorRole.Accent, grey)
|
||||||
|
|
||||||
|
# Set project override colours
|
||||||
|
if (override := CONFIG.iconColTree) != "theme":
|
||||||
|
color = self._qColors.get(override, QtBlack)
|
||||||
|
self._setBaseColor("root", color)
|
||||||
|
self._setBaseColor("folder", color)
|
||||||
|
if not CONFIG.iconColDocs:
|
||||||
|
self._setBaseColor("file", color)
|
||||||
|
self._setBaseColor("title", color)
|
||||||
|
self._setBaseColor("chapter", color)
|
||||||
|
self._setBaseColor("scene", color)
|
||||||
|
self._setBaseColor("note", color)
|
||||||
|
|
||||||
|
self.isDarkTheme = darkMode
|
||||||
|
self._currentTheme = theme
|
||||||
|
|
||||||
# Load icons after the theme is parsed
|
# Load icons after the theme is parsed
|
||||||
self.iconCache.loadTheme(CONFIG.iconTheme)
|
self.iconCache.loadTheme(CONFIG.iconTheme)
|
||||||
|
|
||||||
# Finalise
|
# Finalise
|
||||||
self.isDarkTheme = isDark
|
|
||||||
QApplication.setPalette(self._guiPalette)
|
QApplication.setPalette(self._guiPalette)
|
||||||
self._buildStyleSheets(self._guiPalette)
|
self._buildStyleSheets(self._guiPalette)
|
||||||
|
|
||||||
CONFIG.splashMessage(f"Loaded GUI theme: {meta.name}")
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def loadSyntax(self) -> bool:
|
|
||||||
"""Load the currently specified syntax highlighter theme."""
|
|
||||||
theme = CONFIG.guiSyntax
|
|
||||||
if theme not in self._availSyntax:
|
|
||||||
logger.error("Could not find syntax theme '%s'", theme)
|
|
||||||
theme = DEF_SYNTAX
|
|
||||||
CONFIG.guiSyntax = theme
|
|
||||||
|
|
||||||
if not (file := self._availSyntax.get(theme)):
|
|
||||||
logger.error("Could not load syntax theme")
|
|
||||||
return False
|
|
||||||
|
|
||||||
CONFIG.splashMessage("Loading syntax theme ...")
|
|
||||||
logger.info("Loading syntax theme '%s'", theme)
|
|
||||||
parser = NWConfigParser()
|
|
||||||
try:
|
|
||||||
with open(file, mode="r", encoding="utf-8") as fo:
|
|
||||||
parser.read_file(fo)
|
|
||||||
except Exception:
|
|
||||||
logger.error("Could not read file: %s", file)
|
|
||||||
logException()
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Main
|
|
||||||
sec = "Main"
|
|
||||||
meta = ThemeMeta()
|
|
||||||
if parser.has_section(sec):
|
|
||||||
meta.name = parser.rdStr(sec, "name", "")
|
|
||||||
meta.description = parser.rdStr(sec, "description", "N/A")
|
|
||||||
meta.author = parser.rdStr(sec, "author", "N/A")
|
|
||||||
meta.credit = parser.rdStr(sec, "credit", "N/A")
|
|
||||||
meta.url = parser.rdStr(sec, "url", "")
|
|
||||||
meta.license = parser.rdStr(sec, "license", "N/A")
|
|
||||||
meta.licenseUrl = parser.rdStr(sec, "licenseurl", "")
|
|
||||||
|
|
||||||
# Syntax
|
|
||||||
sec = "Syntax"
|
|
||||||
syntax = SyntaxColors()
|
|
||||||
if parser.has_section(sec):
|
|
||||||
syntax.back = self._parseColor(parser, sec, "background")
|
|
||||||
syntax.text = self._parseColor(parser, sec, "text")
|
|
||||||
syntax.link = self._parseColor(parser, sec, "link")
|
|
||||||
syntax.head = self._parseColor(parser, sec, "headertext")
|
|
||||||
syntax.headH = self._parseColor(parser, sec, "headertag")
|
|
||||||
syntax.emph = self._parseColor(parser, sec, "emphasis")
|
|
||||||
syntax.dialN = self._parseColor(parser, sec, "dialog")
|
|
||||||
syntax.dialA = self._parseColor(parser, sec, "altdialog")
|
|
||||||
syntax.hidden = self._parseColor(parser, sec, "hidden")
|
|
||||||
syntax.note = self._parseColor(parser, sec, "note")
|
|
||||||
syntax.code = self._parseColor(parser, sec, "shortcode")
|
|
||||||
syntax.key = self._parseColor(parser, sec, "keyword")
|
|
||||||
syntax.tag = self._parseColor(parser, sec, "tag")
|
|
||||||
syntax.val = self._parseColor(parser, sec, "value")
|
|
||||||
syntax.opt = self._parseColor(parser, sec, "optional")
|
|
||||||
syntax.spell = self._parseColor(parser, sec, "spellcheckline")
|
|
||||||
syntax.error = self._parseColor(parser, sec, "errorline")
|
|
||||||
syntax.repTag = self._parseColor(parser, sec, "replacetag")
|
|
||||||
syntax.mod = self._parseColor(parser, sec, "modifier")
|
|
||||||
syntax.mark = self._parseColor(parser, sec, "texthighlight")
|
|
||||||
|
|
||||||
CONFIG.splashMessage(f"Loaded syntax theme: {meta.name}")
|
|
||||||
|
|
||||||
self.syntaxMeta = meta
|
|
||||||
self.syntaxTheme = syntax
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def listThemes(self) -> list[tuple[str, str]]:
|
|
||||||
"""Scan the GUI themes folder and list all themes."""
|
|
||||||
if self._themeList:
|
|
||||||
return self._themeList
|
|
||||||
|
|
||||||
themes = []
|
|
||||||
parser = NWConfigParser()
|
|
||||||
for key, path in self._availThemes.items():
|
|
||||||
logger.debug("Checking theme config '%s'", key)
|
|
||||||
if name := _loadInternalName(parser, path):
|
|
||||||
themes.append((key, name))
|
|
||||||
|
|
||||||
self._themeList = sorted(themes, key=_sortTheme)
|
|
||||||
|
|
||||||
return self._themeList
|
|
||||||
|
|
||||||
def listSyntax(self) -> list[tuple[str, str]]:
|
|
||||||
"""Scan the syntax themes folder and list all themes."""
|
|
||||||
if self._syntaxList:
|
|
||||||
return self._syntaxList
|
|
||||||
|
|
||||||
themes = []
|
|
||||||
parser = NWConfigParser()
|
|
||||||
for key, path in self._availSyntax.items():
|
|
||||||
logger.debug("Checking theme syntax '%s'", key)
|
|
||||||
if name := _loadInternalName(parser, path):
|
|
||||||
themes.append((key, name))
|
|
||||||
|
|
||||||
self._syntaxList = sorted(themes, key=_sortTheme)
|
|
||||||
|
|
||||||
return self._syntaxList
|
|
||||||
|
|
||||||
def getStyleSheet(self, name: str) -> str:
|
def getStyleSheet(self, name: str) -> str:
|
||||||
"""Load a standard style sheet."""
|
"""Load a standard style sheet."""
|
||||||
return self._styleSheets.get(name, "")
|
return self._styleSheets.get(name, "")
|
||||||
@@ -470,22 +489,26 @@ class GuiTheme:
|
|||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
|
|
||||||
|
def _setBaseColor(self, key: str, color: QColor) -> None:
|
||||||
|
"""Set the colour for a named colour."""
|
||||||
|
self._qColors[key] = QColor(color)
|
||||||
|
self._svgColors[key] = color.name(QColor.NameFormat.HexRgb).encode("utf-8")
|
||||||
|
return
|
||||||
|
|
||||||
def _resetTheme(self) -> None:
|
def _resetTheme(self) -> None:
|
||||||
"""Reset GUI colours to default values."""
|
"""Reset GUI colours to default values."""
|
||||||
palette = QPalette()
|
palette = QPalette()
|
||||||
|
isDark = self.isDesktopDarkMode()
|
||||||
text = palette.color(QPalette.ColorRole.Text)
|
|
||||||
window = palette.color(QPalette.ColorRole.Window)
|
|
||||||
isDark = text.lightnessF() > window.lightnessF()
|
|
||||||
|
|
||||||
# Reset GUI Palette
|
# Reset GUI Palette
|
||||||
|
default = palette.color(QPalette.ColorRole.Text)
|
||||||
faded = QColor(128, 128, 128)
|
faded = QColor(128, 128, 128)
|
||||||
dimmed = QColor(130, 130, 130) if isDark else QColor(190, 190, 190)
|
dimmed = QColor(130, 130, 130) if isDark else QColor(190, 190, 190)
|
||||||
red = QColor(242, 119, 122) if isDark else QColor(240, 40, 41)
|
red = QColor(242, 119, 122) if isDark else QColor(240, 40, 41)
|
||||||
orange = QColor(249, 145, 57) if isDark else QColor(245, 135, 31)
|
orange = QColor(249, 145, 57) if isDark else QColor(245, 135, 31)
|
||||||
yellow = QColor(255, 204, 102) if isDark else QColor(234, 183, 0)
|
yellow = QColor(255, 204, 102) if isDark else QColor(234, 183, 0)
|
||||||
green = QColor(153, 204, 153) if isDark else QColor(113, 140, 0)
|
green = QColor(153, 204, 153) if isDark else QColor(113, 140, 0)
|
||||||
aqua = QColor(102, 204, 204) if isDark else QColor(62, 153, 159)
|
cyan = QColor(102, 204, 204) if isDark else QColor(62, 153, 159)
|
||||||
blue = QColor(102, 153, 204) if isDark else QColor(66, 113, 174)
|
blue = QColor(102, 153, 204) if isDark else QColor(66, 113, 174)
|
||||||
purple = QColor(204, 153, 204) if isDark else QColor(137, 89, 168)
|
purple = QColor(204, 153, 204) if isDark else QColor(137, 89, 168)
|
||||||
|
|
||||||
@@ -496,37 +519,38 @@ class GuiTheme:
|
|||||||
|
|
||||||
self._guiPalette = palette
|
self._guiPalette = palette
|
||||||
|
|
||||||
# Reset Icons
|
# Reset Base Colours and Icons
|
||||||
icons = self.iconCache
|
self.iconCache.clear()
|
||||||
icons.clear()
|
self._svgColors = {}
|
||||||
icons.setIconColor("default", text)
|
self._qColors = {}
|
||||||
icons.setIconColor("faded", faded)
|
self._setBaseColor("default", default)
|
||||||
icons.setIconColor("red", red)
|
self._setBaseColor("faded", faded)
|
||||||
icons.setIconColor("orange", orange)
|
self._setBaseColor("red", red)
|
||||||
icons.setIconColor("yellow", yellow)
|
self._setBaseColor("orange", orange)
|
||||||
icons.setIconColor("green", green)
|
self._setBaseColor("yellow", yellow)
|
||||||
icons.setIconColor("aqua", aqua)
|
self._setBaseColor("green", green)
|
||||||
icons.setIconColor("blue", blue)
|
self._setBaseColor("cyan", cyan)
|
||||||
icons.setIconColor("purple", purple)
|
self._setBaseColor("blue", blue)
|
||||||
icons.setIconColor("root", blue)
|
self._setBaseColor("purple", purple)
|
||||||
icons.setIconColor("folder", yellow)
|
self._setBaseColor("root", blue)
|
||||||
icons.setIconColor("file", text)
|
self._setBaseColor("folder", yellow)
|
||||||
icons.setIconColor("title", green)
|
self._setBaseColor("file", default)
|
||||||
icons.setIconColor("chapter", red)
|
self._setBaseColor("title", green)
|
||||||
icons.setIconColor("scene", blue)
|
self._setBaseColor("chapter", red)
|
||||||
icons.setIconColor("note", yellow)
|
self._setBaseColor("scene", blue)
|
||||||
|
self._setBaseColor("note", yellow)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _parseColor(self, parser: NWConfigParser, section: str, name: str) -> QColor:
|
def _readColor(self, parser: ConfigParser, section: str, name: str) -> QColor:
|
||||||
"""Parse a colour value from a config string."""
|
"""Parse a colour value from a config string."""
|
||||||
return QColor(*parser.rdIntList(section, name, [0, 0, 0, 255]))
|
return self.parseColor(parser.get(section, name, fallback="default"))
|
||||||
|
|
||||||
def _setPalette(
|
def _setPalette(
|
||||||
self, parser: NWConfigParser, section: str, name: str, value: QPalette.ColorRole
|
self, parser: ConfigParser, section: str, name: str, value: QPalette.ColorRole
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set a palette colour value from a config string."""
|
"""Set a palette colour value from a config string."""
|
||||||
self._guiPalette.setBrush(value, self._parseColor(parser, section, name))
|
self._guiPalette.setBrush(value, self._readColor(parser, section, name))
|
||||||
return
|
return
|
||||||
|
|
||||||
def _buildStyleSheets(self, palette: QPalette) -> None:
|
def _buildStyleSheets(self, palette: QPalette) -> None:
|
||||||
@@ -561,6 +585,35 @@ class GuiTheme:
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _scanThemes(self, files: list[Path]) -> None:
|
||||||
|
"""Scan the GUI themes folder and list all themes."""
|
||||||
|
parser = ConfigParser()
|
||||||
|
data: dict[str, tuple[str, str, bool, Path]] = {}
|
||||||
|
keys = []
|
||||||
|
for file in files:
|
||||||
|
try:
|
||||||
|
parser.clear()
|
||||||
|
parser.read(file, encoding="utf-8")
|
||||||
|
name = parser.get("Main", "name", fallback="")
|
||||||
|
dark = parser.get("Main", "mode", fallback="light").lower() == "dark"
|
||||||
|
if name:
|
||||||
|
key = file.stem
|
||||||
|
prefix = "*" if key.startswith("default") else ""
|
||||||
|
lookup = f"{prefix}{name} {key}"
|
||||||
|
keys.append(lookup)
|
||||||
|
data[lookup] = (file.stem, name, dark, file)
|
||||||
|
except Exception: # noqa: PERF203
|
||||||
|
logger.error("Could not read file: %s", file)
|
||||||
|
logException()
|
||||||
|
|
||||||
|
self._allThemes = {}
|
||||||
|
for lookup in sorted(keys):
|
||||||
|
key, name, dark, item = data[lookup]
|
||||||
|
logger.debug("Checking theme config '%s'", key)
|
||||||
|
self._allThemes[key] = ThemeEntry(name, dark, item)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class GuiIcons:
|
class GuiIcons:
|
||||||
"""The icon class manages the content of the assets/icons folder,
|
"""The icon class manages the content of the assets/icons folder,
|
||||||
@@ -572,9 +625,8 @@ class GuiIcons:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
"_availThemes", "_headerDec", "_headerDecNarrow", "_noIcon",
|
"_allThemes", "_headerDec", "_headerDecNarrow", "_meta",
|
||||||
"_qColors", "_qIcons", "_svgColors", "_svgData", "_themeList",
|
"_noIcon", "_qIcons", "_svgData", "_theme",
|
||||||
"mainTheme", "themeMeta",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
TOGGLE_ICON_KEYS: Final[dict[str, tuple[str, str]]] = {
|
TOGGLE_ICON_KEYS: Final[dict[str, tuple[str, str]]] = {
|
||||||
@@ -588,63 +640,72 @@ class GuiIcons:
|
|||||||
|
|
||||||
def __init__(self, mainTheme: GuiTheme) -> None:
|
def __init__(self, mainTheme: GuiTheme) -> None:
|
||||||
|
|
||||||
self.mainTheme = mainTheme
|
self._theme = mainTheme
|
||||||
self.themeMeta = ThemeMeta()
|
self._meta = ThemeMeta()
|
||||||
|
|
||||||
# Storage
|
# Storage
|
||||||
|
self._allThemes: dict[str, ThemeEntry] = {}
|
||||||
self._svgData: dict[str, bytes] = {}
|
self._svgData: dict[str, bytes] = {}
|
||||||
self._svgColors: dict[str, bytes] = {}
|
|
||||||
self._qColors: dict[str, QColor] = {}
|
|
||||||
self._qIcons: dict[str, QIcon] = {}
|
self._qIcons: dict[str, QIcon] = {}
|
||||||
self._headerDec: list[QPixmap] = []
|
self._headerDec: list[QPixmap] = []
|
||||||
self._headerDecNarrow: list[QPixmap] = []
|
self._headerDecNarrow: list[QPixmap] = []
|
||||||
|
|
||||||
# Icon Theme Path
|
|
||||||
self._availThemes: dict[str, Path] = {}
|
|
||||||
self._themeList: list[tuple[str, str]] = []
|
|
||||||
|
|
||||||
# None Icon
|
# None Icon
|
||||||
self._noIcon = QIcon(str(CONFIG.assetPath("icons") / "none.svg"))
|
self._noIcon = QIcon(str(CONFIG.assetPath("icons") / "none.svg"))
|
||||||
|
|
||||||
_listConf(self._availThemes, CONFIG.assetPath("icons"), ".icons")
|
|
||||||
_listConf(self._availThemes, CONFIG.dataPath("icons"), ".icons")
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def clear(self) -> None:
|
def clear(self) -> None:
|
||||||
"""Clear the icon cache."""
|
"""Clear the icon cache."""
|
||||||
self._svgData = {}
|
self._svgData = {}
|
||||||
self._svgColors = {}
|
|
||||||
self._qColors = {}
|
|
||||||
self._qIcons = {}
|
self._qIcons = {}
|
||||||
self._headerDec = []
|
self._headerDec = []
|
||||||
self._headerDecNarrow = []
|
self._headerDecNarrow = []
|
||||||
self.themeMeta = ThemeMeta()
|
self._meta = ThemeMeta()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Properties
|
||||||
|
##
|
||||||
|
|
||||||
|
@property
|
||||||
|
def iconThemes(self) -> dict[str, ThemeEntry]:
|
||||||
|
"""Return a dictionary of all icon themes."""
|
||||||
|
return self._allThemes
|
||||||
|
|
||||||
##
|
##
|
||||||
# Actions
|
# Actions
|
||||||
##
|
##
|
||||||
|
|
||||||
def loadTheme(self, theme: str) -> bool:
|
def initIcons(self) -> None:
|
||||||
|
"""Initialise icons."""
|
||||||
|
CONFIG.splashMessage("Scanning for icon themes ...")
|
||||||
|
icons: list[Path] = []
|
||||||
|
_listContent(icons, CONFIG.assetPath("icons"), ".icons")
|
||||||
|
_listContent(icons, CONFIG.dataPath("icons"), ".icons")
|
||||||
|
self._scanThemes(icons)
|
||||||
|
return
|
||||||
|
|
||||||
|
def loadTheme(self, theme: str) -> None:
|
||||||
"""Update the theme map. This is more of an init, since many of
|
"""Update the theme map. This is more of an init, since many of
|
||||||
the GUI icons cannot really be replaced without writing specific
|
the GUI icons cannot really be replaced without writing specific
|
||||||
update functions for the classes where they're used.
|
update functions for the classes where they're used.
|
||||||
"""
|
"""
|
||||||
if theme not in self._availThemes:
|
if theme not in self._allThemes:
|
||||||
logger.error("Could not find icon theme '%s'", theme)
|
logger.error("Could not find icon theme '%s'", theme)
|
||||||
theme = DEF_ICONS
|
theme = DEF_ICONS
|
||||||
CONFIG.iconTheme = theme
|
CONFIG.iconTheme = theme
|
||||||
|
|
||||||
if not (file := self._availThemes.get(theme)):
|
entry = self._allThemes.get(theme)
|
||||||
|
if not entry:
|
||||||
logger.error("Could not load icon theme")
|
logger.error("Could not load icon theme")
|
||||||
return False
|
return
|
||||||
|
|
||||||
CONFIG.splashMessage("Loading icon theme ...")
|
CONFIG.splashMessage(f"Loading icon theme: {entry.name}")
|
||||||
logger.info("Loading icon theme '%s'", theme)
|
logger.info("Loading icon theme '%s'", theme)
|
||||||
try:
|
try:
|
||||||
meta = ThemeMeta()
|
meta = ThemeMeta()
|
||||||
with open(file, mode="r", encoding="utf-8") as icons:
|
with open(entry.path, mode="r", encoding="utf-8") as icons:
|
||||||
for icon in icons:
|
for icon in icons:
|
||||||
bits = icon.partition("=")
|
bits = icon.partition("=")
|
||||||
key = bits[0].strip()
|
key = bits[0].strip()
|
||||||
@@ -658,47 +719,23 @@ class GuiIcons:
|
|||||||
meta.author = value
|
meta.author = value
|
||||||
elif key == "meta:license":
|
elif key == "meta:license":
|
||||||
meta.license = value
|
meta.license = value
|
||||||
self.themeMeta = meta
|
self._meta = meta
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error("Could not read file: %s", file)
|
logger.error("Could not read file: %s", entry.path)
|
||||||
logException()
|
logException()
|
||||||
return False
|
return
|
||||||
|
|
||||||
CONFIG.splashMessage(f"Loaded icon theme: {meta.name}")
|
|
||||||
CONFIG.splashMessage("Generating additional icons ...")
|
|
||||||
|
|
||||||
# Set colour overrides for project item icons
|
|
||||||
if (override := CONFIG.iconColTree) != "theme":
|
|
||||||
color = self._svgColors.get(override, b"#000000")
|
|
||||||
self._svgColors["root"] = color
|
|
||||||
self._svgColors["folder"] = color
|
|
||||||
if not CONFIG.iconColDocs:
|
|
||||||
self._svgColors["file"] = color
|
|
||||||
self._svgColors["title"] = color
|
|
||||||
self._svgColors["chapter"] = color
|
|
||||||
self._svgColors["scene"] = color
|
|
||||||
self._svgColors["note"] = color
|
|
||||||
|
|
||||||
# Populate generated icons cache
|
# Populate generated icons cache
|
||||||
|
CONFIG.splashMessage("Generating additional icons ...")
|
||||||
self.getHeaderDecoration(0)
|
self.getHeaderDecoration(0)
|
||||||
self.getHeaderDecorationNarrow(0)
|
self.getHeaderDecorationNarrow(0)
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def setIconColor(self, key: str, color: QColor) -> None:
|
|
||||||
"""Set an icon colour for a named colour."""
|
|
||||||
self._qColors[key] = QColor(color)
|
|
||||||
self._svgColors[key] = color.name(QColor.NameFormat.HexRgb).encode("utf-8")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Access Functions
|
# Access Functions
|
||||||
##
|
##
|
||||||
|
|
||||||
def getIconColor(self, name: str) -> QColor:
|
|
||||||
"""Return an icon color."""
|
|
||||||
return QColor(self._qColors.get(name) or QtBlack)
|
|
||||||
|
|
||||||
def getIcon(self, name: str, color: str | None = None, w: int = 24, h: int = 24) -> QIcon:
|
def getIcon(self, name: str, color: str | None = None, w: int = 24, h: int = 24) -> QIcon:
|
||||||
"""Return an icon from the icon buffer, or load it."""
|
"""Return an icon from the icon buffer, or load it."""
|
||||||
variant = f"{name}-{color}" if color else name
|
variant = f"{name}-{color}" if color else name
|
||||||
@@ -769,7 +806,7 @@ class GuiIcons:
|
|||||||
map or the icon map. This function always returns a QPixmap.
|
map or the icon map. This function always returns a QPixmap.
|
||||||
"""
|
"""
|
||||||
if name in self.IMAGE_MAP:
|
if name in self.IMAGE_MAP:
|
||||||
idx = int(self.mainTheme.isDarkTheme)
|
idx = int(self._theme.isDarkTheme)
|
||||||
imgPath = CONFIG.assetPath("images") / self.IMAGE_MAP[name][idx]
|
imgPath = CONFIG.assetPath("images") / self.IMAGE_MAP[name][idx]
|
||||||
else:
|
else:
|
||||||
logger.error("Decoration with name '%s' does not exist", name)
|
logger.error("Decoration with name '%s' does not exist", name)
|
||||||
@@ -793,7 +830,7 @@ class GuiIcons:
|
|||||||
def getHeaderDecoration(self, hLevel: int) -> QPixmap:
|
def getHeaderDecoration(self, hLevel: int) -> QPixmap:
|
||||||
"""Get the decoration for a specific heading level."""
|
"""Get the decoration for a specific heading level."""
|
||||||
if not self._headerDec:
|
if not self._headerDec:
|
||||||
iPx = self.mainTheme.baseIconHeight
|
iPx = self._theme.baseIconHeight
|
||||||
self._headerDec = [
|
self._headerDec = [
|
||||||
self._generateDecoration("file", iPx, 0),
|
self._generateDecoration("file", iPx, 0),
|
||||||
self._generateDecoration("title", iPx, 0),
|
self._generateDecoration("title", iPx, 0),
|
||||||
@@ -806,7 +843,7 @@ class GuiIcons:
|
|||||||
def getHeaderDecorationNarrow(self, hLevel: int) -> QPixmap:
|
def getHeaderDecorationNarrow(self, hLevel: int) -> QPixmap:
|
||||||
"""Get the narrow decoration for a specific heading level."""
|
"""Get the narrow decoration for a specific heading level."""
|
||||||
if not self._headerDecNarrow:
|
if not self._headerDecNarrow:
|
||||||
iPx = self.mainTheme.baseIconHeight
|
iPx = self._theme.baseIconHeight
|
||||||
self._headerDecNarrow = [
|
self._headerDecNarrow = [
|
||||||
self._generateDecoration("file", iPx, 0),
|
self._generateDecoration("file", iPx, 0),
|
||||||
self._generateDecoration("title", iPx, 0),
|
self._generateDecoration("title", iPx, 0),
|
||||||
@@ -817,21 +854,6 @@ class GuiIcons:
|
|||||||
]
|
]
|
||||||
return self._headerDecNarrow[minmax(hLevel, 0, 5)]
|
return self._headerDecNarrow[minmax(hLevel, 0, 5)]
|
||||||
|
|
||||||
def listThemes(self) -> list[tuple[str, str]]:
|
|
||||||
"""Scan the GUI icons folder and list all themes."""
|
|
||||||
if self._themeList:
|
|
||||||
return self._themeList
|
|
||||||
|
|
||||||
themes = []
|
|
||||||
for key, path in self._availThemes.items():
|
|
||||||
logger.debug("Checking icon theme '%s'", key)
|
|
||||||
if name := _loadIconName(path):
|
|
||||||
themes.append((key, name))
|
|
||||||
|
|
||||||
self._themeList = sorted(themes, key=_sortTheme)
|
|
||||||
|
|
||||||
return self._themeList
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
@@ -847,7 +869,7 @@ class GuiIcons:
|
|||||||
return QIcon(str(CONFIG.assetPath("icons") / "x-novelwriter-project.svg"))
|
return QIcon(str(CONFIG.assetPath("icons") / "x-novelwriter-project.svg"))
|
||||||
|
|
||||||
if svg := self._svgData.get(name, b""):
|
if svg := self._svgData.get(name, b""):
|
||||||
if fill := self._svgColors.get(color or "default"):
|
if fill := self._theme.getRawBaseColor(color or "default"):
|
||||||
svg = svg.replace(b"#000000", fill)
|
svg = svg.replace(b"#000000", fill)
|
||||||
pixmap = QPixmap(w, h)
|
pixmap = QPixmap(w, h)
|
||||||
pixmap.fill(QtTransparent)
|
pixmap.fill(QtTransparent)
|
||||||
@@ -869,53 +891,46 @@ class GuiIcons:
|
|||||||
|
|
||||||
painter = QPainter(pixmap)
|
painter = QPainter(pixmap)
|
||||||
painter.setRenderHint(QtPaintAntiAlias)
|
painter.setRenderHint(QtPaintAntiAlias)
|
||||||
if fill := self._svgColors.get(color or "default"):
|
if fill := self._theme.getRawBaseColor(color or "default"):
|
||||||
painter.fillPath(path, QColor(fill.decode(encoding="utf-8")))
|
painter.fillPath(path, QColor(fill.decode(encoding="utf-8")))
|
||||||
painter.end()
|
painter.end()
|
||||||
|
|
||||||
tMode = Qt.TransformationMode.SmoothTransformation
|
tMode = Qt.TransformationMode.SmoothTransformation
|
||||||
return pixmap.scaledToHeight(height, tMode)
|
return pixmap.scaledToHeight(height, tMode)
|
||||||
|
|
||||||
|
def _scanThemes(self, entries: list[Path]) -> None:
|
||||||
|
"""Scan the GUI themes folder and list all themes."""
|
||||||
|
data: dict[str, tuple[str, str, Path]] = {}
|
||||||
|
keys = []
|
||||||
|
for entry in entries:
|
||||||
|
try:
|
||||||
|
with open(entry, mode="r", encoding="utf-8") as fo:
|
||||||
|
for line in fo:
|
||||||
|
key, _, value = line.partition("=")
|
||||||
|
if key.strip() == "meta:name":
|
||||||
|
if name := value.strip():
|
||||||
|
lookup = entry.stem
|
||||||
|
keys.append(lookup)
|
||||||
|
data[lookup] = (lookup, name, entry)
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
logger.error("Could not read file: %s", entry)
|
||||||
|
logException()
|
||||||
|
|
||||||
|
self._allThemes = {}
|
||||||
|
for lookup in sorted(keys):
|
||||||
|
key, name, item = data[lookup]
|
||||||
|
logger.debug("Checking icon theme '%s'", key)
|
||||||
|
self._allThemes[key] = ThemeEntry(name, False, item)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
# Module Functions
|
# Module Functions
|
||||||
# ================
|
# ================
|
||||||
|
|
||||||
def _listConf(target: dict, path: Path, extension: str) -> None:
|
def _listContent(data: list[Path], path: Path, extension: str) -> None:
|
||||||
"""Scan for theme files and populate the dictionary."""
|
"""List files of a specific type and extend the list."""
|
||||||
if path.is_dir():
|
if path.is_dir():
|
||||||
for item in path.iterdir():
|
data.extend(n for n in path.iterdir() if n.is_file() and n.suffix == extension)
|
||||||
if item.is_file() and item.name.endswith(extension):
|
|
||||||
target[item.stem] = item
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def _sortTheme(data: tuple[str, str]) -> str:
|
|
||||||
"""Key function for theme sorting."""
|
|
||||||
key, name = data
|
|
||||||
return f"*{name}" if key.startswith("default_") else name
|
|
||||||
|
|
||||||
|
|
||||||
def _loadInternalName(parser: NWConfigParser, path: str | Path) -> str:
|
|
||||||
"""Open a conf file and read the 'name' setting."""
|
|
||||||
try:
|
|
||||||
with open(path, mode="r", encoding="utf-8") as inFile:
|
|
||||||
parser.read_file(inFile)
|
|
||||||
return parser.rdStr("Main", "name", "")
|
|
||||||
except Exception:
|
|
||||||
logger.error("Could not read file: %s", path)
|
|
||||||
logException()
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
def _loadIconName(path: Path) -> str:
|
|
||||||
"""Open an icons file and read the name setting."""
|
|
||||||
try:
|
|
||||||
with open(path, mode="r", encoding="utf-8") as icons:
|
|
||||||
for icon in icons:
|
|
||||||
key, _, value = icon.partition("=")
|
|
||||||
if key.strip() == "meta:name":
|
|
||||||
return value.strip()
|
|
||||||
except Exception:
|
|
||||||
logger.error("Could not read file: %s", path)
|
|
||||||
logException()
|
|
||||||
return ""
|
|
||||||
|
|||||||
+37
-18
@@ -30,7 +30,7 @@ from datetime import datetime
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from PyQt6.QtCore import Qt, QTimer, pyqtSlot
|
from PyQt6.QtCore import QEvent, Qt, QTimer, pyqtSlot
|
||||||
from PyQt6.QtGui import QCloseEvent, QCursor, QIcon, QShortcut
|
from PyQt6.QtGui import QCloseEvent, QCursor, QIcon, QShortcut
|
||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox,
|
QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox,
|
||||||
@@ -902,10 +902,45 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return not self.splitView.isVisible()
|
return not self.splitView.isVisible()
|
||||||
|
|
||||||
|
def checkThemeUpdate(self) -> None:
|
||||||
|
"""Load theme if mode changed."""
|
||||||
|
if SHARED.theme.loadTheme():
|
||||||
|
self.refreshThemeColors(syntax=True)
|
||||||
|
self.docEditor.initEditor()
|
||||||
|
self.docViewer.initViewer()
|
||||||
|
return
|
||||||
|
|
||||||
|
def refreshThemeColors(self, syntax: bool = False, force: bool = False) -> None:
|
||||||
|
"""Refresh the GUI theme."""
|
||||||
|
SHARED.theme.loadTheme(force=force)
|
||||||
|
self.setPalette(QApplication.palette())
|
||||||
|
self.docEditor.updateTheme()
|
||||||
|
self.docViewer.updateTheme()
|
||||||
|
self.docViewerPanel.updateTheme()
|
||||||
|
self.sideBar.updateTheme()
|
||||||
|
self.projView.updateTheme()
|
||||||
|
self.novelView.updateTheme()
|
||||||
|
self.projSearch.updateTheme()
|
||||||
|
self.outlineView.updateTheme()
|
||||||
|
self.itemDetails.updateTheme()
|
||||||
|
self.mainStatus.updateTheme()
|
||||||
|
SHARED.project.tree.refreshAllItems()
|
||||||
|
|
||||||
|
if syntax:
|
||||||
|
self.docEditor.updateSyntaxColors()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Events
|
# Events
|
||||||
##
|
##
|
||||||
|
|
||||||
|
def changeEvent(self, event: QEvent) -> None:
|
||||||
|
"""Capture application change events."""
|
||||||
|
if int(event.type()) == 210: # ThemeChange
|
||||||
|
self.checkThemeUpdate()
|
||||||
|
return
|
||||||
|
|
||||||
def closeEvent(self, event: QCloseEvent) -> None:
|
def closeEvent(self, event: QCloseEvent) -> None:
|
||||||
"""Capture the closing event of the GUI and call the close
|
"""Capture the closing event of the GUI and call the close
|
||||||
function to handle all the close process steps.
|
function to handle all the close process steps.
|
||||||
@@ -1054,23 +1089,7 @@ class GuiMain(QMainWindow):
|
|||||||
self.novelView.refreshCurrentTree()
|
self.novelView.refreshCurrentTree()
|
||||||
|
|
||||||
if theme:
|
if theme:
|
||||||
SHARED.theme.loadTheme()
|
self.refreshThemeColors(syntax=syntax, force=True)
|
||||||
self.setPalette(QApplication.palette())
|
|
||||||
self.docEditor.updateTheme()
|
|
||||||
self.docViewer.updateTheme()
|
|
||||||
self.docViewerPanel.updateTheme()
|
|
||||||
self.sideBar.updateTheme()
|
|
||||||
self.projView.updateTheme()
|
|
||||||
self.novelView.updateTheme()
|
|
||||||
self.projSearch.updateTheme()
|
|
||||||
self.outlineView.updateTheme()
|
|
||||||
self.itemDetails.updateTheme()
|
|
||||||
self.mainStatus.updateTheme()
|
|
||||||
SHARED.project.tree.refreshAllItems()
|
|
||||||
|
|
||||||
if syntax:
|
|
||||||
SHARED.theme.loadSyntax()
|
|
||||||
self.docEditor.updateSyntaxColors()
|
|
||||||
|
|
||||||
self.docEditor.initEditor()
|
self.docEditor.initEditor()
|
||||||
self.docViewer.initViewer()
|
self.docViewer.initViewer()
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ class SharedData(QObject):
|
|||||||
is created.
|
is created.
|
||||||
"""
|
"""
|
||||||
self._theme = theme
|
self._theme = theme
|
||||||
|
self._theme.initThemes()
|
||||||
return
|
return
|
||||||
|
|
||||||
def initSharedData(self, gui: GuiMain) -> None:
|
def initSharedData(self, gui: GuiMain) -> None:
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ class MockTheme:
|
|||||||
self.guiFontBU = QFont()
|
self.guiFontBU = QFont()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def initThemes(self) -> None:
|
||||||
|
return
|
||||||
|
|
||||||
def getPixmap(self, *a) -> QPixmap:
|
def getPixmap(self, *a) -> QPixmap:
|
||||||
return QPixmap()
|
return QPixmap()
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
[Meta]
|
[Meta]
|
||||||
timestamp = 2025-05-11 13:28:11
|
timestamp = 2025-06-02 16:21:38
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
font =
|
font =
|
||||||
theme = default
|
lighttheme = default_light
|
||||||
syntax = default_light
|
darktheme = default_dark
|
||||||
|
thememode = AUTO
|
||||||
icons = material_rounded_normal
|
icons = material_rounded_normal
|
||||||
iconcoltree = theme
|
iconcoltree = theme
|
||||||
iconcoldocs = False
|
iconcoldocs = False
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ from novelwriter.common import (
|
|||||||
readTextFile, simplified, transferCase, uniqueCompact, xmlElement,
|
readTextFile, simplified, transferCase, uniqueCompact, xmlElement,
|
||||||
xmlIndent, xmlSubElem, yesNo
|
xmlIndent, xmlSubElem, yesNo
|
||||||
)
|
)
|
||||||
|
from novelwriter.enum import nwItemClass
|
||||||
|
|
||||||
from tests.mocked import causeOSError
|
from tests.mocked import causeOSError
|
||||||
from tests.tools import writeFile
|
from tests.tools import writeFile
|
||||||
@@ -804,6 +805,7 @@ def testBaseCommon_NWConfigParser(fncPath):
|
|||||||
"list1 = a, b, c\n"
|
"list1 = a, b, c\n"
|
||||||
"list2 = 17, 18, 19\n"
|
"list2 = 17, 18, 19\n"
|
||||||
"float1 = 4.2\n"
|
"float1 = 4.2\n"
|
||||||
|
"enum1 = NOVEL\n"
|
||||||
f"path1 = {fncPath}\n"
|
f"path1 = {fncPath}\n"
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -875,3 +877,7 @@ def testBaseCommon_NWConfigParser(fncPath):
|
|||||||
|
|
||||||
assert cfgParser.rdIntList("nope", "list2", [1]) == [1]
|
assert cfgParser.rdIntList("nope", "list2", [1]) == [1]
|
||||||
assert cfgParser.rdIntList("main", "blabla", [1]) == [1]
|
assert cfgParser.rdIntList("main", "blabla", [1]) == [1]
|
||||||
|
|
||||||
|
# Read Enum
|
||||||
|
assert cfgParser.rdEnum("main", "enum1", nwItemClass.NO_CLASS) == nwItemClass.NOVEL
|
||||||
|
assert cfgParser.rdEnum("main", "blabla", nwItemClass.NO_CLASS) == nwItemClass.NO_CLASS
|
||||||
|
|||||||
@@ -131,15 +131,15 @@ def testBaseConfig_InitLoadSave(monkeypatch, fncPath, tstPaths):
|
|||||||
assert tstConf.errorText().startswith("Could not load config file")
|
assert tstConf.errorText().startswith("Could not load config file")
|
||||||
|
|
||||||
# Change a few settings, save, reset, and reload
|
# Change a few settings, save, reset, and reload
|
||||||
tstConf.guiTheme = "foo"
|
tstConf.lightTheme = "foo"
|
||||||
tstConf.guiSyntax = "bar"
|
tstConf.darkTheme = "bar"
|
||||||
assert tstConf.saveConfig() is True
|
assert tstConf.saveConfig() is True
|
||||||
|
|
||||||
newConf = Config()
|
newConf = Config()
|
||||||
newConf.initConfig(confPath=fncPath, dataPath=fncPath)
|
newConf.initConfig(confPath=fncPath, dataPath=fncPath)
|
||||||
newConf.loadConfig()
|
newConf.loadConfig()
|
||||||
assert newConf.guiTheme == "foo"
|
assert newConf.lightTheme == "foo"
|
||||||
assert newConf.guiSyntax == "bar"
|
assert newConf.darkTheme == "bar"
|
||||||
|
|
||||||
# Test Correcting Quote Settings
|
# Test Correcting Quote Settings
|
||||||
tstConf.fmtDQuoteOpen = '"'
|
tstConf.fmtDQuoteOpen = '"'
|
||||||
|
|||||||
@@ -27,10 +27,11 @@ from PyQt6.QtGui import QAction, QFont, QFontDatabase, QKeyEvent
|
|||||||
from PyQt6.QtWidgets import QFileDialog, QFontDialog
|
from PyQt6.QtWidgets import QFileDialog, QFontDialog
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.config import DEF_GUI
|
from novelwriter.config import DEF_GUI_DARK, DEF_GUI_LIGHT
|
||||||
from novelwriter.constants import nwUnicode
|
from novelwriter.constants import nwUnicode
|
||||||
from novelwriter.dialogs.preferences import GuiPreferences
|
from novelwriter.dialogs.preferences import GuiPreferences
|
||||||
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
||||||
|
from novelwriter.gui.theme import ThemeEntry
|
||||||
from novelwriter.types import QtDialogCancel, QtDialogSave, QtModNone
|
from novelwriter.types import QtDialogCancel, QtDialogSave, QtModNone
|
||||||
|
|
||||||
KEY_DELAY = 1
|
KEY_DELAY = 1
|
||||||
@@ -55,15 +56,11 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths):
|
|||||||
assert "en_GB" in languages
|
assert "en_GB" in languages
|
||||||
|
|
||||||
# Check GUI Themes
|
# Check GUI Themes
|
||||||
themes = [prefs.guiTheme.itemData(i) for i in range(prefs.guiTheme.count())]
|
themes = [prefs.lightTheme.itemData(i) for i in range(prefs.lightTheme.count())]
|
||||||
assert len(themes) >= 5
|
assert DEF_GUI_LIGHT in themes
|
||||||
assert DEF_GUI in themes
|
|
||||||
|
|
||||||
# Check GUI Syntax
|
themes = [prefs.darkTheme.itemData(i) for i in range(prefs.darkTheme.count())]
|
||||||
syntax = [prefs.guiSyntax.itemData(i) for i in range(prefs.guiSyntax.count())]
|
assert DEF_GUI_DARK in themes
|
||||||
assert len(syntax) >= 10
|
|
||||||
assert "default_dark" in syntax
|
|
||||||
assert "default_light" in syntax
|
|
||||||
|
|
||||||
# Check Spell Checking
|
# Check Spell Checking
|
||||||
spelling = [prefs.spellLanguage.itemData(i) for i in range(prefs.spellLanguage.count())]
|
spelling = [prefs.spellLanguage.itemData(i) for i in range(prefs.spellLanguage.count())]
|
||||||
@@ -124,7 +121,7 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
|
|||||||
button = prefs.buttonBox.button(QtDialogSave)
|
button = prefs.buttonBox.button(QtDialogSave)
|
||||||
assert button is not None
|
assert button is not None
|
||||||
button.click()
|
button.click()
|
||||||
assert signal.args == [False, False, False, False]
|
assert len(signal.args) == 4
|
||||||
|
|
||||||
# Check Close Button
|
# Check Close Button
|
||||||
prefs.show()
|
prefs.show()
|
||||||
@@ -151,6 +148,12 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
|
|||||||
(fncPath / "nw_en_US.qm").touch()
|
(fncPath / "nw_en_US.qm").touch()
|
||||||
(fncPath / "project_en_US.json").touch()
|
(fncPath / "project_en_US.json").touch()
|
||||||
CONFIG._nwLangPath = fncPath
|
CONFIG._nwLangPath = fncPath
|
||||||
|
SHARED.theme._allThemes = {
|
||||||
|
"theme1": ThemeEntry(name="Theme 1", dark=False, path=fncPath),
|
||||||
|
"theme2": ThemeEntry(name="Theme 2", dark=False, path=fncPath),
|
||||||
|
"theme3": ThemeEntry(name="Theme 3", dark=True, path=fncPath),
|
||||||
|
"theme4": ThemeEntry(name="Theme 4", dark=True, path=fncPath),
|
||||||
|
}
|
||||||
|
|
||||||
prefs = GuiPreferences(nwGUI)
|
prefs = GuiPreferences(nwGUI)
|
||||||
with qtbot.waitExposed(prefs):
|
with qtbot.waitExposed(prefs):
|
||||||
@@ -158,7 +161,8 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
|
|||||||
|
|
||||||
# Appearance
|
# Appearance
|
||||||
prefs.guiLocale.setCurrentIndex(prefs.guiLocale.findData("en_US"))
|
prefs.guiLocale.setCurrentIndex(prefs.guiLocale.findData("en_US"))
|
||||||
prefs.guiTheme.setCurrentIndex(prefs.guiTheme.findData("default_dark"))
|
prefs.lightTheme.setCurrentIndex(prefs.lightTheme.findData("theme1"))
|
||||||
|
prefs.darkTheme.setCurrentIndex(prefs.darkTheme.findData("theme3"))
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(QFontDialog, "getFont", lambda *a, **k: (QFont(), True))
|
mp.setattr(QFontDialog, "getFont", lambda *a, **k: (QFont(), True))
|
||||||
prefs.nativeFont.setChecked(True) # Use OS font dialog
|
prefs.nativeFont.setChecked(True) # Use OS font dialog
|
||||||
@@ -169,14 +173,14 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
|
|||||||
prefs.useCharCount.setChecked(True)
|
prefs.useCharCount.setChecked(True)
|
||||||
|
|
||||||
assert CONFIG.guiLocale != "en_US"
|
assert CONFIG.guiLocale != "en_US"
|
||||||
assert CONFIG.guiTheme != "default_dark"
|
assert CONFIG.lightTheme == "default_light"
|
||||||
|
assert CONFIG.darkTheme == "default_dark"
|
||||||
assert CONFIG.guiFont.family() != ""
|
assert CONFIG.guiFont.family() != ""
|
||||||
assert CONFIG.hideVScroll is False
|
assert CONFIG.hideVScroll is False
|
||||||
assert CONFIG.hideHScroll is False
|
assert CONFIG.hideHScroll is False
|
||||||
assert CONFIG.useCharCount is False
|
assert CONFIG.useCharCount is False
|
||||||
|
|
||||||
# Document Style
|
# Document Style
|
||||||
prefs.guiSyntax.setCurrentIndex(prefs.guiSyntax.findData("default_dark"))
|
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(QFontDialog, "getFont", lambda *a, **k: (QFont(), True))
|
mp.setattr(QFontDialog, "getFont", lambda *a, **k: (QFont(), True))
|
||||||
prefs.nativeFont.setChecked(False) # Use Qt font dialog
|
prefs.nativeFont.setChecked(False) # Use Qt font dialog
|
||||||
@@ -185,7 +189,6 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
|
|||||||
prefs.showFullPath.setChecked(False)
|
prefs.showFullPath.setChecked(False)
|
||||||
prefs.incNotesWCount.setChecked(False)
|
prefs.incNotesWCount.setChecked(False)
|
||||||
|
|
||||||
assert CONFIG.guiSyntax != "default_dark"
|
|
||||||
assert CONFIG.textFont.family() != ""
|
assert CONFIG.textFont.family() != ""
|
||||||
assert CONFIG.showFullPath is True
|
assert CONFIG.showFullPath is True
|
||||||
assert CONFIG.incNotesWCount is True
|
assert CONFIG.incNotesWCount is True
|
||||||
@@ -344,14 +347,14 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
|
|||||||
|
|
||||||
# Appearance
|
# Appearance
|
||||||
assert CONFIG.guiLocale == "en_US"
|
assert CONFIG.guiLocale == "en_US"
|
||||||
assert CONFIG.guiTheme == "default_dark"
|
assert CONFIG.lightTheme == "theme1"
|
||||||
|
assert CONFIG.darkTheme == "theme3"
|
||||||
assert CONFIG.guiFont == QFont()
|
assert CONFIG.guiFont == QFont()
|
||||||
assert CONFIG.hideVScroll is True
|
assert CONFIG.hideVScroll is True
|
||||||
assert CONFIG.hideHScroll is True
|
assert CONFIG.hideHScroll is True
|
||||||
assert CONFIG.useCharCount is True
|
assert CONFIG.useCharCount is True
|
||||||
|
|
||||||
# Document Style
|
# Document Style
|
||||||
assert CONFIG.guiSyntax == "default_dark"
|
|
||||||
assert CONFIG.textFont == QFont()
|
assert CONFIG.textFont == QFont()
|
||||||
assert CONFIG.showFullPath is False
|
assert CONFIG.showFullPath is False
|
||||||
assert CONFIG.incNotesWCount is False
|
assert CONFIG.incNotesWCount is False
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import shutil
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -32,9 +33,10 @@ from PyQt6.QtGui import QPalette
|
|||||||
from PyQt6.QtWidgets import QInputDialog, QMessageBox
|
from PyQt6.QtWidgets import QInputDialog, QMessageBox
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
|
from novelwriter.config import DEF_GUI_DARK, DEF_GUI_LIGHT
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
from novelwriter.dialogs.editlabel import GuiEditLabel
|
from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||||
from novelwriter.enum import nwDocAction, nwDocMode, nwFocus, nwItemType, nwView
|
from novelwriter.enum import nwDocAction, nwDocMode, nwFocus, nwItemType, nwTheme, nwView
|
||||||
from novelwriter.gui.doceditor import GuiDocEditor
|
from novelwriter.gui.doceditor import GuiDocEditor
|
||||||
from novelwriter.gui.noveltree import GuiNovelView
|
from novelwriter.gui.noveltree import GuiNovelView
|
||||||
from novelwriter.gui.outline import GuiOutlineView
|
from novelwriter.gui.outline import GuiOutlineView
|
||||||
@@ -179,21 +181,35 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
|||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiMain_UpdateTheme(qtbot, nwGUI):
|
def testGuiMain_UpdateTheme(qtbot, nwGUI):
|
||||||
"""Test updating the theme in the GUI."""
|
"""Test updating the theme in the GUI."""
|
||||||
mainTheme = SHARED.theme
|
theme = SHARED.theme
|
||||||
CONFIG.guiTheme = "default_dark"
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
CONFIG.guiSyntax = "default_dark"
|
CONFIG.darkTheme = DEF_GUI_DARK
|
||||||
mainTheme.loadTheme()
|
CONFIG.lightTheme = DEF_GUI_LIGHT
|
||||||
mainTheme.loadSyntax()
|
theme.loadTheme()
|
||||||
|
assert theme.isDarkTheme is True
|
||||||
|
|
||||||
nwGUI._processConfigChanges(False, True, False, False)
|
nwGUI._processConfigChanges(False, True, False, False)
|
||||||
nwGUI._processConfigChanges(True, True, True, True)
|
nwGUI._processConfigChanges(True, True, True, True)
|
||||||
|
|
||||||
|
# Check editor syntax
|
||||||
syntax = SHARED.theme.syntaxTheme
|
syntax = SHARED.theme.syntaxTheme
|
||||||
|
|
||||||
assert nwGUI.docEditor.palette().color(QPalette.ColorRole.Window) == syntax.back
|
assert nwGUI.docEditor.palette().color(QPalette.ColorRole.Window) == syntax.back
|
||||||
assert nwGUI.docEditor.docHeader.palette().color(QPalette.ColorRole.Window) == syntax.back
|
assert nwGUI.docEditor.docHeader.palette().color(QPalette.ColorRole.Window) == syntax.back
|
||||||
assert nwGUI.docViewer.palette().color(QPalette.ColorRole.Window) == syntax.back
|
assert nwGUI.docViewer.palette().color(QPalette.ColorRole.Window) == syntax.back
|
||||||
assert nwGUI.docViewer.docHeader.palette().color(QPalette.ColorRole.Window) == syntax.back
|
assert nwGUI.docViewer.docHeader.palette().color(QPalette.ColorRole.Window) == syntax.back
|
||||||
|
|
||||||
|
# Update by check
|
||||||
|
CONFIG.themeMode = nwTheme.LIGHT
|
||||||
|
nwGUI.checkThemeUpdate()
|
||||||
|
assert theme.isDarkTheme is False
|
||||||
|
|
||||||
|
# Through change event
|
||||||
|
event = Mock()
|
||||||
|
event.type.return_value = 210
|
||||||
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
|
nwGUI.changeEvent(event)
|
||||||
|
assert theme.isDarkTheme is True
|
||||||
|
|
||||||
# qtbot.stop()
|
# qtbot.stop()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
novelWriter – Side Bar Class Tester
|
||||||
|
===================================
|
||||||
|
|
||||||
|
This file is a part of novelWriter
|
||||||
|
Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program 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
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from novelwriter import CONFIG
|
||||||
|
from novelwriter.constants import nwLabels
|
||||||
|
from novelwriter.enum import nwTheme
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiSideBar_CycleColourTheme(nwGUI):
|
||||||
|
"""Test theme cycle feature on the side bar."""
|
||||||
|
CONFIG.themeMode = nwTheme.AUTO
|
||||||
|
sidebar = nwGUI.sideBar
|
||||||
|
sidebar.mainGui.checkThemeUpdate = lambda *a: None
|
||||||
|
|
||||||
|
# Run 3 Cycles
|
||||||
|
for _ in range(3):
|
||||||
|
|
||||||
|
# Cycle Light
|
||||||
|
sidebar._cycleColurTheme()
|
||||||
|
assert CONFIG.themeMode == nwTheme.LIGHT
|
||||||
|
assert sidebar.tbTheme.toolTip() == nwLabels.THEME_MODE_LABEL[nwTheme.LIGHT]
|
||||||
|
|
||||||
|
# Cycle Dark
|
||||||
|
sidebar._cycleColurTheme()
|
||||||
|
assert CONFIG.themeMode == nwTheme.DARK
|
||||||
|
assert sidebar.tbTheme.toolTip() == nwLabels.THEME_MODE_LABEL[nwTheme.DARK]
|
||||||
|
|
||||||
|
# Cycle Auto
|
||||||
|
sidebar._cycleColurTheme()
|
||||||
|
assert CONFIG.themeMode == nwTheme.AUTO
|
||||||
|
assert sidebar.tbTheme.toolTip() == nwLabels.THEME_MODE_LABEL[nwTheme.AUTO]
|
||||||
@@ -31,7 +31,7 @@ from tests.tools import C, buildTestProject
|
|||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiStatusBar_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
def testGuiStatusBar_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||||
"""Test the the various features of the status bar."""
|
"""Test the various features of the status bar."""
|
||||||
buildTestProject(nwGUI, projPath)
|
buildTestProject(nwGUI, projPath)
|
||||||
cHandle = SHARED.project.newFile("A Note", C.hCharRoot)
|
cHandle = SHARED.project.newFile("A Note", C.hCharRoot)
|
||||||
newDoc = SHARED.project.storage.getDocument(cHandle)
|
newDoc = SHARED.project.storage.getDocument(cHandle)
|
||||||
|
|||||||
+340
-298
@@ -20,344 +20,389 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
from configparser import ConfigParser
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from unittest.mock import MagicMock, Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PyQt6.QtGui import QColor, QIcon, QPalette, QPixmap
|
from PyQt6.QtCore import Qt
|
||||||
|
from PyQt6.QtGui import QColor, QFont, QFontDatabase, QIcon, QPalette, QPixmap, QStyleHints
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG
|
||||||
from novelwriter.common import NWConfigParser
|
from novelwriter.config import DEF_GUI_DARK, DEF_GUI_LIGHT, DEF_ICONS
|
||||||
from novelwriter.config import DEF_GUI
|
|
||||||
from novelwriter.constants import nwLabels
|
from novelwriter.constants import nwLabels
|
||||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType, nwTheme
|
||||||
from novelwriter.gui.theme import _listConf
|
from novelwriter.gui.theme import (
|
||||||
|
STYLES_BIG_TOOLBUTTON, STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON, GuiTheme,
|
||||||
|
ThemeMeta, _listContent
|
||||||
|
)
|
||||||
|
|
||||||
from tests.mocked import causeOSError
|
from tests.mocked import causeOSError
|
||||||
from tests.tools import writeFile
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiTheme_Main(qtbot, nwGUI, tstPaths):
|
def testGuiTheme_ParseColor():
|
||||||
"""Test the theme class init."""
|
"""Test the colour parsing."""
|
||||||
mainTheme = SHARED.theme
|
theme = GuiTheme()
|
||||||
|
|
||||||
# Methods
|
# Pre-Populate
|
||||||
# =======
|
theme._qColors["red"] = QColor(255, 0, 0)
|
||||||
|
theme._qColors["green"] = QColor(0, 255, 0)
|
||||||
|
theme._qColors["blue"] = QColor(0, 0, 255)
|
||||||
|
|
||||||
mSize = mainTheme.getTextWidth("m")
|
# By Name
|
||||||
assert mSize > 0
|
assert theme.parseColor("red").getRgb() == (255, 0, 0, 255)
|
||||||
assert mainTheme.getTextWidth("m", mainTheme.guiFont) == mSize
|
assert theme.parseColor("green").getRgb() == (0, 255, 0, 255)
|
||||||
|
assert theme.parseColor("blue").getRgb() == (0, 0, 255, 255)
|
||||||
|
assert theme.parseColor("bob").getRgb() == (0, 0, 0, 255)
|
||||||
|
|
||||||
# Scan for Themes
|
# CSS Format
|
||||||
# ===============
|
assert theme.parseColor("#ff0000").getRgb() == (255, 0, 0, 255)
|
||||||
|
assert theme.parseColor("#ff00007f").getRgb() == (255, 0, 0, 127)
|
||||||
|
assert theme.parseColor("#ff00").getRgb() == (0, 0, 0, 255) # Too short -> ignored
|
||||||
|
assert theme.parseColor("#ff00007f15").getRgb() == (0, 0, 0, 255) # Too long -> ignored
|
||||||
|
|
||||||
result = {}
|
# Name + Alpha
|
||||||
_listConf({}, Path("not_a_path"), ".conf")
|
assert theme.parseColor("red:255").getRgb() == (255, 0, 0, 255)
|
||||||
assert result == {}
|
assert theme.parseColor("red:127").getRgb() == (255, 0, 0, 127)
|
||||||
|
assert theme.parseColor("red:512").getRgb() == (255, 0, 0, 255) # Value truncated
|
||||||
|
|
||||||
themeOne = tstPaths.cnfDir / "themes" / "themeone.conf"
|
# Values
|
||||||
themeTwo = tstPaths.cnfDir / "themes" / "themetwo.conf"
|
assert theme.parseColor("255, 0, 0").getRgb() == (255, 0, 0, 255)
|
||||||
writeFile(themeOne, "# Stuff")
|
assert theme.parseColor("255, 0, 0, 255").getRgb() == (255, 0, 0, 255)
|
||||||
writeFile(themeTwo, "# Stuff")
|
assert theme.parseColor("255, 0, 0, 127").getRgb() == (255, 0, 0, 127)
|
||||||
|
assert theme.parseColor("255, 0, 0, 127, 42").getRgb() == (255, 0, 0, 127) # Truncated
|
||||||
_listConf(result, tstPaths.cnfDir / "themes", ".conf")
|
|
||||||
assert result["themeone"] == themeOne
|
|
||||||
assert result["themetwo"] == themeTwo
|
|
||||||
|
|
||||||
# Parse Colours
|
|
||||||
# =============
|
|
||||||
|
|
||||||
parser = NWConfigParser()
|
|
||||||
parser["Palette"] = {
|
|
||||||
"colour1": "100, 150, 200", # Valid
|
|
||||||
"colour2": "100, 150, 200, 250", # With alpha
|
|
||||||
"colour3": "100, 150, 200, 250, 300", # Too many values
|
|
||||||
"colour4": "250, 250", # Missing blue
|
|
||||||
"colour5": "-10, 127, 300", # Invalid red and blue
|
|
||||||
"colour6": "bob, 127, 255", # Invalid red
|
|
||||||
}
|
|
||||||
|
|
||||||
# Test the parser for several valid and invalid values
|
|
||||||
assert mainTheme._parseColor(parser, "Palette", "colour1").getRgb() == (100, 150, 200, 255)
|
|
||||||
assert mainTheme._parseColor(parser, "Palette", "colour2").getRgb() == (100, 150, 200, 250)
|
|
||||||
assert mainTheme._parseColor(parser, "Palette", "colour3").getRgb() == (100, 150, 200, 250)
|
|
||||||
assert mainTheme._parseColor(parser, "Palette", "colour4").getRgb() == (250, 250, 0, 255)
|
|
||||||
assert mainTheme._parseColor(parser, "Palette", "colour5").getRgb() == (0, 0, 0, 0)
|
|
||||||
assert mainTheme._parseColor(parser, "Palette", "colour6").getRgb() == (0, 127, 255, 255)
|
|
||||||
|
|
||||||
# The palette should load with the parsed values
|
|
||||||
mainTheme._setPalette(parser, "Palette", "colour1", QPalette.ColorRole.Window)
|
|
||||||
assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (100, 150, 200, 255)
|
|
||||||
mainTheme._setPalette(parser, "Palette", "colour2", QPalette.ColorRole.Window)
|
|
||||||
assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (100, 150, 200, 250)
|
|
||||||
mainTheme._setPalette(parser, "Palette", "colour3", QPalette.ColorRole.Window)
|
|
||||||
assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (100, 150, 200, 250)
|
|
||||||
mainTheme._setPalette(parser, "Palette", "colour4", QPalette.ColorRole.Window)
|
|
||||||
assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (250, 250, 0, 255)
|
|
||||||
mainTheme._setPalette(parser, "Palette", "colour5", QPalette.ColorRole.Window)
|
|
||||||
assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (0, 0, 0, 0)
|
|
||||||
mainTheme._setPalette(parser, "Palette", "colour6", QPalette.ColorRole.Window)
|
|
||||||
assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (0, 127, 255, 255)
|
|
||||||
|
|
||||||
# Non-existing value should return default colour
|
|
||||||
mainTheme._setPalette(parser, "Palette", "stuff", QPalette.ColorRole.Window)
|
|
||||||
assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == (0, 0, 0, 255)
|
|
||||||
|
|
||||||
# qtbot.stop()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI, tstPaths):
|
def testGuiTheme_ScanThemes(monkeypatch):
|
||||||
"""Test the theme part of the class."""
|
"""Test the themes scanning."""
|
||||||
mainTheme = SHARED.theme
|
theme = GuiTheme()
|
||||||
|
|
||||||
# List Themes
|
# Load built-in themes
|
||||||
|
files = []
|
||||||
|
_listContent(files, CONFIG.assetPath("themes"), ".conf")
|
||||||
|
assert len(files) > 0
|
||||||
|
|
||||||
|
# Block reading theme files
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(ConfigParser, "read", causeOSError)
|
||||||
|
theme._scanThemes(files)
|
||||||
|
assert theme.colourThemes == {}
|
||||||
|
|
||||||
|
# Read all themes correctly
|
||||||
|
theme._scanThemes(files)
|
||||||
|
assert len(theme.colourThemes) > 0
|
||||||
|
|
||||||
|
dark = theme.colourThemes[DEF_GUI_DARK]
|
||||||
|
light = theme.colourThemes[DEF_GUI_LIGHT]
|
||||||
|
|
||||||
|
assert dark.name == "Default Dark Theme"
|
||||||
|
assert dark.dark is True
|
||||||
|
assert light.name == "Default Light Theme"
|
||||||
|
assert light.dark is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiTheme_LoadThemes(monkeypatch):
|
||||||
|
"""Test loading themes."""
|
||||||
|
theme = GuiTheme()
|
||||||
|
theme.iconCache = MagicMock()
|
||||||
|
CONFIG.lightTheme = DEF_GUI_LIGHT
|
||||||
|
CONFIG.darkTheme = DEF_GUI_DARK
|
||||||
|
|
||||||
|
# Load built-in themes
|
||||||
|
files = []
|
||||||
|
_listContent(files, CONFIG.assetPath("themes"), ".conf")
|
||||||
|
theme._scanThemes(files)
|
||||||
|
assert DEF_GUI_LIGHT in theme._allThemes
|
||||||
|
assert DEF_GUI_DARK in theme._allThemes
|
||||||
|
assert theme._currentTheme == ""
|
||||||
|
|
||||||
|
# Load light theme
|
||||||
|
CONFIG.themeMode = nwTheme.LIGHT
|
||||||
|
theme.loadTheme()
|
||||||
|
assert theme._currentTheme == DEF_GUI_LIGHT
|
||||||
|
|
||||||
|
# Load dark theme
|
||||||
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
|
theme.loadTheme()
|
||||||
|
assert theme._currentTheme == DEF_GUI_DARK
|
||||||
|
|
||||||
|
# Let auto switch back to light, then dark
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(CONFIG, "verQtValue", 0x060500)
|
||||||
|
mp.setattr(QStyleHints, "colorScheme", lambda *a: Qt.ColorScheme.Light)
|
||||||
|
CONFIG.themeMode = nwTheme.AUTO
|
||||||
|
theme.loadTheme()
|
||||||
|
assert theme._currentTheme == DEF_GUI_LIGHT
|
||||||
|
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(CONFIG, "verQtValue", 0x060500)
|
||||||
|
mp.setattr(QStyleHints, "colorScheme", lambda *a: Qt.ColorScheme.Dark)
|
||||||
|
CONFIG.themeMode = nwTheme.AUTO
|
||||||
|
theme.loadTheme()
|
||||||
|
assert theme._currentTheme == DEF_GUI_DARK
|
||||||
|
|
||||||
|
# Error Cases
|
||||||
# ===========
|
# ===========
|
||||||
|
|
||||||
# Block the reading of the files
|
# Invalid light theme
|
||||||
|
CONFIG.lightTheme = "not_a_theme"
|
||||||
|
CONFIG.themeMode = nwTheme.LIGHT
|
||||||
|
theme.loadTheme()
|
||||||
|
assert theme._currentTheme == DEF_GUI_LIGHT
|
||||||
|
|
||||||
|
# Invalid dark theme
|
||||||
|
CONFIG.darkTheme = "not_a_theme"
|
||||||
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
|
theme.loadTheme()
|
||||||
|
assert theme._currentTheme == DEF_GUI_DARK
|
||||||
|
|
||||||
|
# Clear meta and check exit early cases
|
||||||
|
theme._meta = ThemeMeta()
|
||||||
|
assert theme._meta.name == ""
|
||||||
|
|
||||||
|
# Reload dark should not load anything
|
||||||
|
CONFIG.darkTheme = DEF_GUI_DARK
|
||||||
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
|
theme.loadTheme()
|
||||||
|
assert theme._meta.name == ""
|
||||||
|
|
||||||
|
# Force reload, but fail parsing
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr("builtins.open", causeOSError)
|
mp.setattr(ConfigParser, "read", causeOSError)
|
||||||
assert mainTheme.listThemes() == []
|
CONFIG.darkTheme = DEF_GUI_DARK
|
||||||
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
|
theme.loadTheme(force=True)
|
||||||
|
assert theme._meta.name == ""
|
||||||
|
|
||||||
# Load the theme info, default themes first
|
# Invalid theme, and defaults are missing
|
||||||
themesList = mainTheme.listThemes()
|
del theme._allThemes[DEF_GUI_DARK]
|
||||||
assert themesList[0] == ("default_dark", "Default Dark Theme")
|
del theme._allThemes[DEF_GUI_LIGHT]
|
||||||
assert themesList[1] == ("default_light", "Default Light Theme")
|
|
||||||
assert themesList[2] == ("cyberpunk_night", "Cyberpunk Night")
|
|
||||||
assert themesList[3] == ("dracula", "Dracula")
|
|
||||||
|
|
||||||
# A second call should returned the cached list
|
CONFIG.lightTheme = "not_a_theme"
|
||||||
assert mainTheme.listThemes() == mainTheme._themeList
|
CONFIG.themeMode = nwTheme.LIGHT
|
||||||
|
theme.loadTheme(force=True)
|
||||||
|
assert theme._meta.name == ""
|
||||||
|
|
||||||
# Check handling of broken theme settings
|
CONFIG.darkTheme = "not_a_theme"
|
||||||
CONFIG.guiTheme = "not_a_theme"
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
availThemes = mainTheme._availThemes
|
theme.loadTheme(force=True)
|
||||||
mainTheme._availThemes = {}
|
assert theme._meta.name == ""
|
||||||
assert mainTheme.loadTheme() is False
|
|
||||||
mainTheme._availThemes = availThemes
|
|
||||||
|
|
||||||
# Check handling of unreadable file
|
|
||||||
CONFIG.guiTheme = DEF_GUI
|
|
||||||
with monkeypatch.context() as mp:
|
|
||||||
mp.setattr("builtins.open", causeOSError)
|
|
||||||
assert mainTheme.loadTheme() is False
|
|
||||||
|
|
||||||
# Load Default Theme
|
@pytest.mark.gui
|
||||||
# ==================
|
def testGuiTheme_SpecialColors(tstPaths):
|
||||||
|
"""Test handling special cases for colours."""
|
||||||
|
theme = GuiTheme()
|
||||||
|
theme.iconCache = MagicMock()
|
||||||
|
|
||||||
if sys.platform != "win32":
|
testTheme: Path = tstPaths.cnfDir / "themes" / "test.conf"
|
||||||
# Set a mock colour for the window background
|
testTheme.write_text(
|
||||||
mainTheme._guiPalette.color(QPalette.ColorRole.Window).setRgb(0, 0, 0, 0)
|
|
||||||
|
|
||||||
# Load the default theme
|
|
||||||
CONFIG.guiTheme = DEF_GUI
|
|
||||||
assert mainTheme.loadTheme() is True
|
|
||||||
|
|
||||||
# This should load a standard palette
|
|
||||||
wCol = QPalette().color(QPalette.ColorRole.Window).getRgb()
|
|
||||||
assert mainTheme._guiPalette.color(QPalette.ColorRole.Window).getRgb() == wCol
|
|
||||||
|
|
||||||
# Mock Dark Theme
|
|
||||||
# ===============
|
|
||||||
|
|
||||||
mockTheme: Path = tstPaths.cnfDir / "themes" / "test.conf"
|
|
||||||
mockTheme.write_text(
|
|
||||||
"[Main]\n"
|
"[Main]\n"
|
||||||
"name = Test\n"
|
"name = Test\n"
|
||||||
|
"mode = light\n"
|
||||||
|
"\n"
|
||||||
|
"[Base]\n"
|
||||||
|
"default = #cccccc\n"
|
||||||
|
"faded = #949494\n"
|
||||||
|
"red = #ff0000\n"
|
||||||
|
"orange = #ff7f00\n"
|
||||||
|
"yellow = #ffff00\n"
|
||||||
|
"green = #00ff00\n"
|
||||||
|
"cyan = #00ffff\n"
|
||||||
|
"blue = #0000ff\n"
|
||||||
|
"purple = #ff00ff\n"
|
||||||
|
"\n"
|
||||||
|
"[Project]\n"
|
||||||
|
"root = blue\n"
|
||||||
|
"folder = yellow\n"
|
||||||
|
"file = default\n"
|
||||||
|
"title = green\n"
|
||||||
|
"chapter = red\n"
|
||||||
|
"scene = blue\n"
|
||||||
|
"note = yellow\n"
|
||||||
"\n"
|
"\n"
|
||||||
"[Palette]\n"
|
"[Palette]\n"
|
||||||
"window = 0, 0, 0\n"
|
"window = #000000\n"
|
||||||
"text = 255, 255, 255\n"
|
"text = #ffffff\n"
|
||||||
)
|
)
|
||||||
mainTheme._availThemes["test"] = mockTheme
|
theme._scanThemes([testTheme])
|
||||||
|
assert len(theme.colourThemes) == 1
|
||||||
|
CONFIG.themeMode = nwTheme.LIGHT
|
||||||
|
CONFIG.lightTheme = "test"
|
||||||
|
|
||||||
CONFIG.guiTheme = "test"
|
# Load theme
|
||||||
assert mainTheme.loadTheme() is True
|
theme.loadTheme()
|
||||||
assert mainTheme._guiPalette.window().color().getRgb() == (0, 0, 0, 255)
|
|
||||||
assert mainTheme._guiPalette.text().color().getRgb() == (255, 255, 255, 255)
|
|
||||||
assert mainTheme._guiPalette.light().color().getRgb() == (57, 57, 57, 255)
|
|
||||||
assert mainTheme.isDarkTheme is True
|
|
||||||
|
|
||||||
# Load Default Light Theme
|
# Since window is black, a lighter version should be generated
|
||||||
# ========================
|
assert theme._guiPalette.light().color().getRgb() == (57, 57, 57, 255)
|
||||||
|
|
||||||
CONFIG.guiTheme = "default_light"
|
# Reload with project override to red
|
||||||
assert mainTheme.loadTheme() is True
|
CONFIG.iconColTree = "red"
|
||||||
|
CONFIG.iconColDocs = True
|
||||||
|
theme.loadTheme(force=True)
|
||||||
|
|
||||||
# Check a few values
|
assert theme.getBaseColor("root").getRgb() == (255, 0, 0, 255)
|
||||||
assert mainTheme._guiPalette.color(
|
assert theme.getBaseColor("folder").getRgb() == (255, 0, 0, 255)
|
||||||
QPalette.ColorRole.Window
|
assert theme.getBaseColor("file").getRgb() == (204, 204, 204, 255)
|
||||||
).getRgb() == (239, 239, 239, 255)
|
assert theme.getBaseColor("title").getRgb() == (0, 255, 0, 255)
|
||||||
assert mainTheme._guiPalette.color(
|
assert theme.getBaseColor("chapter").getRgb() == (255, 0, 0, 255)
|
||||||
QPalette.ColorRole.WindowText
|
assert theme.getBaseColor("scene").getRgb() == (0, 0, 255, 255)
|
||||||
).getRgb() == (0, 0, 0, 255)
|
assert theme.getBaseColor("note").getRgb() == (255, 255, 0, 255)
|
||||||
assert mainTheme._guiPalette.color(
|
|
||||||
QPalette.ColorRole.Base
|
|
||||||
).getRgb() == (255, 255, 255, 255)
|
|
||||||
assert mainTheme._guiPalette.color(
|
|
||||||
QPalette.ColorRole.AlternateBase
|
|
||||||
).getRgb() == (224, 224, 224, 255)
|
|
||||||
|
|
||||||
# Load Default Dark Theme
|
assert theme.getRawBaseColor("root") == b"#ff0000"
|
||||||
# =======================
|
assert theme.getRawBaseColor("folder") == b"#ff0000"
|
||||||
|
assert theme.getRawBaseColor("file") == b"#cccccc"
|
||||||
CONFIG.guiTheme = "default_dark"
|
assert theme.getRawBaseColor("title") == b"#00ff00"
|
||||||
assert mainTheme.loadTheme() is True
|
assert theme.getRawBaseColor("chapter") == b"#ff0000"
|
||||||
|
assert theme.getRawBaseColor("scene") == b"#0000ff"
|
||||||
# Check a few values
|
assert theme.getRawBaseColor("note") == b"#ffff00"
|
||||||
assert mainTheme._guiPalette.color(
|
|
||||||
QPalette.ColorRole.Window).getRgb() == (54, 54, 54, 255)
|
|
||||||
assert mainTheme._guiPalette.color(
|
|
||||||
QPalette.ColorRole.WindowText).getRgb() == (204, 204, 204, 255)
|
|
||||||
assert mainTheme._guiPalette.color(
|
|
||||||
QPalette.ColorRole.Base).getRgb() == (62, 62, 62, 255)
|
|
||||||
assert mainTheme._guiPalette.color(
|
|
||||||
QPalette.ColorRole.AlternateBase).getRgb() == (78, 78, 78, 255)
|
|
||||||
|
|
||||||
# qtbot.stop()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
|
||||||
def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI):
|
|
||||||
"""Test the syntax part of the class."""
|
|
||||||
mainTheme = SHARED.theme
|
|
||||||
|
|
||||||
# List Themes
|
|
||||||
# ===========
|
|
||||||
|
|
||||||
# Block the reading of the files
|
|
||||||
with monkeypatch.context() as mp:
|
|
||||||
mp.setattr("builtins.open", causeOSError)
|
|
||||||
assert mainTheme.listThemes() == []
|
|
||||||
|
|
||||||
# Load the syntax info
|
|
||||||
syntaxList = mainTheme.listSyntax()
|
|
||||||
assert syntaxList[0] == ("default_dark", "Default Dark")
|
|
||||||
assert syntaxList[1] == ("default_light", "Default Light")
|
|
||||||
|
|
||||||
# A second call should returned the cached list
|
|
||||||
assert mainTheme.listSyntax() == mainTheme._syntaxList
|
|
||||||
|
|
||||||
# Check handling of broken theme settings
|
|
||||||
availSyntax = mainTheme._availSyntax
|
|
||||||
mainTheme._availSyntax = {}
|
|
||||||
CONFIG.guiSyntax = "not_a_syntax"
|
|
||||||
assert mainTheme.loadSyntax() is False
|
|
||||||
mainTheme._availSyntax = availSyntax
|
|
||||||
|
|
||||||
# Check handling of unreadable file
|
|
||||||
CONFIG.guiSyntax = "default_light"
|
|
||||||
with monkeypatch.context() as mp:
|
|
||||||
mp.setattr("builtins.open", causeOSError)
|
|
||||||
assert mainTheme.loadSyntax() is False
|
|
||||||
|
|
||||||
# Load Default Light Syntax
|
|
||||||
# =========================
|
|
||||||
|
|
||||||
# Load the default syntax
|
|
||||||
CONFIG.guiSyntax = "default_light"
|
|
||||||
assert mainTheme.loadSyntax() is True
|
|
||||||
|
|
||||||
# Check some values
|
|
||||||
assert mainTheme.syntaxMeta.name == "Default Light"
|
|
||||||
assert mainTheme.syntaxTheme.back == QColor(255, 255, 255)
|
|
||||||
assert mainTheme.syntaxTheme.text == QColor(0, 0, 0)
|
|
||||||
assert mainTheme.syntaxTheme.link == QColor(0, 0, 200)
|
|
||||||
|
|
||||||
# Load Default Dark Theme
|
|
||||||
# =======================
|
|
||||||
|
|
||||||
# Load the default syntax
|
|
||||||
CONFIG.guiSyntax = "default_dark"
|
|
||||||
assert mainTheme.loadSyntax() is True
|
|
||||||
|
|
||||||
# Check some values
|
|
||||||
assert mainTheme.syntaxMeta.name == "Default Dark"
|
|
||||||
assert mainTheme.syntaxTheme.back == QColor(42, 42, 42)
|
|
||||||
assert mainTheme.syntaxTheme.text == QColor(204, 204, 204)
|
|
||||||
assert mainTheme.syntaxTheme.link == QColor(102, 153, 204)
|
|
||||||
|
|
||||||
# qtbot.stop()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
|
||||||
def testGuiTheme_IconThemes(qtbot, caplog, monkeypatch, nwGUI, tstPaths):
|
|
||||||
"""Test the icon cache class."""
|
|
||||||
iconCache = SHARED.theme.iconCache
|
|
||||||
|
|
||||||
# Load Theme
|
|
||||||
# ==========
|
|
||||||
|
|
||||||
# Invalid theme name
|
|
||||||
availThemes = iconCache._availThemes
|
|
||||||
iconCache._availThemes = {}
|
|
||||||
assert iconCache.loadTheme("not_a_theme") is False
|
|
||||||
iconCache._availThemes = availThemes
|
|
||||||
|
|
||||||
# Check handling of unreadable file
|
|
||||||
with monkeypatch.context() as mp:
|
|
||||||
mp.setattr("builtins.open", causeOSError)
|
|
||||||
assert iconCache.loadTheme("material_rounded_normal") is False
|
|
||||||
|
|
||||||
# Load working theme file
|
|
||||||
assert iconCache.loadTheme("material_rounded_normal") is True
|
|
||||||
assert iconCache.themeMeta.name == "Material Symbols - Rounded Medium"
|
|
||||||
|
|
||||||
# Load with project colour override
|
|
||||||
purple = iconCache._svgColors["purple"]
|
|
||||||
assert iconCache._svgColors["root"] != purple
|
|
||||||
assert iconCache._svgColors["folder"] != purple
|
|
||||||
assert iconCache._svgColors["file"] != purple
|
|
||||||
assert iconCache._svgColors["title"] != purple
|
|
||||||
assert iconCache._svgColors["chapter"] != purple
|
|
||||||
assert iconCache._svgColors["scene"] != purple
|
|
||||||
assert iconCache._svgColors["note"] != purple
|
|
||||||
|
|
||||||
|
# Reload with project override to purple, also for docs
|
||||||
CONFIG.iconColTree = "purple"
|
CONFIG.iconColTree = "purple"
|
||||||
assert iconCache.loadTheme("material_rounded_normal") is True
|
CONFIG.iconColDocs = False
|
||||||
assert iconCache._svgColors["root"] == purple
|
theme.loadTheme(force=True)
|
||||||
assert iconCache._svgColors["folder"] == purple
|
|
||||||
assert iconCache._svgColors["file"] == purple
|
|
||||||
assert iconCache._svgColors["title"] == purple
|
|
||||||
assert iconCache._svgColors["chapter"] == purple
|
|
||||||
assert iconCache._svgColors["scene"] == purple
|
|
||||||
assert iconCache._svgColors["note"] == purple
|
|
||||||
|
|
||||||
# Change some colours
|
assert theme.getBaseColor("root").getRgb() == (255, 0, 255, 255)
|
||||||
iconCache.setIconColor("root", QColor(255, 255, 255))
|
assert theme.getBaseColor("folder").getRgb() == (255, 0, 255, 255)
|
||||||
assert iconCache._svgColors["root"] != purple
|
assert theme.getBaseColor("file").getRgb() == (255, 0, 255, 255)
|
||||||
assert iconCache._svgColors["root"] == b"#ffffff"
|
assert theme.getBaseColor("title").getRgb() == (255, 0, 255, 255)
|
||||||
|
assert theme.getBaseColor("chapter").getRgb() == (255, 0, 255, 255)
|
||||||
|
assert theme.getBaseColor("scene").getRgb() == (255, 0, 255, 255)
|
||||||
|
assert theme.getBaseColor("note").getRgb() == (255, 0, 255, 255)
|
||||||
|
|
||||||
# List Themes
|
assert theme.getRawBaseColor("root") == b"#ff00ff"
|
||||||
# ===========
|
assert theme.getRawBaseColor("folder") == b"#ff00ff"
|
||||||
|
assert theme.getRawBaseColor("file") == b"#ff00ff"
|
||||||
# Load error returns empty list
|
assert theme.getRawBaseColor("title") == b"#ff00ff"
|
||||||
with monkeypatch.context() as mp:
|
assert theme.getRawBaseColor("chapter") == b"#ff00ff"
|
||||||
mp.setattr("builtins.open", causeOSError)
|
assert theme.getRawBaseColor("scene") == b"#ff00ff"
|
||||||
themes = iconCache.listThemes()
|
assert theme.getRawBaseColor("note") == b"#ff00ff"
|
||||||
assert themes == []
|
|
||||||
|
|
||||||
# Successful read
|
|
||||||
themes = iconCache.listThemes()
|
|
||||||
assert len(themes) > 1
|
|
||||||
assert "material_rounded_normal" in dict(themes)
|
|
||||||
|
|
||||||
# Load error doesn't matter on second read since list is cached
|
|
||||||
with monkeypatch.context() as mp:
|
|
||||||
mp.setattr("builtins.open", causeOSError)
|
|
||||||
assert iconCache.listThemes() == themes
|
|
||||||
|
|
||||||
# qtbot.stop()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiTheme_LoadIcons(qtbot, nwGUI):
|
def testGuiTheme_Methods(monkeypatch):
|
||||||
|
"""Test other themes methods."""
|
||||||
|
theme = GuiTheme()
|
||||||
|
theme.iconCache = MagicMock()
|
||||||
|
CONFIG.darkTheme = DEF_GUI_DARK
|
||||||
|
CONFIG.themeMode = nwTheme.DARK
|
||||||
|
|
||||||
|
# Init theme
|
||||||
|
assert theme.colourThemes == {}
|
||||||
|
theme.initThemes()
|
||||||
|
assert theme._meta.name == "Default Dark Theme"
|
||||||
|
|
||||||
|
# Text width
|
||||||
|
theme.guiFont = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
||||||
|
assert theme.getTextWidth("MMMMM") > theme.getTextWidth("MMM")
|
||||||
|
font = QFont(theme.guiFont)
|
||||||
|
font.setPointSizeF(0.5*font.pointSizeF())
|
||||||
|
assert theme.getTextWidth("MMMMM", font) < theme.getTextWidth("MMMMM")
|
||||||
|
|
||||||
|
# Detect desktop mode Qt 6.5+
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(CONFIG, "verQtValue", 0x060500)
|
||||||
|
|
||||||
|
mp.setattr(QStyleHints, "colorScheme", lambda *a: Qt.ColorScheme.Light)
|
||||||
|
assert theme.isDesktopDarkMode() is False
|
||||||
|
|
||||||
|
mp.setattr(QStyleHints, "colorScheme", lambda *a: Qt.ColorScheme.Dark)
|
||||||
|
assert theme.isDesktopDarkMode() is True
|
||||||
|
|
||||||
|
# Detect desktop mode Qt 6.4
|
||||||
|
mockWhite = Mock()
|
||||||
|
mockWhite.color.return_value = QColor(255, 255, 255)
|
||||||
|
|
||||||
|
mockBlack = Mock()
|
||||||
|
mockBlack.color.return_value = QColor(0, 0, 0)
|
||||||
|
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(CONFIG, "verQtValue", 0x060400)
|
||||||
|
|
||||||
|
mp.setattr(QPalette, "window", lambda *a: mockWhite)
|
||||||
|
mp.setattr(QPalette, "windowText", lambda *a: mockBlack)
|
||||||
|
assert theme.isDesktopDarkMode() is False
|
||||||
|
|
||||||
|
mp.setattr(QPalette, "window", lambda *a: mockBlack)
|
||||||
|
mp.setattr(QPalette, "windowText", lambda *a: mockWhite)
|
||||||
|
assert theme.isDesktopDarkMode() is True
|
||||||
|
|
||||||
|
# Stylesheets
|
||||||
|
assert theme.getStyleSheet(STYLES_FLAT_TABS) != ""
|
||||||
|
assert theme.getStyleSheet(STYLES_MIN_TOOLBUTTON) != ""
|
||||||
|
assert theme.getStyleSheet(STYLES_BIG_TOOLBUTTON) != ""
|
||||||
|
assert theme.getStyleSheet("stuff") == ""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiTheme_ScanIcons(monkeypatch):
|
||||||
|
"""Test the icon theme scanning."""
|
||||||
|
theme = GuiTheme()
|
||||||
|
|
||||||
|
# Load built-in themes
|
||||||
|
files = []
|
||||||
|
_listContent(files, CONFIG.assetPath("icons"), ".icons")
|
||||||
|
assert len(files) > 0
|
||||||
|
|
||||||
|
# Block reading theme files
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr("builtins.open", causeOSError)
|
||||||
|
theme.iconCache._scanThemes(files)
|
||||||
|
assert theme.iconCache.iconThemes == {}
|
||||||
|
|
||||||
|
# Read all themes correctly
|
||||||
|
theme.iconCache._scanThemes(files)
|
||||||
|
assert len(theme.iconCache.iconThemes) > 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiTheme_IconThemes(monkeypatch):
|
||||||
|
"""Test loading icon theme."""
|
||||||
|
CONFIG.lightTheme = DEF_GUI_LIGHT
|
||||||
|
CONFIG.themeMode = nwTheme.LIGHT
|
||||||
|
CONFIG.iconTheme = DEF_ICONS
|
||||||
|
|
||||||
|
theme = GuiTheme()
|
||||||
|
|
||||||
|
# Init should load default theme
|
||||||
|
theme.initThemes()
|
||||||
|
assert theme.iconCache._meta.name == "Material Symbols - Rounded Medium"
|
||||||
|
assert DEF_ICONS in theme.iconCache.iconThemes
|
||||||
|
|
||||||
|
# Load default theme directly
|
||||||
|
theme.iconCache._meta = ThemeMeta()
|
||||||
|
theme.iconCache.loadTheme("DEF_ICONS")
|
||||||
|
assert theme.iconCache._meta.name == "Material Symbols - Rounded Medium"
|
||||||
|
|
||||||
|
# Failed loading should load nothing
|
||||||
|
theme.iconCache._meta = ThemeMeta()
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr("builtins.open", causeOSError)
|
||||||
|
theme.iconCache.loadTheme("DEF_ICONS")
|
||||||
|
assert theme.iconCache._meta.name == ""
|
||||||
|
|
||||||
|
# Reload with non-existent theme should reload default
|
||||||
|
theme.iconCache._meta = ThemeMeta()
|
||||||
|
theme.iconCache.loadTheme("not_a_theme")
|
||||||
|
assert theme.iconCache._meta.name == "Material Symbols - Rounded Medium"
|
||||||
|
|
||||||
|
# If default theme is missing, load nothing
|
||||||
|
del theme.iconCache._allThemes[DEF_ICONS]
|
||||||
|
theme.iconCache._meta = ThemeMeta()
|
||||||
|
theme.iconCache.loadTheme("not_a_theme")
|
||||||
|
assert theme.iconCache._meta.name == ""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiTheme_LoadIcons():
|
||||||
"""Test the icon cache class."""
|
"""Test the icon cache class."""
|
||||||
iconCache = SHARED.theme.iconCache
|
theme = GuiTheme()
|
||||||
assert iconCache.loadTheme("material_rounded_normal") is True
|
theme.initThemes()
|
||||||
|
iconCache = theme.iconCache
|
||||||
|
|
||||||
# Load Icons
|
# Load Icons
|
||||||
# ==========
|
# ==========
|
||||||
@@ -455,14 +500,13 @@ def testGuiTheme_LoadIcons(qtbot, nwGUI):
|
|||||||
nwItemType.NO_TYPE, nwItemClass.NOVEL, nwItemLayout.DOCUMENT, hLevel="H0"
|
nwItemType.NO_TYPE, nwItemClass.NOVEL, nwItemLayout.DOCUMENT, hLevel="H0"
|
||||||
) == iconCache._noIcon
|
) == iconCache._noIcon
|
||||||
|
|
||||||
# qtbot.stop()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiTheme_LoadDecorations(qtbot, monkeypatch, nwGUI):
|
def testGuiTheme_LoadDecorations(monkeypatch):
|
||||||
"""Test the icon cache class."""
|
"""Test the icon cache class."""
|
||||||
iconCache = SHARED.theme.iconCache
|
theme = GuiTheme()
|
||||||
assert iconCache.loadTheme("material_rounded_normal") is True
|
theme.initThemes()
|
||||||
|
iconCache = theme.iconCache
|
||||||
|
|
||||||
# Load Decorations
|
# Load Decorations
|
||||||
# ================
|
# ================
|
||||||
@@ -519,5 +563,3 @@ def testGuiTheme_LoadDecorations(qtbot, monkeypatch, nwGUI):
|
|||||||
assert iconCache.getHeaderDecorationNarrow(4) == iconCache._headerDecNarrow[4]
|
assert iconCache.getHeaderDecorationNarrow(4) == iconCache._headerDecNarrow[4]
|
||||||
assert iconCache.getHeaderDecorationNarrow(5) == iconCache._headerDecNarrow[5]
|
assert iconCache.getHeaderDecorationNarrow(5) == iconCache._headerDecNarrow[5]
|
||||||
assert iconCache.getHeaderDecorationNarrow(6) == iconCache._headerDecNarrow[5]
|
assert iconCache.getHeaderDecorationNarrow(6) == iconCache._headerDecNarrow[5]
|
||||||
|
|
||||||
# qtbot.stop()
|
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ ICONS = [
|
|||||||
"sb_search",
|
"sb_search",
|
||||||
"sb_stats",
|
"sb_stats",
|
||||||
|
|
||||||
|
"theme_light",
|
||||||
|
"theme_dark",
|
||||||
|
"theme_auto",
|
||||||
|
|
||||||
"add",
|
"add",
|
||||||
"bookmarks",
|
"bookmarks",
|
||||||
"browse",
|
"browse",
|
||||||
|
|||||||
@@ -56,6 +56,10 @@
|
|||||||
"sb_search": "magnifying-glass",
|
"sb_search": "magnifying-glass",
|
||||||
"sb_stats": "chart-simple",
|
"sb_stats": "chart-simple",
|
||||||
|
|
||||||
|
"theme_light": "sun",
|
||||||
|
"theme_dark": "moon",
|
||||||
|
"theme_auto": "circle-half-stroke",
|
||||||
|
|
||||||
"add": "plus",
|
"add": "plus",
|
||||||
"bookmarks": "bookmark",
|
"bookmarks": "bookmark",
|
||||||
"browse": "folder-open",
|
"browse": "folder-open",
|
||||||
|
|||||||
@@ -56,6 +56,10 @@
|
|||||||
"sb_search": "search",
|
"sb_search": "search",
|
||||||
"sb_stats": "bar_chart",
|
"sb_stats": "bar_chart",
|
||||||
|
|
||||||
|
"theme_light": "light_mode",
|
||||||
|
"theme_dark": "dark_mode",
|
||||||
|
"theme_auto": "contrast",
|
||||||
|
|
||||||
"add": "add",
|
"add": "add",
|
||||||
"bookmarks": "bookmarks",
|
"bookmarks": "bookmarks",
|
||||||
"browse": "folder_open",
|
"browse": "folder_open",
|
||||||
|
|||||||
@@ -56,6 +56,10 @@
|
|||||||
"sb_search": "file-search",
|
"sb_search": "file-search",
|
||||||
"sb_stats": "bar-chart-fill",
|
"sb_stats": "bar-chart-fill",
|
||||||
|
|
||||||
|
"theme_light": "sun",
|
||||||
|
"theme_dark": "moon",
|
||||||
|
"theme_auto": "contrast",
|
||||||
|
|
||||||
"add": "add",
|
"add": "add",
|
||||||
"bookmarks": "bookmark",
|
"bookmarks": "bookmark",
|
||||||
"browse": "folder-2",
|
"browse": "folder-2",
|
||||||
|
|||||||
Reference in New Issue
Block a user