Compare commits

...

7 Commits

Author SHA1 Message Date
Adam Treat c7b0812d1f This is a draft PR. It reflects a lot of major new ui redesign work that
follows the new FIGMA design made by Vincent. It also contains a lot of
changes to the way localdocs works.

This is now rebased on top of main and conflicts resolved. This is still
a monolithic commit that needs to be broken up into smaller pieces in order
to aid proper review. I'll be working on that now and force pushing as I
do so.

Signed-off-by: Adam Treat <treat.adam@gmail.com>
3 weeks ago
Adam Treat 42615ea4be Add several new icons and change current set.
Signed-off-by: Adam Treat <treat.adam@gmail.com>
3 weeks ago
Adam Treat f888a9f548 Large update to localdocs with many moving parts. This commit is a breaking
change that requires re-indexing of all collections.

- Adds a general mechanism for handling breaking changes to localdocs database
  upgrades

- Upgrades the database format to version 2 and includes numerous changes to
  the underlying tables including:
    a) adds word and token count fields for chunk table
    b) adds a boolean field indicating whether the chunk has a generated embedding
    c) adds a last updated time field for collection table which can be displayed in GUI
    d) adds an embedding model field for collection table
    e) adds a boolean field for collection table to allow forced re-indexing

- Adds several statistics about the collection which can be displayed in GUI
    a) total documents
    b) total words
    c) total tokens
    d) last updated time
    e) which document is currently being indexed
    f) which document is currently being embedded
    g) which model is being used to generate embeddings for the collection

- Simplifies communication between the database thread and the GUI thread
  removing a lot of extra code and makes clear what methods/signals in database
  class are soley used for communicating state to the GUI

- Provides a pool for sending embedding requests to the embedding thread to
  increase speed of embedding when the chunks per document are small

- Provides a mechanism for resuming indexing/embedding when the app shutsdown
  or crashes in the middle of indexing/embedding

NOTE: This change is part of a larger set of commits, but can be built and
compiles up to this point
3 weeks ago
Adam Treat 6597a464b9 Remove the debug example in database as it's now too simplistic and out of date.
Signed-off-by: Adam Treat <treat.adam@gmail.com>
3 weeks ago
Adam Treat 3221b5787e Add a FIXME for the current hardcoding of the dimension for the index.
Signed-off-by: Adam Treat <treat.adam@gmail.com>
3 weeks ago
Adam Treat d6d3481a78 Back out some of the changes that were added to localdocs to support sending
mixpanel events. These changes added complexity to the Database code which
we're looking to simplify not increase complexity and all info that we care
about from mixpanel should be available from the GUI thread.

NOTE: This change will not compile by itself. It must be included with subsequent
changes made in PR #2302 but is here broken out into a standalone commit
to aid in review.

Signed-off-by: Adam Treat <treat.adam@gmail.com>
3 weeks ago
Adam Treat f40e9c1d33 Fix destruction and tear down of the embedding thread.
Signed-off-by: Adam Treat <treat.adam@gmail.com>
3 weeks ago

@ -103,11 +103,12 @@ qt_add_qml_module(chat
qml/ChatDrawer.qml
qml/ChatView.qml
qml/CollectionsDialog.qml
qml/ModelDownloaderDialog.qml
qml/HomeView.qml
qml/ModelDownloaderView.qml
qml/NetworkDialog.qml
qml/NewVersionDialog.qml
qml/ThumbsDownDialog.qml
qml/SettingsDialog.qml
qml/SettingsView.qml
qml/StartupDialog.qml
qml/PopupDialog.qml
qml/AboutDialog.qml
@ -115,6 +116,7 @@ qt_add_qml_module(chat
qml/ModelSettings.qml
qml/ApplicationSettings.qml
qml/LocalDocsSettings.qml
qml/LocalDocsView.qml
qml/SwitchModelDialog.qml
qml/MySettingsTab.qml
qml/MySettingsStack.qml
@ -126,28 +128,42 @@ qt_add_qml_module(chat
qml/MyComboBox.qml
qml/MyDialog.qml
qml/MyDirectoryField.qml
qml/MyFancyLink.qml
qml/MyTextArea.qml
qml/MyTextField.qml
qml/MyCheckBox.qml
qml/MyBusyIndicator.qml
qml/MyMiniButton.qml
qml/MyToolButton.qml
qml/MyWelcomeButton.qml
RESOURCES
icons/send_message.svg
icons/stop_generating.svg
icons/regenerate.svg
icons/chat.svg
icons/changelog.svg
icons/close.svg
icons/copy.svg
icons/db.svg
icons/discord.svg
icons/download.svg
icons/settings.svg
icons/eject.svg
icons/edit.svg
icons/github.svg
icons/globe.svg
icons/home.svg
icons/image.svg
icons/info.svg
icons/local-docs.svg
icons/models.svg
icons/nomic_logo.svg
icons/search.svg
icons/trash.svg
icons/network.svg
icons/thumbs_up.svg
icons/thumbs_down.svg
icons/twitter.svg
icons/left_panel_closed.svg
icons/left_panel_open.svg
icons/logo.svg

File diff suppressed because it is too large Load Diff

@ -41,15 +41,26 @@ struct CollectionItem {
QString collection;
QString folder_path;
int folder_id = -1;
bool installed = false;
bool indexing = false;
QString error;
int currentDocsToIndex = 0;
int totalDocsToIndex = 0;
size_t currentBytesToIndex = 0;
size_t totalBytesToIndex = 0;
size_t currentEmbeddingsToIndex = 0;
size_t totalEmbeddingsToIndex = 0;
bool installed = false; // not database
bool indexing = false; // not database
bool forceIndexing = false;
QString error; // not database
// progress
int currentDocsToIndex = 0; // not database
int totalDocsToIndex = 0; // not database
size_t currentBytesToIndex = 0; // not database
size_t totalBytesToIndex = 0; // not database
size_t currentEmbeddingsToIndex = 0; // not database
size_t totalEmbeddingsToIndex = 0; // not database
// statistics
size_t totalDocs = 0;
size_t totalWords = 0;
size_t totalTokens = 0;
QDateTime lastUpdate;
QString fileCurrentlyProcessing;
QString embeddingModel;
};
Q_DECLARE_METATYPE(CollectionItem)
@ -63,45 +74,38 @@ public:
public Q_SLOTS:
void start();
void scanQueue();
void scanDocuments(int folder_id, const QString &folder_path, bool isNew);
bool addFolder(const QString &collection, const QString &path, bool fromDb);
void scanDocuments(int folder_id, const QString &folder_path);
void forceIndexing(const QString &collection);
void addFolder(const QString &collection, const QString &path);
void removeFolder(const QString &collection, const QString &path);
void retrieveFromDB(const QList<QString> &collections, const QString &text, int retrievalSize, QList<ResultInfo> *results);
void cleanDB();
void changeChunkSize(int chunkSize);
Q_SIGNALS:
void docsToScanChanged();
void updateInstalled(int folder_id, bool b);
void updateIndexing(int folder_id, bool b);
void updateError(int folder_id, const QString &error);
void updateCurrentDocsToIndex(int folder_id, size_t currentDocsToIndex);
void updateTotalDocsToIndex(int folder_id, size_t totalDocsToIndex);
void subtractCurrentBytesToIndex(int folder_id, size_t subtractedBytes);
void updateCurrentBytesToIndex(int folder_id, size_t currentBytesToIndex);
void updateTotalBytesToIndex(int folder_id, size_t totalBytesToIndex);
void updateCurrentEmbeddingsToIndex(int folder_id, size_t currentBytesToIndex);
void updateTotalEmbeddingsToIndex(int folder_id, size_t totalBytesToIndex);
void addCollectionItem(const CollectionItem &item, bool fromDb);
void removeFolderById(int folder_id);
void collectionListUpdated(const QList<CollectionItem> &collectionList);
// Signals for the gui only
void requestUpdateGuiForCollectionItem(const CollectionItem &item);
void requestAddGuiCollectionItem(const CollectionItem &item);
void requestRemoveGuiFolderById(int folder_id);
void requestGuiCollectionListUpdated(const QList<CollectionItem> &collectionList);
private Q_SLOTS:
void directoryChanged(const QString &path);
bool addFolderToWatch(const QString &path);
bool removeFolderFromWatch(const QString &path);
int addCurrentFolders();
void addCurrentFolders();
void handleEmbeddingsGenerated(const QVector<EmbeddingResult> &embeddings);
void handleErrorGenerated(int folder_id, const QString &error);
private:
enum class FolderStatus { Started, Embedding, Complete };
struct FolderStatusRecord { qint64 startTime; bool isNew; int numDocs, docsChanged, chunksRead; };
QSqlError initDb();
void addForcedCollection(const CollectionItem &collection);
void removeFolderInternal(const QString &collection, int folder_id, const QString &path);
size_t chunkStream(QTextStream &stream, int folder_id, int document_id, const QString &file,
const QString &title, const QString &author, const QString &subject, const QString &keywords, int page,
int maxChunks = -1);
void appendChunk(const EmbeddingChunk &chunk);
void sendChunkList();
void removeEmbeddingsByDocumentId(int document_id);
void scheduleNext(int folder_id, size_t countForFolder);
void handleDocumentError(const QString &errorMessage,
@ -112,20 +116,26 @@ private:
void removeFolderFromDocumentQueue(int folder_id);
void enqueueDocumentInternal(const DocumentInfo &info, bool prepend = false);
void enqueueDocuments(int folder_id, const QVector<DocumentInfo> &infos);
void updateIndexingStatus();
void updateFolderStatus(int folder_id, FolderStatus status, int numDocs = -1, bool atStart = false, bool isNew = false);
CollectionItem guiCollectionItem(int folder_id) const;
void updateGuiForCollectionItem(const CollectionItem &item);
void addGuiCollectionItem(const CollectionItem &item);
void removeGuiFolderById(int folder_id);
void guiCollectionListUpdated(const QList<CollectionItem> &collectionList);
void scheduleUncompletedEmbeddings(int folder_id);
void updateCollectionStatistics();
private:
int m_chunkSize;
QTimer *m_scanTimer;
QMap<int, QQueue<DocumentInfo>> m_docsToScan;
QElapsedTimer m_indexingTimer;
QMap<int, FolderStatusRecord> m_foldersBeingIndexed;
QList<ResultInfo> m_retrieve;
QThread m_dbThread;
QFileSystemWatcher *m_watcher;
EmbeddingLLM *m_embLLM;
Embeddings *m_embeddings;
QVector<EmbeddingChunk> m_chunkList;
QHash<int, CollectionItem> m_collectionMap; // used only for tracking indexing/embedding progress
};
#endif // DATABASE_H

@ -62,6 +62,8 @@ ReleaseInfo Download::releaseInfo() const
const QString currentVersion = QCoreApplication::applicationVersion();
if (m_releaseMap.contains(currentVersion))
return m_releaseMap.value(currentVersion);
if (!m_releaseMap.empty())
return m_releaseMap.last();
return ReleaseInfo();
}

@ -9,6 +9,8 @@
#define EMBEDDINGS_VERSION 0
// FIXME!!!!! We can't hardcode like this for different embedding models
const int s_dim = 384; // Dimension of the elements
const int s_ef_construction = 200; // Controls index search speed/build speed tradeoff
const int s_M = 16; // Tightly connected with internal dimensionality of the data

@ -5,6 +5,7 @@ EmbeddingLLMWorker::EmbeddingLLMWorker()
: QObject(nullptr)
, m_networkManager(new QNetworkAccessManager(this))
, m_model(nullptr)
, m_stopGenerating(false)
{
moveToThread(&m_workerThread);
connect(this, &EmbeddingLLMWorker::finished, &m_workerThread, &QThread::quit, Qt::DirectConnection);
@ -14,6 +15,10 @@ EmbeddingLLMWorker::EmbeddingLLMWorker()
EmbeddingLLMWorker::~EmbeddingLLMWorker()
{
m_stopGenerating = true;
m_workerThread.quit();
m_workerThread.wait();
if (m_model) {
delete m_model;
m_model = nullptr;
@ -148,6 +153,9 @@ void EmbeddingLLMWorker::requestSyncEmbedding(const QString &text)
// this function is always called for storage into the database
void EmbeddingLLMWorker::requestAsyncEmbedding(const QVector<EmbeddingChunk> &chunks)
{
if (m_stopGenerating)
return;
if (!hasModel() && !loadModel()) {
qWarning() << "WARNING: Could not load model for embeddings";
return;
@ -295,6 +303,20 @@ EmbeddingLLM::~EmbeddingLLM()
m_embeddingWorker = nullptr;
}
QString EmbeddingLLM::model() const
{
const EmbeddingModels *embeddingModels = ModelList::globalInstance()->installedEmbeddingModels();
if (!embeddingModels->count())
return QString("Unknown");
const ModelInfo defaultModel = embeddingModels->defaultModelInfo();
if (!defaultModel.name().isEmpty())
return defaultModel.name();
else if (!defaultModel.id().isEmpty())
return defaultModel.id();
return defaultModel.filename();
}
std::vector<float> EmbeddingLLM::generateEmbeddings(const QString &text)
{
if (!m_embeddingWorker->hasModel() && !m_embeddingWorker->loadModel()) {

@ -58,6 +58,7 @@ private:
QNetworkAccessManager *m_networkManager;
std::vector<float> m_lastResponse;
LLModel *m_model = nullptr;
std::atomic<bool> m_stopGenerating;
QThread m_workerThread;
};
@ -68,6 +69,7 @@ public:
EmbeddingLLM();
virtual ~EmbeddingLLM();
QString model() const;
bool loadModel();
bool hasModel() const;

@ -0,0 +1,3 @@
<svg width="30" height="24" viewBox="0 0 30 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M25.5 14.5C25.5 14.7967 25.412 15.0867 25.2472 15.3334C25.0824 15.58 24.8481 15.7723 24.574 15.8858C24.2999 15.9993 23.9983 16.0291 23.7074 15.9712C23.4164 15.9133 23.1491 15.7704 22.9393 15.5607C22.7296 15.3509 22.5867 15.0836 22.5288 14.7926C22.4709 14.5017 22.5007 14.2001 22.6142 13.926C22.7277 13.6519 22.92 13.4176 23.1666 13.2528C23.4133 13.088 23.7033 13 24 13C24.3978 13 24.7794 13.158 25.0607 13.4393C25.342 13.7206 25.5 14.1022 25.5 14.5ZM30 14.5C30 19.5462 27.365 23.5 24 23.5H6C2.635 23.5 0 19.5462 0 14.5C0 9.45375 2.635 5.5 6 5.5H10.5863L15.2925 0.7925C15.3854 0.699666 15.4958 0.626052 15.6171 0.575864C15.7385 0.525676 15.8686 0.499897 16 0.5H20C20.2652 0.5 20.5196 0.605357 20.7071 0.792893C20.8946 0.98043 21 1.23478 21 1.5C21 1.76522 20.8946 2.01957 20.7071 2.20711C20.5196 2.39464 20.2652 2.5 20 2.5H16.4137L13.4137 5.5H24C27.365 5.5 30 9.45375 30 14.5ZM6 21.5H20.1887C19.4791 20.607 18.942 19.5897 18.605 18.5H9C8.73478 18.5 8.48043 18.3946 8.29289 18.2071C8.10536 18.0196 8 17.7652 8 17.5C8 17.2348 8.10536 16.9804 8.29289 16.7929C8.48043 16.6054 8.73478 16.5 9 16.5H18.145C18.0483 15.8377 17.9999 15.1693 18 14.5C18 11.6425 18.845 9.1375 20.1887 7.5H6C4.44125 7.5 3.05625 9.1575 2.4 11.5H12C12.2652 11.5 12.5196 11.6054 12.7071 11.7929C12.8946 11.9804 13 12.2348 13 12.5C13 12.7652 12.8946 13.0196 12.7071 13.2071C12.5196 13.3946 12.2652 13.5 12 13.5H2.04375C2.01542 13.8275 2.00083 14.1608 2 14.5C2 18.295 3.83125 21.5 6 21.5ZM28 14.5C28 10.705 26.1688 7.5 24 7.5C21.8312 7.5 20 10.705 20 14.5C20 18.295 21.8312 21.5 24 21.5C26.1688 21.5 28 18.295 28 14.5Z" fill="#8F7676"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M26.1538 9.76H22.4615V5.92C22.4615 5.41078 22.267 4.92242 21.9208 4.56235C21.5746 4.20229 21.105 4 20.6154 4H5.84615C5.35652 4 4.88695 4.20229 4.54073 4.56235C4.1945 4.92242 4 5.41078 4 5.92V21.28C4.00054 21.4606 4.05006 21.6374 4.14287 21.79C4.23568 21.9427 4.36801 22.065 4.52467 22.143C4.68132 22.2209 4.85595 22.2513 5.02847 22.2307C5.201 22.2101 5.36444 22.1393 5.5 22.0264L9.53846 18.64V22.24C9.53846 22.7492 9.73297 23.2376 10.0792 23.5976C10.4254 23.9577 10.895 24.16 11.3846 24.16H22.1835L26.5 27.7864C26.6633 27.9238 26.8668 27.9991 27.0769 28C27.3217 28 27.5565 27.8989 27.7296 27.7188C27.9027 27.5388 28 27.2946 28 27.04V11.68C28 11.1708 27.8055 10.6824 27.4593 10.3224C27.1131 9.96229 26.6435 9.76 26.1538 9.76ZM8.90962 16.6936L5.84615 19.27V5.92H20.6154V16.48H9.49C9.27874 16.48 9.07387 16.5554 8.90962 16.6936ZM26.1538 25.03L23.0904 22.4536C22.9271 22.3162 22.7235 22.2408 22.5135 22.24H11.3846V18.4H20.6154C21.105 18.4 21.5746 18.1977 21.9208 17.8376C22.267 17.4776 22.4615 16.9892 22.4615 16.48V11.68H26.1538V25.03Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -1,5 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#7d7d8e" viewBox="0 0 448 512"><path d="M448 80v48c0 44.2-100.3 80-224 80S0 172.2 0 128V80C0 35.8 100.3 0 224 0S448 35.8 448 80zM393.2 214.7c20.8-7.4 39.9-16.9 54.8-28.6V288c0 44.2-100.3 80-224 80S0 332.2 0 288V186.1c14.9 11.8 34 21.2 54.8 28.6C99.7 230.7 159.5 240 224 240s124.3-9.3 169.2-25.3zM0 346.1c14.9 11.8 34 21.2 54.8 28.6C99.7 390.7 159.5 400 224 400s124.3-9.3 169.2-25.3c20.8-7.4 39.9-16.9 54.8-28.6V432c0 44.2-100.3 80-224 80S0 476.2 0 432V346.1z"/></svg>
<!--
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 3C9.27125 3 4 6.075 4 10V22C4 25.925 9.27125 29 16 29C22.7288 29 28 25.925 28 22V10C28 6.075 22.7288 3 16 3ZM26 16C26 17.2025 25.015 18.4287 23.2987 19.365C21.3662 20.4187 18.7738 21 16 21C13.2262 21 10.6338 20.4187 8.70125 19.365C6.985 18.4287 6 17.2025 6 16V13.92C8.1325 15.795 11.7787 17 16 17C20.2213 17 23.8675 15.79 26 13.92V16ZM8.70125 6.635C10.6338 5.58125 13.2262 5 16 5C18.7738 5 21.3662 5.58125 23.2987 6.635C25.015 7.57125 26 8.7975 26 10C26 11.2025 25.015 12.4287 23.2987 13.365C21.3662 14.4187 18.7738 15 16 15C13.2262 15 10.6338 14.4187 8.70125 13.365C6.985 12.4287 6 11.2025 6 10C6 8.7975 6.985 7.57125 8.70125 6.635ZM23.2987 25.365C21.3662 26.4187 18.7738 27 16 27C13.2262 27 10.6338 26.4187 8.70125 25.365C6.985 24.4287 6 23.2025 6 22V19.92C8.1325 21.795 11.7787 23 16 23C20.2213 23 23.8675 21.79 26 19.92V22C26 23.2025 25.015 24.4287 23.2987 25.365Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 689 B

After

Width:  |  Height:  |  Size: 1001 B

@ -0,0 +1,3 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M25.9996 34.9998C25.9996 35.5931 25.8236 36.1731 25.494 36.6665C25.1644 37.1598 24.6958 37.5444 24.1476 37.7714C23.5995 37.9985 22.9963 38.0579 22.4143 37.9421C21.8324 37.8264 21.2978 37.5407 20.8783 37.1211C20.4587 36.7015 20.173 36.167 20.0572 35.5851C19.9415 35.0031 20.0009 34.3999 20.228 33.8517C20.455 33.3036 20.8395 32.835 21.3329 32.5054C21.8262 32.1757 22.4062 31.9998 22.9996 31.9998C23.7952 31.9998 24.5583 32.3159 25.1209 32.8785C25.6835 33.4411 25.9996 34.2041 25.9996 34.9998ZM40.9996 31.9998C40.4062 31.9998 39.8262 32.1757 39.3329 32.5054C38.8395 32.835 38.455 33.3036 38.228 33.8517C38.0009 34.3999 37.9415 35.0031 38.0572 35.5851C38.173 36.167 38.4587 36.7015 38.8783 37.1211C39.2978 37.5407 39.8324 37.8264 40.4143 37.9421C40.9963 38.0579 41.5995 37.9985 42.1476 37.7714C42.6958 37.5444 43.1644 37.1598 43.494 36.6665C43.8236 36.1731 43.9996 35.5931 43.9996 34.9998C43.9996 34.2041 43.6835 33.4411 43.1209 32.8785C42.5583 32.3159 41.7952 31.9998 40.9996 31.9998ZM59.6121 48.2248L42.8621 55.6523C42.3584 55.8762 41.8143 55.9947 41.2632 56.0006C40.712 56.0065 40.1655 55.8997 39.6572 55.6866C39.1488 55.4735 38.6894 55.1588 38.3072 54.7616C37.925 54.3645 37.6281 53.8934 37.4346 53.3773L35.4071 47.8773C34.2871 47.9523 33.1513 47.9906 31.9996 47.9923C30.8479 47.994 29.7121 47.9556 28.5921 47.8773L26.5646 53.3773C26.3708 53.8932 26.0737 54.364 25.6914 54.761C25.3092 55.1579 24.8498 55.4725 24.3416 55.6855C23.8333 55.8986 23.2869 56.0055 22.7359 55.9998C22.1849 55.9941 21.6408 55.8758 21.1371 55.6523L4.38709 48.2248C3.52256 47.8468 2.82032 47.1741 2.4055 46.3266C1.99069 45.4792 1.89025 44.5119 2.12209 43.5973L9.49959 14.4998C9.69429 13.7431 10.1054 13.0595 10.6827 12.5329C11.2599 12.0063 11.9782 11.6594 12.7496 11.5348L21.7646 10.0523C22.7584 9.89244 23.7761 10.1079 24.6199 10.6569C25.4636 11.2058 26.073 12.0489 26.3296 13.0223L27.1446 16.2323C28.7329 16.0773 30.3513 15.9998 31.9996 15.9998C33.6479 15.9998 35.2646 16.0773 36.8496 16.2323L37.6646 13.0223C37.9206 12.0486 38.5299 11.2052 39.3738 10.6561C40.2177 10.1071 41.2357 9.89186 42.2296 10.0523L51.2496 11.5348C52.021 11.6594 52.7392 12.0063 53.3165 12.5329C53.8937 13.0595 54.3049 13.7431 54.4996 14.4998L61.8821 43.5948C62.1142 44.5104 62.0134 45.4787 61.5976 46.3268C61.1818 47.1749 60.4781 47.8476 59.6121 48.2248ZM57.9996 44.5698L50.6171 15.4998C50.6171 15.4998 50.6171 15.4998 50.5971 15.4998L41.5821 13.9998C41.5756 13.9961 41.5683 13.9941 41.5608 13.9941C41.5534 13.9941 41.5461 13.9961 41.5396 13.9998L40.8321 16.7848C42.0821 17.0198 43.3321 17.2998 44.5396 17.6398C45.0156 17.7611 45.4304 18.0535 45.7047 18.461C45.9791 18.8686 46.0938 19.3628 46.027 19.8496C45.9603 20.3363 45.7167 20.7814 45.3428 21.1001C44.9689 21.4187 44.4907 21.5886 43.9996 21.5773C43.817 21.5768 43.6354 21.5515 43.4596 21.5023C39.7245 20.4887 35.8698 19.9834 31.9996 19.9998C28.1295 19.9825 24.2748 20.4871 20.5396 21.4998C20.2844 21.5787 20.0161 21.6056 19.7503 21.5791C19.4845 21.5526 19.2268 21.4731 18.9922 21.3454C18.7577 21.2176 18.5511 21.0442 18.3847 20.8353C18.2182 20.6264 18.0953 20.3864 18.0232 20.1292C17.9511 19.872 17.9312 19.6031 17.9647 19.3381C17.9982 19.0731 18.0844 18.8175 18.2183 18.5864C18.3522 18.3554 18.531 18.1534 18.7442 17.9925C18.9574 17.8317 19.2006 17.7151 19.4596 17.6498C20.6646 17.3098 21.9046 17.0298 23.1646 16.7948L22.4571 13.9998C22.4571 13.9998 22.4571 13.9998 22.4271 13.9998L13.4021 15.4823C13.3947 15.4803 13.387 15.4803 13.3796 15.4823L5.99959 44.5823L22.7496 51.9998C22.758 52.0044 22.7675 52.0068 22.7771 52.0068C22.7867 52.0068 22.7962 52.0044 22.8046 51.9998L24.4996 47.4298C22.8013 47.17 21.12 46.8094 19.4646 46.3498C18.9715 46.1922 18.5587 45.8497 18.313 45.3941C18.0673 44.9385 18.0078 44.4054 18.147 43.9068C18.2862 43.4082 18.6133 42.9831 19.0595 42.7207C19.5057 42.4583 20.0362 42.3791 20.5396 42.4998C24.2746 43.5137 28.1295 44.0182 31.9996 43.9998C35.8697 44.0182 39.7246 43.5137 43.4596 42.4998C43.9705 42.3566 44.5173 42.4222 44.9798 42.6821C45.4423 42.9421 45.7826 43.3752 45.9258 43.886C46.0691 44.3969 46.0035 44.9438 45.7435 45.4063C45.4835 45.8688 45.0505 46.2091 44.5396 46.3523C42.8825 46.8112 41.1995 47.171 39.4996 47.4298L41.1871 51.9998C41.1951 52.0042 41.2042 52.0065 41.2133 52.0065C41.2225 52.0065 41.2315 52.0042 41.2396 51.9998L57.9996 44.5698Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

@ -1,5 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#7d7d8e" viewBox="0 0 576 512"><path d="M402.6 83.2l90.2 90.2c3.8 3.8 3.8 10 0 13.8L274.4 405.6l-92.8 10.3c-12.4 1.4-22.9-9.1-21.5-21.5l10.3-92.8L388.8 83.2c3.8-3.8 10-3.8 13.8 0zm162-22.9l-48.8-48.8c-15.2-15.2-39.9-15.2-55.2 0l-35.4 35.4c-3.8 3.8-3.8 10 0 13.8l90.2 90.2c3.8 3.8 10 3.8 13.8 0l35.4-35.4c15.2-15.3 15.2-40 0-55.2zM384 346.2V448H64V128h229.8c3.2 0 6.2-1.3 8.5-3.5l40-40c7.6-7.6 2.2-20.5-8.5-20.5H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V306.2c0-10.7-12.9-16-20.5-8.5l-40 40c-2.2 2.3-3.5 5.3-3.5 8.5z"/></svg>
<!--
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M28.4138 9.17125L22.8288 3.585C22.643 3.39924 22.4225 3.25188 22.1799 3.15134C21.9372 3.0508 21.6771 2.99905 21.4144 2.99905C21.1517 2.99905 20.8916 3.0508 20.6489 3.15134C20.4062 3.25188 20.1857 3.39924 20 3.585L4.58626 19C4.39973 19.185 4.25185 19.4053 4.15121 19.648C4.05057 19.8907 3.99917 20.151 4.00001 20.4138V26C4.00001 26.5304 4.21072 27.0391 4.5858 27.4142C4.96087 27.7893 5.46958 28 6.00001 28H11.5863C11.849 28.0008 12.1093 27.9494 12.352 27.8488C12.5947 27.7482 12.815 27.6003 13 27.4138L28.4138 12C28.5995 11.8143 28.7469 11.5938 28.8474 11.3511C28.948 11.1084 28.9997 10.8483 28.9997 10.5856C28.9997 10.3229 28.948 10.0628 28.8474 9.82015C28.7469 9.57747 28.5995 9.35698 28.4138 9.17125ZM6.41376 20L17 9.41375L19.0863 11.5L8.50001 22.085L6.41376 20ZM6.00001 22.4138L9.58626 26H6.00001V22.4138ZM12 25.5863L9.91376 23.5L20.5 12.9138L22.5863 15L12 25.5863ZM24 13.5863L18.4138 8L21.4138 5L27 10.585L24 13.5863Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 778 B

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,10 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_291_4849)">
<path d="M52.0775 18.92C52.6888 16.948 52.8849 14.8707 52.6534 12.8192C52.4219 10.7676 51.7679 8.78624 50.7325 7.00003C50.5569 6.69593 50.3044 6.44341 50.0003 6.26787C49.6961 6.09233 49.3511 5.99995 49 6.00003C46.6705 5.99516 44.3721 6.53519 42.2885 7.57699C40.2049 8.6188 38.3938 10.1335 37 12H31C29.6062 10.1335 27.7951 8.6188 25.7115 7.57699C23.6279 6.53519 21.3295 5.99516 19 6.00003C18.6489 5.99995 18.3039 6.09233 17.9997 6.26787C17.6956 6.44341 17.4431 6.69593 17.2675 7.00003C16.2321 8.78624 15.5781 10.7676 15.3466 12.8192C15.1151 14.8707 15.3112 16.948 15.9225 18.92C14.6868 21.0768 14.0249 23.5145 14 26V28C14.0042 31.384 15.2327 34.6523 17.4586 37.2012C19.6844 39.7501 22.7574 41.4076 26.11 41.8675C24.7415 43.6187 23.9987 45.7776 24 48V50H18C16.4087 50 14.8826 49.3679 13.7574 48.2427C12.6321 47.1175 12 45.5913 12 44C12 42.6868 11.7413 41.3865 11.2388 40.1732C10.7362 38.9599 9.99965 37.8576 9.07107 36.929C8.14248 36.0004 7.04009 35.2638 5.82683 34.7612C4.61358 34.2587 3.31322 34 2 34C1.46957 34 0.960859 34.2107 0.585786 34.5858C0.210714 34.9609 0 35.4696 0 36C0 36.5305 0.210714 37.0392 0.585786 37.4143C0.960859 37.7893 1.46957 38 2 38C3.5913 38 5.11742 38.6322 6.24264 39.7574C7.36786 40.8826 8 42.4087 8 44C8 46.6522 9.05357 49.1957 10.9289 51.0711C12.8043 52.9465 15.3478 54 18 54H24V58C24 58.5305 24.2107 59.0392 24.5858 59.4143C24.9609 59.7893 25.4696 60 26 60C26.5304 60 27.0391 59.7893 27.4142 59.4143C27.7893 59.0392 28 58.5305 28 58V48C28 46.4087 28.6321 44.8826 29.7574 43.7574C30.8826 42.6322 32.4087 42 34 42C35.5913 42 37.1174 42.6322 38.2426 43.7574C39.3679 44.8826 40 46.4087 40 48V58C40 58.5305 40.2107 59.0392 40.5858 59.4143C40.9609 59.7893 41.4696 60 42 60C42.5304 60 43.0391 59.7893 43.4142 59.4143C43.7893 59.0392 44 58.5305 44 58V48C44.0013 45.7776 43.2585 43.6187 41.89 41.8675C45.2426 41.4076 48.3156 39.7501 50.5414 37.2012C52.7673 34.6523 53.9958 31.384 54 28V26C53.9751 23.5145 53.3132 21.0768 52.0775 18.92ZM50 28C50 30.6522 48.9464 33.1957 47.0711 35.0711C45.1957 36.9465 42.6522 38 40 38H28C25.3478 38 22.8043 36.9465 20.9289 35.0711C19.0536 33.1957 18 30.6522 18 28V26C18.0245 24.0001 18.6233 22.0493 19.725 20.38C19.9304 20.1093 20.0634 19.7908 20.1115 19.4544C20.1596 19.118 20.1212 18.775 20 18.4575C19.4791 17.114 19.2283 15.6809 19.2622 14.2404C19.2961 12.7998 19.614 11.3801 20.1975 10.0625C21.8343 10.2386 23.4105 10.7808 24.8092 11.649C26.2079 12.5171 27.3933 13.6889 28.2775 15.0775C28.4577 15.3593 28.7056 15.5914 28.9987 15.7525C29.2918 15.9137 29.6206 15.9988 29.955 16H38.0425C38.3782 16 38.7085 15.9155 39.003 15.7543C39.2975 15.5931 39.5466 15.3604 39.7275 15.0775C40.6116 13.6888 41.7969 12.5169 43.1957 11.6487C44.5944 10.7806 46.1707 10.2384 47.8075 10.0625C48.3902 11.3804 48.7072 12.8003 48.7402 14.2409C48.7733 15.6814 48.5217 17.1144 48 18.4575C47.8791 18.7719 47.8387 19.1115 47.8823 19.4455C47.926 19.7795 48.0524 20.0973 48.25 20.37C49.3626 22.0393 49.9703 23.9941 50 26V28Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_291_4849">
<rect width="64" height="64" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

@ -0,0 +1,3 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M32 6C26.8577 6 21.8309 7.52487 17.5552 10.3818C13.2795 13.2387 9.94702 17.2994 7.97914 22.0502C6.01127 26.8011 5.49638 32.0288 6.49959 37.0723C7.50281 42.1159 9.97907 46.7486 13.6152 50.3848C17.2514 54.0209 21.8842 56.4972 26.9277 57.5004C31.9712 58.5036 37.1989 57.9887 41.9498 56.0209C46.7007 54.053 50.7613 50.7205 53.6182 46.4448C56.4751 42.1691 58 37.1423 58 32C57.9921 25.1068 55.2502 18.4982 50.376 13.624C45.5018 8.74977 38.8932 6.00794 32 6ZM54 32C54.0018 34.0289 53.7216 36.0482 53.1675 38H43.54C44.1534 34.0235 44.1534 29.9765 43.54 26H53.1675C53.7216 27.9518 54.0018 29.9711 54 32ZM25.5 42H38.5C37.2193 46.1965 34.996 50.0445 32 53.25C29.0052 50.0437 26.782 46.1959 25.5 42ZM24.525 38C23.8384 34.0295 23.8384 29.9705 24.525 26H39.495C40.1817 29.9705 40.1817 34.0295 39.495 38H24.525ZM10 32C9.99827 29.9711 10.2785 27.9518 10.8325 26H20.46C19.8467 29.9765 19.8467 34.0235 20.46 38H10.8325C10.2785 36.0482 9.99827 34.0289 10 32ZM38.5 22H25.5C26.7807 17.8035 29.0041 13.9555 32 10.75C34.9948 13.9563 37.218 17.8041 38.5 22ZM51.5825 22H42.6775C41.5551 17.8823 39.6635 14.0142 37.1025 10.6C40.1968 11.3433 43.0937 12.7469 45.5948 14.7146C48.0958 16.6823 50.1418 19.1676 51.5925 22H51.5825ZM26.8975 10.6C24.3365 14.0142 22.4449 17.8823 21.3225 22H12.4075C13.8582 19.1676 15.9042 16.6823 18.4052 14.7146C20.9063 12.7469 23.8032 11.3433 26.8975 10.6ZM12.4075 42H21.3225C22.4449 46.1177 24.3365 49.9858 26.8975 53.4C23.8032 52.6567 20.9063 51.2531 18.4052 49.2854C15.9042 47.3177 13.8582 44.8324 12.4075 42ZM37.1025 53.4C39.6635 49.9858 41.5551 46.1177 42.6775 42H51.5925C50.1418 44.8324 48.0958 47.3177 45.5948 49.2854C43.0937 51.2531 40.1968 52.6567 37.1025 53.4Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -0,0 +1,3 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M54.9008 27.9002L36.1508 9.10039C35.4476 8.3958 34.4941 8 33.5 8C32.5059 8 31.5524 8.3958 30.8492 9.10039L12.0992 27.9002C11.7493 28.2484 11.472 28.6629 11.2833 29.1196C11.0945 29.5763 10.9983 30.066 11 30.5603V53.12C11 53.6186 11.1976 54.0968 11.5492 54.4494C11.9008 54.8019 12.3777 55 12.875 55H27.875C28.3723 55 28.8492 54.8019 29.2008 54.4494C29.5525 54.0968 29.75 53.6186 29.75 53.12V39.9602H37.25V53.12C37.25 53.6186 37.4475 54.0968 37.7992 54.4494C38.1508 54.8019 38.6277 55 39.125 55H54.125C54.6223 55 55.0992 54.8019 55.4508 54.4494C55.8024 54.0968 56 53.6186 56 53.12V30.5603C56.0017 30.066 55.9055 29.5763 55.7168 29.1196C55.528 28.6629 55.2507 28.2484 54.9008 27.9002ZM52.25 51.24H41V38.0802C41 37.5816 40.8025 37.1034 40.4508 36.7509C40.0992 36.3983 39.6223 36.2002 39.125 36.2002H27.875C27.3777 36.2002 26.9008 36.3983 26.5492 36.7509C26.1976 37.1034 26 37.5816 26 38.0802V51.24H14.75V30.5603L33.5 11.7606L52.25 30.5603V51.24Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 3C13.4288 3 10.9154 3.76244 8.77759 5.1909C6.63975 6.61935 4.97351 8.64968 3.98957 11.0251C3.00563 13.4006 2.74819 16.0144 3.2498 18.5362C3.75141 21.0579 4.98953 23.3743 6.80762 25.1924C8.6257 27.0105 10.9421 28.2486 13.4638 28.7502C15.9856 29.2518 18.5995 28.9944 20.9749 28.0104C23.3503 27.0265 25.3807 25.3603 26.8091 23.2224C28.2376 21.0846 29 18.5712 29 16C28.9964 12.5533 27.6256 9.24882 25.1884 6.81163C22.7512 4.37445 19.4467 3.00364 16 3ZM16 27C13.8244 27 11.6977 26.3549 9.88873 25.1462C8.07979 23.9375 6.66989 22.2195 5.83733 20.2095C5.00477 18.1995 4.78693 15.9878 5.21137 13.854C5.63581 11.7202 6.68345 9.7602 8.22183 8.22183C9.76021 6.68345 11.7202 5.6358 13.854 5.21136C15.9878 4.78692 18.1995 5.00476 20.2095 5.83733C22.2195 6.66989 23.9375 8.07979 25.1462 9.88873C26.3549 11.6977 27 13.8244 27 16C26.9967 18.9164 25.8367 21.7123 23.7745 23.7745C21.7123 25.8367 18.9164 26.9967 16 27ZM18 22C18 22.2652 17.8946 22.5196 17.7071 22.7071C17.5196 22.8946 17.2652 23 17 23C16.4696 23 15.9609 22.7893 15.5858 22.4142C15.2107 22.0391 15 21.5304 15 21V16C14.7348 16 14.4804 15.8946 14.2929 15.7071C14.1054 15.5196 14 15.2652 14 15C14 14.7348 14.1054 14.4804 14.2929 14.2929C14.4804 14.1054 14.7348 14 15 14C15.5304 14 16.0391 14.2107 16.4142 14.5858C16.7893 14.9609 17 15.4696 17 16V21C17.2652 21 17.5196 21.1054 17.7071 21.2929C17.8946 21.4804 18 21.7348 18 22ZM14 10.5C14 10.2033 14.088 9.91332 14.2528 9.66665C14.4176 9.41997 14.6519 9.22771 14.926 9.11418C15.2001 9.00065 15.5017 8.97094 15.7926 9.02882C16.0836 9.0867 16.3509 9.22956 16.5607 9.43934C16.7704 9.64912 16.9133 9.91639 16.9712 10.2074C17.0291 10.4983 16.9994 10.7999 16.8858 11.074C16.7723 11.3481 16.58 11.5824 16.3334 11.7472C16.0867 11.912 15.7967 12 15.5 12C15.1022 12 14.7206 11.842 14.4393 11.5607C14.158 11.2794 14 10.8978 14 10.5Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M26.7075 8.2925L21.7075 3.2925C21.6146 3.19967 21.5042 3.12605 21.3829 3.07586C21.2615 3.02568 21.1314 2.9999 21 3H11C10.4696 3 9.96086 3.21071 9.58579 3.58579C9.21071 3.96086 9 4.46957 9 5V7H7C6.46957 7 5.96086 7.21071 5.58579 7.58579C5.21071 7.96086 5 8.46957 5 9V27C5 27.5304 5.21071 28.0391 5.58579 28.4142C5.96086 28.7893 6.46957 29 7 29H21C21.5304 29 22.0391 28.7893 22.4142 28.4142C22.7893 28.0391 23 27.5304 23 27V25H25C25.5304 25 26.0391 24.7893 26.4142 24.4142C26.7893 24.0391 27 23.5304 27 23V9C27.0001 8.86864 26.9743 8.73855 26.9241 8.61715C26.8739 8.49576 26.8003 8.38544 26.7075 8.2925ZM21 27H7V9H16.5863L21 13.4137V23.98C21 23.9875 21 23.9937 21 24C21 24.0063 21 24.0125 21 24.02V27ZM25 23H23V13C23.0001 12.8686 22.9743 12.7385 22.9241 12.6172C22.8739 12.4958 22.8003 12.3854 22.7075 12.2925L17.7075 7.2925C17.6146 7.19967 17.5042 7.12605 17.3829 7.07586C17.2615 7.02568 17.1314 6.9999 17 7H11V5H20.5863L25 9.41375V23ZM18 19C18 19.2652 17.8946 19.5196 17.7071 19.7071C17.5196 19.8946 17.2652 20 17 20H11C10.7348 20 10.4804 19.8946 10.2929 19.7071C10.1054 19.5196 10 19.2652 10 19C10 18.7348 10.1054 18.4804 10.2929 18.2929C10.4804 18.1054 10.7348 18 11 18H17C17.2652 18 17.5196 18.1054 17.7071 18.2929C17.8946 18.4804 18 18.7348 18 19ZM18 23C18 23.2652 17.8946 23.5196 17.7071 23.7071C17.5196 23.8946 17.2652 24 17 24H11C10.7348 24 10.4804 23.8946 10.2929 23.7071C10.1054 23.5196 10 23.2652 10 23C10 22.7348 10.1054 22.4804 10.2929 22.2929C10.4804 22.1054 10.7348 22 11 22H17C17.2652 22 17.5196 22.1054 17.7071 22.2929C17.8946 22.4804 18 22.7348 18 23Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27.96 8.26876L16.96 2.25001C16.6661 2.08761 16.3358 2.00243 16 2.00243C15.6642 2.00243 15.3339 2.08761 15.04 2.25001L4.04 8.27126C3.72586 8.44314 3.46363 8.69621 3.28069 9.00404C3.09775 9.31187 3.00081 9.66317 3 10.0213V21.9763C3.00081 22.3343 3.09775 22.6856 3.28069 22.9935C3.46363 23.3013 3.72586 23.5544 4.04 23.7263L15.04 29.7475C15.3339 29.9099 15.6642 29.9951 16 29.9951C16.3358 29.9951 16.6661 29.9099 16.96 29.7475L27.96 23.7263C28.2741 23.5544 28.5364 23.3013 28.7193 22.9935C28.9023 22.6856 28.9992 22.3343 29 21.9763V10.0225C28.9999 9.66378 28.9032 9.3117 28.7203 9.00315C28.5373 8.6946 28.2747 8.44095 27.96 8.26876ZM16 4.00001L26.0425 9.50001L16 15L5.9575 9.50001L16 4.00001ZM5 11.25L15 16.7225V27.4463L5 21.9775V11.25ZM17 27.4463V16.7275L27 11.25V21.9725L17 27.4463Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 911 B

@ -0,0 +1,7 @@
<svg width="45" height="31" viewBox="0 0 45 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.41228 22.6607V0H6.76535V30.2143H5.41228L1.35307 7.55357V30.2143H0V0H1.35307L5.41228 22.6607Z" fill="black"/>
<path d="M13.6575 28.9006C14.024 28.9006 14.3341 28.7775 14.5878 28.5312C14.8697 28.2848 15.0106 27.9701 15.0106 27.587V2.62733C15.0106 2.27154 14.8697 1.9705 14.5878 1.72418C14.3341 1.4505 14.024 1.31366 13.6575 1.31366C13.2629 1.31366 12.9387 1.4505 12.685 1.72418C12.4313 1.9705 12.3045 2.27154 12.3045 2.62733V27.587C12.3045 27.9701 12.4313 28.2848 12.685 28.5312C12.9387 28.7775 13.2629 28.9006 13.6575 28.9006ZM13.6575 30.2143C12.8964 30.2143 12.2481 29.968 11.7125 29.4753C11.2051 28.9554 10.9514 28.3259 10.9514 27.587V2.62733C10.9514 1.91576 11.2051 1.29998 11.7125 0.779988C12.2481 0.259996 12.8964 0 13.6575 0C14.3905 0 15.0247 0.259996 15.5603 0.779988C16.0959 1.29998 16.3637 1.91576 16.3637 2.62733V27.587C16.3637 28.3259 16.0959 28.9554 15.5603 29.4753C15.0247 29.968 14.3905 30.2143 13.6575 30.2143Z" fill="black"/>
<path d="M28.3299 0H29.683V30.2143H28.3299V5.25466L24.9472 18.3913L21.5645 5.25466V30.2143H20.2115V0H21.5645L24.9472 13.1366L28.3299 0Z" fill="black"/>
<path d="M33.6999 30.2143V0H35.0529V30.2143H33.6999Z" fill="black"/>
<path d="M41.776 30.2143C41.0149 30.2143 40.3666 29.968 39.831 29.4753C39.3236 28.9554 39.0699 28.3259 39.0699 27.587V2.62733C39.0699 1.91576 39.3236 1.29998 39.831 0.779988C40.3666 0.259996 41.0149 0 41.776 0C42.5089 0 43.1432 0.259996 43.6788 0.779988C44.2143 1.29998 44.4821 1.91576 44.4821 2.62733V5.25466H43.1291V2.62733C43.1291 2.27154 42.9881 1.9705 42.7062 1.72418C42.4525 1.4505 42.1425 1.31366 41.776 1.31366C41.3814 1.31366 41.0572 1.4505 40.8035 1.72418C40.5498 1.9705 40.4229 2.27154 40.4229 2.62733V27.587C40.4229 27.9701 40.5498 28.2848 40.8035 28.5312C41.0572 28.7775 41.3814 28.9006 41.776 28.9006C42.1425 28.9006 42.4525 28.7775 42.7062 28.5312C42.9881 28.2848 43.1291 27.9701 43.1291 27.587V24.9596H44.4821V27.587C44.4821 28.3259 44.2143 28.9554 43.6788 29.4753C43.1432 29.968 42.5089 30.2143 41.776 30.2143Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>
<!--
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->

After

Width:  |  Height:  |  Size: 602 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

@ -1,5 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#7d7d8e" viewBox="0 0 448 512"><path d="M0 84V56c0-13.3 10.7-24 24-24h112l9.4-18.7c4-8.2 12.3-13.3 21.4-13.3h114.3c9.1 0 17.4 5.1 21.5 13.3L312 32h112c13.3 0 24 10.7 24 24v28c0 6.6-5.4 12-12 12H12C5.4 96 0 90.6 0 84zm416 56v324c0 26.5-21.5 48-48 48H80c-26.5 0-48-21.5-48-48V140c0-6.6 5.4-12 12-12h360c6.6 0 12 5.4 12 12zm-272 68c0-8.8-7.2-16-16-16s-16 7.2-16 16v224c0 8.8 7.2 16 16 16s16-7.2 16-16V208zm96 0c0-8.8-7.2-16-16-16s-16 7.2-16 16v224c0 8.8 7.2 16 16 16s16-7.2 16-16V208zm96 0c0-8.8-7.2-16-16-16s-16 7.2-16 16v224c0 8.8 7.2 16 16 16s16-7.2 16-16V208z"/></svg>
<!--
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27 6H5C4.73478 6 4.48043 6.10536 4.29289 6.29289C4.10536 6.48043 4 6.73478 4 7C4 7.26522 4.10536 7.51957 4.29289 7.70711C4.48043 7.89464 4.73478 8 5 8H6V26C6 26.5304 6.21071 27.0391 6.58579 27.4142C6.96086 27.7893 7.46957 28 8 28H24C24.5304 28 25.0391 27.7893 25.4142 27.4142C25.7893 27.0391 26 26.5304 26 26V8H27C27.2652 8 27.5196 7.89464 27.7071 7.70711C27.8946 7.51957 28 7.26522 28 7C28 6.73478 27.8946 6.48043 27.7071 6.29289C27.5196 6.10536 27.2652 6 27 6ZM24 26H8V8H24V26ZM10 3C10 2.73478 10.1054 2.48043 10.2929 2.29289C10.4804 2.10536 10.7348 2 11 2H21C21.2652 2 21.5196 2.10536 21.7071 2.29289C21.8946 2.48043 22 2.73478 22 3C22 3.26522 21.8946 3.51957 21.7071 3.70711C21.5196 3.89464 21.2652 4 21 4H11C10.7348 4 10.4804 3.89464 10.2929 3.70711C10.1054 3.51957 10 3.26522 10 3Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 917 B

@ -0,0 +1,3 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M53.687 52.9275L38.037 28.3325L53.4795 11.345C53.8288 10.9513 54.0088 10.4358 53.9805 9.91031C53.9522 9.38479 53.718 8.89159 53.3285 8.53764C52.939 8.18369 52.4257 7.99752 51.8999 8.01949C51.3741 8.04146 50.8781 8.2698 50.5195 8.655L35.8095 24.835L25.687 8.9275C25.5065 8.64339 25.2572 8.40943 24.9622 8.24729C24.6673 8.08516 24.3361 8.0001 23.9995 8H11.9995C11.6409 7.99983 11.2889 8.09607 10.9802 8.27865C10.6716 8.46123 10.4177 8.72343 10.2452 9.0378C10.0727 9.35218 9.98787 9.70715 9.99963 10.0656C10.0114 10.424 10.1193 10.7726 10.312 11.075L25.962 35.6675L10.5195 52.6675C10.3392 52.8612 10.1991 53.0888 10.1074 53.337C10.0156 53.5853 9.97409 53.8493 9.98514 54.1137C9.99619 54.3782 10.0596 54.6378 10.1717 54.8775C10.2839 55.1173 10.4424 55.3324 10.6383 55.5104C10.8342 55.6883 11.0634 55.8257 11.3127 55.9144C11.5621 56.0032 11.8266 56.0416 12.0908 56.0274C12.3551 56.0131 12.6139 55.9466 12.8523 55.8316C13.0907 55.7166 13.3039 55.5555 13.4795 55.3575L28.1895 39.1775L38.312 55.085C38.494 55.3668 38.7439 55.5983 39.0388 55.7582C39.3337 55.9181 39.6641 56.0012 39.9995 56H51.9995C52.3577 55.9999 52.7093 55.9036 53.0176 55.7211C53.3259 55.5387 53.5795 55.2768 53.7519 54.9628C53.9244 54.6488 54.0093 54.2943 53.9979 53.9363C53.9865 53.5782 53.8791 53.2299 53.687 52.9275ZM41.097 52L15.642 12H22.892L48.357 52H41.097Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -20,6 +20,8 @@ LocalDocs::LocalDocs()
connect(this, &LocalDocs::requestStart, m_database,
&Database::start, Qt::QueuedConnection);
connect(this, &LocalDocs::requestForceIndexing, m_database,
&Database::forceIndexing, Qt::QueuedConnection);
connect(this, &LocalDocs::requestAddFolder, m_database,
&Database::addFolder, Qt::QueuedConnection);
connect(this, &LocalDocs::requestRemoveFolder, m_database,
@ -28,31 +30,13 @@ LocalDocs::LocalDocs()
&Database::changeChunkSize, Qt::QueuedConnection);
// Connections for modifying the model and keeping it updated with the database
connect(m_database, &Database::updateInstalled,
m_localDocsModel, &LocalDocsModel::updateInstalled, Qt::QueuedConnection);
connect(m_database, &Database::updateIndexing,
m_localDocsModel, &LocalDocsModel::updateIndexing, Qt::QueuedConnection);
connect(m_database, &Database::updateError,
m_localDocsModel, &LocalDocsModel::updateError, Qt::QueuedConnection);
connect(m_database, &Database::updateCurrentDocsToIndex,
m_localDocsModel, &LocalDocsModel::updateCurrentDocsToIndex, Qt::QueuedConnection);
connect(m_database, &Database::updateTotalDocsToIndex,
m_localDocsModel, &LocalDocsModel::updateTotalDocsToIndex, Qt::QueuedConnection);
connect(m_database, &Database::subtractCurrentBytesToIndex,
m_localDocsModel, &LocalDocsModel::subtractCurrentBytesToIndex, Qt::QueuedConnection);
connect(m_database, &Database::updateCurrentBytesToIndex,
m_localDocsModel, &LocalDocsModel::updateCurrentBytesToIndex, Qt::QueuedConnection);
connect(m_database, &Database::updateTotalBytesToIndex,
m_localDocsModel, &LocalDocsModel::updateTotalBytesToIndex, Qt::QueuedConnection);
connect(m_database, &Database::updateCurrentEmbeddingsToIndex,
m_localDocsModel, &LocalDocsModel::updateCurrentEmbeddingsToIndex, Qt::QueuedConnection);
connect(m_database, &Database::updateTotalEmbeddingsToIndex,
m_localDocsModel, &LocalDocsModel::updateTotalEmbeddingsToIndex, Qt::QueuedConnection);
connect(m_database, &Database::addCollectionItem,
connect(m_database, &Database::requestUpdateGuiForCollectionItem,
m_localDocsModel, &LocalDocsModel::updateCollectionItem, Qt::QueuedConnection);
connect(m_database, &Database::requestAddGuiCollectionItem,
m_localDocsModel, &LocalDocsModel::addCollectionItem, Qt::QueuedConnection);
connect(m_database, &Database::removeFolderById,
connect(m_database, &Database::requestRemoveGuiFolderById,
m_localDocsModel, &LocalDocsModel::removeFolderById, Qt::QueuedConnection);
connect(m_database, &Database::collectionListUpdated,
connect(m_database, &Database::requestGuiCollectionListUpdated,
m_localDocsModel, &LocalDocsModel::collectionListUpdated, Qt::QueuedConnection);
connect(qApp, &QCoreApplication::aboutToQuit, this, &LocalDocs::aboutToQuit);
@ -64,11 +48,16 @@ void LocalDocs::aboutToQuit()
m_database = nullptr;
}
void LocalDocs::forceIndexing(const QString &collection)
{
emit requestForceIndexing(collection);
}
void LocalDocs::addFolder(const QString &collection, const QString &path)
{
const QUrl url(path);
const QString localPath = url.isLocalFile() ? url.toLocalFile() : path;
emit requestAddFolder(collection, localPath, false);
emit requestAddFolder(collection, localPath);
}
void LocalDocs::removeFolder(const QString &collection, const QString &path)

@ -16,6 +16,7 @@ public:
LocalDocsModel *localDocsModel() const { return m_localDocsModel; }
Q_INVOKABLE void forceIndexing(const QString &collection);
Q_INVOKABLE void addFolder(const QString &collection, const QString &path);
Q_INVOKABLE void removeFolder(const QString &collection, const QString &path);
@ -27,7 +28,8 @@ public Q_SLOTS:
Q_SIGNALS:
void requestStart();
void requestAddFolder(const QString &collection, const QString &path, bool fromDb);
void requestForceIndexing(const QString &collection);
void requestAddFolder(const QString &collection, const QString &path);
void requestRemoveFolder(const QString &collection, const QString &path);
void requestChunkSizeChange(int chunkSize);
void localDocsModelChanged();

@ -51,6 +51,8 @@ QVariant LocalDocsModel::data(const QModelIndex &index, int role) const
return item.indexing;
case ErrorRole:
return item.error;
case ForceIndexingRole:
return item.forceIndexing;
case CurrentDocsToIndexRole:
return item.currentDocsToIndex;
case TotalDocsToIndexRole:
@ -63,6 +65,18 @@ QVariant LocalDocsModel::data(const QModelIndex &index, int role) const
return quint64(item.currentEmbeddingsToIndex);
case TotalEmbeddingsToIndexRole:
return quint64(item.totalEmbeddingsToIndex);
case TotalDocsRole:
return quint64(item.totalDocs);
case TotalWordsRole:
return quint64(item.totalWords);
case TotalTokensRole:
return quint64(item.totalTokens);
case LastUpdateRole:
return item.lastUpdate;
case FileCurrentlyProcessingRole:
return item.fileCurrentlyProcessing;
case EmbeddingModelRole:
return item.embeddingModel;
}
return QVariant();
@ -76,100 +90,77 @@ QHash<int, QByteArray> LocalDocsModel::roleNames() const
roles[InstalledRole] = "installed";
roles[IndexingRole] = "indexing";
roles[ErrorRole] = "error";
roles[ForceIndexingRole] = "forceIndexing";
roles[CurrentDocsToIndexRole] = "currentDocsToIndex";
roles[TotalDocsToIndexRole] = "totalDocsToIndex";
roles[CurrentBytesToIndexRole] = "currentBytesToIndex";
roles[TotalBytesToIndexRole] = "totalBytesToIndex";
roles[CurrentEmbeddingsToIndexRole] = "currentEmbeddingsToIndex";
roles[TotalEmbeddingsToIndexRole] = "totalEmbeddingsToIndex";
roles[TotalDocsRole] = "totalDocs";
roles[TotalWordsRole] = "totalWords";
roles[TotalTokensRole] = "totalTokens";
roles[LastUpdateRole] = "lastUpdate";
roles[FileCurrentlyProcessingRole] = "fileCurrentlyProcessing";
roles[EmbeddingModelRole] = "embeddingModel";
return roles;
}
template<typename T>
void LocalDocsModel::updateField(int folder_id, T value,
const std::function<void(CollectionItem&, T)>& updater,
const QVector<int>& roles)
void LocalDocsModel::updateCollectionItem(const CollectionItem &item)
{
for (int i = 0; i < m_collectionList.size(); ++i) {
if (m_collectionList.at(i).folder_id != folder_id)
CollectionItem &stored = m_collectionList[i];
if (stored.folder_id != item.folder_id)
continue;
updater(m_collectionList[i], value);
emit dataChanged(this->index(i), this->index(i), roles);
QVector<int> changed;
if (stored.collection != item.collection)
changed.append(CollectionRole);
if (stored.folder_path != item.folder_path)
changed.append(FolderPathRole);
if (stored.installed != item.installed)
changed.append(InstalledRole);
if (stored.indexing != item.indexing)
changed.append(IndexingRole);
if (stored.error != item.error)
changed.append(ErrorRole);
if (stored.forceIndexing != item.forceIndexing)
changed.append(ForceIndexingRole);
if (stored.currentDocsToIndex != item.currentDocsToIndex)
changed.append(CurrentDocsToIndexRole);
if (stored.totalDocsToIndex != item.totalDocsToIndex)
changed.append(TotalDocsToIndexRole);
if (stored.currentBytesToIndex != item.currentBytesToIndex)
changed.append(CurrentBytesToIndexRole);
if (stored.totalBytesToIndex != item.totalBytesToIndex)
changed.append(TotalBytesToIndexRole);
if (stored.currentEmbeddingsToIndex != item.currentEmbeddingsToIndex)
changed.append(CurrentEmbeddingsToIndexRole);
if (stored.totalEmbeddingsToIndex != item.totalEmbeddingsToIndex)
changed.append(TotalEmbeddingsToIndexRole);
if (stored.totalDocs != item.totalDocs)
changed.append(TotalDocsRole);
if (stored.totalWords != item.totalWords)
changed.append(TotalWordsRole);
if (stored.totalTokens != item.totalTokens)
changed.append(TotalTokensRole);
if (stored.lastUpdate != item.lastUpdate)
changed.append(LastUpdateRole);
if (stored.fileCurrentlyProcessing != item.fileCurrentlyProcessing)
changed.append(FileCurrentlyProcessingRole);
if (stored.embeddingModel != item.embeddingModel)
changed.append(EmbeddingModelRole);
stored = item;
emit dataChanged(this->index(i), this->index(i), changed);
}
}
void LocalDocsModel::updateInstalled(int folder_id, bool b)
{
updateField<bool>(folder_id, b,
[](CollectionItem& item, bool val) { item.installed = val; }, {InstalledRole});
}
void LocalDocsModel::updateIndexing(int folder_id, bool b)
{
updateField<bool>(folder_id, b,
[](CollectionItem& item, bool val) { item.indexing = val; }, {IndexingRole});
}
void LocalDocsModel::updateError(int folder_id, const QString &error)
{
updateField<QString>(folder_id, error,
[](CollectionItem& item, QString val) { item.error = val; }, {ErrorRole});
}
void LocalDocsModel::updateCurrentDocsToIndex(int folder_id, size_t currentDocsToIndex)
{
updateField<size_t>(folder_id, currentDocsToIndex,
[](CollectionItem& item, size_t val) { item.currentDocsToIndex = val; }, {CurrentDocsToIndexRole});
}
void LocalDocsModel::updateTotalDocsToIndex(int folder_id, size_t totalDocsToIndex)
{
updateField<size_t>(folder_id, totalDocsToIndex,
[](CollectionItem& item, size_t val) { item.totalDocsToIndex = val; }, {TotalDocsToIndexRole});
}
void LocalDocsModel::subtractCurrentBytesToIndex(int folder_id, size_t subtractedBytes)
{
updateField<size_t>(folder_id, subtractedBytes,
[](CollectionItem& item, size_t val) { item.currentBytesToIndex -= val; }, {CurrentBytesToIndexRole});
}
void LocalDocsModel::updateCurrentBytesToIndex(int folder_id, size_t currentBytesToIndex)
{
updateField<size_t>(folder_id, currentBytesToIndex,
[](CollectionItem& item, size_t val) { item.currentBytesToIndex = val; }, {CurrentBytesToIndexRole});
}
void LocalDocsModel::updateTotalBytesToIndex(int folder_id, size_t totalBytesToIndex)
{
updateField<size_t>(folder_id, totalBytesToIndex,
[](CollectionItem& item, size_t val) { item.totalBytesToIndex = val; }, {TotalBytesToIndexRole});
}
void LocalDocsModel::updateCurrentEmbeddingsToIndex(int folder_id, size_t currentEmbeddingsToIndex)
{
updateField<size_t>(folder_id, currentEmbeddingsToIndex,
[](CollectionItem& item, size_t val) { item.currentEmbeddingsToIndex += val; }, {CurrentEmbeddingsToIndexRole});
}
void LocalDocsModel::updateTotalEmbeddingsToIndex(int folder_id, size_t totalEmbeddingsToIndex)
{
updateField<size_t>(folder_id, totalEmbeddingsToIndex,
[](CollectionItem& item, size_t val) { item.totalEmbeddingsToIndex += val; }, {TotalEmbeddingsToIndexRole});
}
void LocalDocsModel::addCollectionItem(const CollectionItem &item, bool fromDb)
void LocalDocsModel::addCollectionItem(const CollectionItem &item)
{
beginInsertRows(QModelIndex(), m_collectionList.size(), m_collectionList.size());
m_collectionList.append(item);
endInsertRows();
if (!fromDb) {
Network::globalInstance()->trackEvent("doc_collection_add", {
{"collection_count", m_collectionList.count()},
});
}
}
void LocalDocsModel::removeCollectionIf(std::function<bool(CollectionItem)> const &predicate) {

@ -31,12 +31,19 @@ public:
InstalledRole,
IndexingRole,
ErrorRole,
ForceIndexingRole,
CurrentDocsToIndexRole,
TotalDocsToIndexRole,
CurrentBytesToIndexRole,
TotalBytesToIndexRole,
CurrentEmbeddingsToIndexRole,
TotalEmbeddingsToIndexRole
TotalEmbeddingsToIndexRole,
TotalDocsRole,
TotalWordsRole,
TotalTokensRole,
LastUpdateRole,
FileCurrentlyProcessingRole,
EmbeddingModelRole
};
explicit LocalDocsModel(QObject *parent = nullptr);
@ -45,29 +52,14 @@ public:
QHash<int, QByteArray> roleNames() const override;
public Q_SLOTS:
void updateInstalled(int folder_id, bool b);
void updateIndexing(int folder_id, bool b);
void updateError(int folder_id, const QString &error);
void updateCurrentDocsToIndex(int folder_id, size_t currentDocsToIndex);
void updateTotalDocsToIndex(int folder_id, size_t totalDocsToIndex);
void subtractCurrentBytesToIndex(int folder_id, size_t subtractedBytes);
void updateCurrentBytesToIndex(int folder_id, size_t currentBytesToIndex);
void updateTotalBytesToIndex(int folder_id, size_t totalBytesToIndex);
void updateCurrentEmbeddingsToIndex(int folder_id, size_t currentBytesToIndex);
void updateTotalEmbeddingsToIndex(int folder_id, size_t totalBytesToIndex);
void addCollectionItem(const CollectionItem &item, bool fromDb);
void updateCollectionItem(const CollectionItem&);
void addCollectionItem(const CollectionItem &item);
void removeFolderById(int folder_id);
void removeCollectionPath(const QString &name, const QString &path);
void collectionListUpdated(const QList<CollectionItem> &collectionList);
private:
template<typename T>
void updateField(int folder_id, T value,
const std::function<void(CollectionItem&, T)>& updater,
const QVector<int>& roles);
void removeCollectionIf(std::function<bool(CollectionItem)> const &predicate);
private:
QList<CollectionItem> m_collectionList;
};

@ -10,14 +10,15 @@ import download
import modellist
import network
import gpt4all
import localdocs
import mysettings
Window {
id: window
width: 1920
height: 1080
minimumWidth: 720
minimumHeight: 480
minimumWidth: 1280
minimumHeight: 720
visible: true
title: qsTr("GPT4All v") + Qt.application.version
@ -32,6 +33,166 @@ Window {
id: theme
}
Item {
Accessible.role: Accessible.Window
Accessible.name: title
}
// Startup code
Component.onCompleted: {
startupDialogs();
}
Component.onDestruction: {
Network.trackEvent("session_end")
}
Connections {
target: firstStartDialog
function onClosed() {
startupDialogs();
}
}
Connections {
target: Download
function onHasNewerReleaseChanged() {
startupDialogs();
}
}
property bool hasShownModelDownload: false
property bool hasCheckedFirstStart: false
property bool hasShownSettingsAccess: false
function startupDialogs() {
if (!LLM.compatHardware()) {
Network.trackEvent("noncompat_hardware")
errorCompatHardware.open();
return;
}
// check if we have access to settings and if not show an error
if (!hasShownSettingsAccess && !LLM.hasSettingsAccess()) {
errorSettingsAccess.open();
hasShownSettingsAccess = true;
return;
}
// check for first time start of this version
if (!hasCheckedFirstStart) {
if (Download.isFirstStart(/*writeVersion*/ true)) {
firstStartDialog.open();
return;
}
// send startup or opt-out now that the user has made their choice
Network.sendStartup()
// start localdocs
LocalDocs.requestStart()
hasCheckedFirstStart = true
}
// check for any current models and if not, open download view once
if (!hasShownModelDownload && ModelList.installedModels.count === 0 && !firstStartDialog.opened) {
downloadViewRequested();
hasShownModelDownload = true;
return;
}
// check for new version
if (Download.hasNewerRelease && !firstStartDialog.opened) {
newVersionDialog.open();
return;
}
}
PopupDialog {
id: errorCompatHardware
anchors.centerIn: parent
shouldTimeOut: false
shouldShowBusy: false
closePolicy: Popup.NoAutoClose
modal: true
text: qsTr("<h3>Encountered an error starting up:</h3><br>")
+ qsTr("<i>\"Incompatible hardware detected.\"</i>")
+ qsTr("<br><br>Unfortunately, your CPU does not meet the minimal requirements to run ")
+ qsTr("this program. In particular, it does not support AVX intrinsics which this ")
+ qsTr("program requires to successfully run a modern large language model. ")
+ qsTr("The only solution at this time is to upgrade your hardware to a more modern CPU.")
+ qsTr("<br><br>See here for more information: <a href=\"https://en.wikipedia.org/wiki/Advanced_Vector_Extensions\">")
+ qsTr("https://en.wikipedia.org/wiki/Advanced_Vector_Extensions</a>")
}
PopupDialog {
id: errorSettingsAccess
anchors.centerIn: parent
shouldTimeOut: false
shouldShowBusy: false
modal: true
text: qsTr("<h3>Encountered an error starting up:</h3><br>")
+ qsTr("<i>\"Inability to access settings file.\"</i>")
+ qsTr("<br><br>Unfortunately, something is preventing the program from accessing ")
+ qsTr("the settings file. This could be caused by incorrect permissions in the local ")
+ qsTr("app config directory where the settings file is located. ")
+ qsTr("Check out our <a href=\"https://discord.gg/4M2QFmTt2k\">discord channel</a> for help.")
}
StartupDialog {
id: firstStartDialog
anchors.centerIn: parent
}
NewVersionDialog {
id: newVersionDialog
anchors.centerIn: parent
}
Connections {
target: Network
function onHealthCheckFailed(code) {
healthCheckFailed.open();
}
}
PopupDialog {
id: healthCheckFailed
anchors.centerIn: parent
text: qsTr("Connection to datalake failed.")
font.pixelSize: theme.fontSizeLarge
}
Dialog {
id: checkForUpdatesError
anchors.centerIn: parent
modal: false
padding: 20
Text {
horizontalAlignment: Text.AlignJustify
text: qsTr("ERROR: Update system could not find the MaintenanceTool used<br>
to check for updates!<br><br>
Did you install this application using the online installer? If so,<br>
the MaintenanceTool executable should be located one directory<br>
above where this application resides on your filesystem.<br><br>
If you can't start it manually, then I'm afraid you'll have to<br>
reinstall.")
color: theme.textErrorColor
font.pixelSize: theme.fontSizeLarge
Accessible.role: Accessible.Dialog
Accessible.name: text
Accessible.description: qsTr("Error dialog")
}
background: Rectangle {
anchors.fill: parent
color: theme.containerBackground
border.width: 1
border.color: theme.dialogBorder
radius: 10
}
}
property bool hasSaved: false
PopupDialog {
@ -43,6 +204,25 @@ Window {
font.pixelSize: theme.fontSizeLarge
}
NetworkDialog {
id: networkDialog
anchors.centerIn: parent
width: Math.min(1024, window.width - (window.width * .2))
height: Math.min(600, window.height - (window.height * .2))
Item {
Accessible.role: Accessible.Dialog
Accessible.name: qsTr("Network dialog")
Accessible.description: qsTr("opt-in to share feedback/conversations")
}
}
AboutDialog {
id: aboutDialog
anchors.centerIn: parent
width: Math.min(1024, window.width - (window.width * .2))
height: Math.min(600, window.height - (window.height * .2))
}
onClosing: function(close) {
if (window.hasSaved)
return;
@ -61,9 +241,390 @@ Window {
}
}
color: theme.black
color: theme.viewBarBackground
Rectangle {
id: viewBar
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 120
color: theme.viewBarBackground
ColumnLayout {
id: viewsLayout
anchors.top: parent.top
anchors.topMargin: 30
anchors.horizontalCenter: parent.horizontalCenter
Layout.margins: 0
spacing: 22
MyToolButton {
id: homeButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 70
Layout.preferredHeight: 70
Layout.alignment: Qt.AlignCenter
toggledWidth: 0
toggled: homeView.isShown()
toggledColor: theme.iconBackgroundViewBarToggled
imageWidth: 50
imageHeight: 50
source: "qrc:/gpt4all/icons/home.svg"
Accessible.name: qsTr("Home view")
Accessible.description: qsTr("Home view of application")
onClicked: {
homeView.show()
}
}
Text {
Layout.topMargin: -20
text: qsTr("Home")
font.pixelSize: theme.fontSizeFixedSmall
font.bold: true
color: homeButton.hovered ? homeButton.backgroundColorHovered : homeButton.backgroundColor
Layout.preferredWidth: 70
horizontalAlignment: Text.AlignHCenter
TapHandler {
onTapped: function(eventPoint, button) {
homeView.show()
}
}
}
MyToolButton {
id: chatButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 70
Layout.preferredHeight: 70
Layout.alignment: Qt.AlignCenter
toggledWidth: 0
toggled: chatView.isShown()
toggledColor: theme.iconBackgroundViewBarToggled
imageWidth: 50
imageHeight: 50
source: "qrc:/gpt4all/icons/chat.svg"
Accessible.name: qsTr("Chat view")
Accessible.description: qsTr("Chat view to interact with models")
onClicked: {
chatView.show()
}
}
ChatView {
anchors.fill: parent
Text {
Layout.topMargin: -20
text: qsTr("Chats")
font.pixelSize: theme.fontSizeFixedSmall
font.bold: true
color: chatButton.hovered ? chatButton.backgroundColorHovered : chatButton.backgroundColor
Layout.preferredWidth: 70
horizontalAlignment: Text.AlignHCenter
TapHandler {
onTapped: function(eventPoint, button) {
chatView.show()
}
}
}
MyToolButton {
id: searchButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 70
Layout.preferredHeight: 70
toggledWidth: 0
toggled: downloadView.isShown()
toggledColor: theme.iconBackgroundViewBarToggled
imageWidth: 50
imageHeight: 50
source: "qrc:/gpt4all/icons/models.svg"
Accessible.name: qsTr("Search")
Accessible.description: qsTr("Models view to explore and download models")
onClicked: {
downloadView.show()
}
}
Text {
Layout.topMargin: -20
text: qsTr("Models")
font.pixelSize: theme.fontSizeFixedSmall
font.bold: true
color: searchButton.hovered ? searchButton.backgroundColorHovered : searchButton.backgroundColor
Layout.preferredWidth: 70
horizontalAlignment: Text.AlignHCenter
TapHandler {
onTapped: function(eventPoint, button) {
downloadView.show()
}
}
}
MyToolButton {
id: localdocsButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 70
Layout.preferredHeight: 70
toggledWidth: 0
toggledColor: theme.iconBackgroundViewBarToggled
toggled: localDocsView.isShown()
imageWidth: 50
imageHeight: 50
source: "qrc:/gpt4all/icons/db.svg"
Accessible.name: qsTr("LocalDocs")
Accessible.description: qsTr("LocalDocs view to configure and use local docs")
onClicked: {
localDocsView.show()
}
}
Text {
Layout.topMargin: -20
text: qsTr("LocalDocs")
font.pixelSize: theme.fontSizeFixedSmall
font.bold: true
color: localdocsButton.hovered ? localdocsButton.backgroundColorHovered : localdocsButton.backgroundColor
Layout.preferredWidth: 70
horizontalAlignment: Text.AlignHCenter
TapHandler {
onTapped: function(eventPoint, button) {
localDocsView.show()
}
}
}
MyToolButton {
id: settingsButton
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
backgroundColorHovered: theme.iconBackgroundViewBarHovered
Layout.preferredWidth: 70
Layout.preferredHeight: 70
toggledWidth: 0
toggledColor: theme.iconBackgroundViewBarToggled
toggled: settingsView.isShown()
imageWidth: 50
imageHeight: 50
source: "qrc:/gpt4all/icons/settings.svg"
Accessible.name: qsTr("Settings")
Accessible.description: qsTr("Settings view for application configuration")
onClicked: {
settingsView.show(0 /*pageToDisplay*/)
}
}
Text {
Layout.topMargin: -20
text: qsTr("Settings")
font.pixelSize: theme.fontSizeFixedSmall
font.bold: true
color: settingsButton.hovered ? settingsButton.backgroundColorHovered : settingsButton.backgroundColor
Layout.preferredWidth: 70
horizontalAlignment: Text.AlignHCenter
TapHandler {
onTapped: function(eventPoint, button) {
settingsView.show(0 /*pageToDisplay*/)
}
}
}
}
ColumnLayout {
id: buttonsLayout
anchors.bottom: parent.bottom
anchors.margins: 0
anchors.bottomMargin: 25
anchors.horizontalCenter: parent.horizontalCenter
Layout.margins: 0
spacing: 22
Rectangle {
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: image.width
Layout.preferredHeight: image.height
color: "transparent"
Image {
id: image
anchors.centerIn: parent
sourceSize.width: 80
sourceSize.height: 55
fillMode: Image.PreserveAspectFit
mipmap: true
visible: false
source: "qrc:/gpt4all/icons/nomic_logo.svg"
}
ColorOverlay {
anchors.fill: image
source: image
color: image.hovered ? theme.logoColorHovered : theme.logoColor
TapHandler {
onTapped: function(eventPoint, button) {
Qt.openUrlExternally("https://nomic.ai")
}
}
}
}
}
}
Rectangle {
id: roundedFrame
z: 299
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: viewBar.right
anchors.right: parent.right
anchors.topMargin: 15
anchors.bottomMargin: 15
anchors.rightMargin: 15
radius: 15
border.width: 2
border.color: theme.dividerColor
color: "transparent"
clip: true
}
RectangularGlow {
id: effect
anchors.fill: roundedFrame
glowRadius: 15
spread: 0
color: theme.dividerColor
cornerRadius: 10
opacity: 0.5
}
StackLayout {
id: stackLayout
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: viewBar.right
anchors.right: parent.right
anchors.topMargin: 15
anchors.bottomMargin: 15
anchors.rightMargin: 15
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: roundedFrame.width
height: roundedFrame.height
radius: 15
}
}
HomeView {
id: homeView
Layout.fillWidth: true
Layout.fillHeight: true
shouldShowFirstStart: !hasCheckedFirstStart
function show() {
stackLayout.currentIndex = 0;
}
function isShown() {
return stackLayout.currentIndex === 0
}
Connections {
target: homeView
function onChatViewRequested() {
chatView.show();
}
function onLocalDocsViewRequested() {
localDocsView.show();
}
function onDownloadViewRequested(showEmbeddingModels) {
downloadView.show(showEmbeddingModels);
}
function onSettingsViewRequested(page) {
settingsView.show(page);
}
}
}
ChatView {
id: chatView
Layout.fillWidth: true
Layout.fillHeight: true
function show() {
stackLayout.currentIndex = 1;
}
function isShown() {
return stackLayout.currentIndex === 1
}
Connections {
target: chatView
function onDownloadViewRequested(showEmbeddingModels) {
downloadView.show(showEmbeddingModels);
}
function onSettingsViewRequested(page) {
settingsView.show(page);
}
}
}
ModelDownloaderView {
id: downloadView
Layout.fillWidth: true
Layout.fillHeight: true
function show(showEmbeddingModels) {
stackLayout.currentIndex = 2;
if (showEmbeddingModels)
downloadView.showEmbeddingModels();
}
function isShown() {
return stackLayout.currentIndex === 2
}
Item {
Accessible.name: qsTr("Download new models")
Accessible.description: qsTr("View for downloading new models")
}
}
LocalDocsView {
id: localDocsView
Layout.fillWidth: true
Layout.fillHeight: true
function show() {
stackLayout.currentIndex = 3;
}
function isShown() {
return stackLayout.currentIndex === 3
}
}
SettingsView {
id: settingsView
Layout.fillWidth: true
Layout.fillHeight: true
function show(page) {
settingsView.pageToDisplay = page;
stackLayout.currentIndex = 4;
}
function isShown() {
return stackLayout.currentIndex === 4
}
onDownloadClicked: {
downloadView.show(true /*showEmbeddingModels*/)
}
}
}
}

@ -98,4 +98,17 @@ MyDialog {
Accessible.description: qsTr("Contains embedded link to https://home.nomic.ai")
}
}
MyButton {
id: checkForUpdatesButton
anchors.right: parent.right
anchors.bottom: parent.bottom
text: qsTr("Check for updates...")
font.pixelSize: theme.fontSizeLarge
Accessible.description: qsTr("Launch an external application that will check for updates to the installer")
onClicked: {
if (!LLM.checkForUpdates())
checkForUpdatesError.open()
}
}
}

@ -16,20 +16,29 @@ Rectangle {
id: theme
}
signal downloadClicked
signal aboutClicked
color: theme.viewBackground
color: theme.containerBackground
Rectangle {
id: borderRight
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 2
color: theme.dividerColor
}
Item {
anchors.fill: parent
anchors.margins: 10
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: borderRight.left
anchors.margins: 20
Accessible.role: Accessible.Pane
Accessible.name: qsTr("Drawer")
Accessible.description: qsTr("Main navigation drawer")
MyButton {
MySettingsButton {
id: newChat
anchors.left: parent.left
anchors.right: parent.right
@ -50,7 +59,7 @@ Rectangle {
anchors.rightMargin: -10
anchors.topMargin: 10
anchors.top: newChat.bottom
anchors.bottom: checkForUpdatesButton.top
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
clip: true
@ -236,45 +245,5 @@ Rectangle {
Accessible.description: qsTr("List of chats in the drawer dialog")
}
}
MyButton {
id: checkForUpdatesButton
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: downloadButton.top
anchors.bottomMargin: 10
text: qsTr("Updates")
font.pixelSize: theme.fontSizeLarge
Accessible.description: qsTr("Launch an external application that will check for updates to the installer")
onClicked: {
if (!LLM.checkForUpdates())
checkForUpdatesError.open()
}
}
MyButton {
id: downloadButton
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: aboutButton.top
anchors.bottomMargin: 10
text: qsTr("Downloads")
Accessible.description: qsTr("Launch a dialog to download new models")
onClicked: {
downloadClicked()
}
}
MyButton {
id: aboutButton
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
text: qsTr("About")
Accessible.description: qsTr("Launch a dialog to show the about page")
onClicked: {
aboutClicked()
}
}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,299 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import llm
import chatlistmodel
import download
import modellist
import network
import gpt4all
import mysettings
Rectangle {
id: homeView
Theme {
id: theme
}
color: theme.viewBackground
signal chatViewRequested()
signal localDocsViewRequested()
signal settingsViewRequested(int page)
signal downloadViewRequested(bool showEmbeddingModels)
property bool shouldShowFirstStart: false
ColumnLayout {
id: mainArea
anchors.fill: parent
anchors.margins: 30
spacing: 30
ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: 1530
Layout.alignment: Qt.AlignCenter
spacing: 30
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 5
Text {
id: welcome
Layout.alignment: Qt.AlignHCenter
text: qsTr("Welcome to GPT4All")
font.pixelSize: theme.fontSizeBanner
color: theme.titleTextColor
}
Text {
Layout.alignment: Qt.AlignHCenter
text: qsTr("the privacy-first LLM chat application")
font.pixelSize: theme.fontSizeLarge
color: theme.mutedTextColor
}
}
MyButton {
id: startChat
visible: shouldShowFirstStart
Layout.alignment: Qt.AlignHCenter
text: qsTr("Start chatting")
onClicked: {
chatViewRequested()
}
}
// FIXME! We need a spot for dynamic content to be loaded here
RowLayout {
spacing: 15
visible: !startChat.visible
Layout.alignment: Qt.AlignHCenter
MyWelcomeButton {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.preferredHeight: 150
text: qsTr("Start Chatting")
description: qsTr("Chat with any LLM")
imageSource: "qrc:/gpt4all/icons/chat.svg"
onClicked: {
chatViewRequested()
}
}
MyWelcomeButton {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.preferredHeight: 150
text: qsTr("LocalDocs")
description: qsTr("Chat with your local files")
imageSource: "qrc:/gpt4all/icons/db.svg"
onClicked: {
localDocsViewRequested()
}
}
MyWelcomeButton {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.preferredHeight: 150
text: qsTr("Find Models")
description: qsTr("Explore and download models")
imageSource: "qrc:/gpt4all/icons/models.svg"
onClicked: {
downloadViewRequested(false /*show embedding models*/)
}
}
}
Item {
visible: !startChat.visible
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 150
Layout.maximumHeight: textArea.height
Rectangle {
id: roundedFrame
anchors.fill: parent
z: 299
radius: 10
border.width: 1
border.color: theme.controlBorder
color: "transparent"
clip: true
}
Item {
anchors.fill: parent
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: roundedFrame.width
height: roundedFrame.height
radius: 10
}
}
RowLayout {
spacing: 0
anchors.fill: parent
Rectangle {
color: "transparent"
width: 100
height: 100
Image {
id: changelogImg
anchors.centerIn: parent
sourceSize.width: 64
sourceSize.height: 64
mipmap: true
visible: false
source: "qrc:/gpt4all/icons/changelog.svg"
}
ColorOverlay {
anchors.fill: changelogImg
source: changelogImg
color: theme.changeLogColor
}
}
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
TextArea {
id: textArea
padding: 30
color: theme.changeLogColor
font.pixelSize: theme.fontSizeLarge
textFormat: TextEdit.MarkdownText
text: "### "
+ qsTr("Release notes for version ")
+ Download.releaseInfo.version
+ Download.releaseInfo.notes
+ "<br />\n### "
+ qsTr("Contributors")
+ Download.releaseInfo.contributors
background: Rectangle {
implicitWidth: 150
color: theme.conversationBackground
}
focus: false
readOnly: true
selectByKeyboard: false
selectByMouse: false
Accessible.role: Accessible.Paragraph
Accessible.name: qsTr("Release notes")
Accessible.description: qsTr("Release notes for this version")
}
}
}
}
}
}
Rectangle {
id: linkBar
Layout.alignment: Qt.AlignBottom
Layout.fillWidth: true
border.width: 1
border.color: theme.dividerColor
radius: 6
z: 200
height: 50
color: theme.conversationBackground
RowLayout {
anchors.fill: parent
spacing: 0
RowLayout {
Layout.alignment: Qt.AlignLeft
spacing: 40
MyFancyLink {
text: qsTr("Changelog")
imageSource: "qrc:/gpt4all/icons/changelog.svg"
onClicked: { Qt.openUrlExternally("!fixme!") }
}
MyFancyLink {
text: qsTr("Discord")
imageSource: "qrc:/gpt4all/icons/discord.svg"
onClicked: { Qt.openUrlExternally("https://discord.gg/4M2QFmTt2k") }
}
MyFancyLink {
text: qsTr("X (Twitter)")
imageSource: "qrc:/gpt4all/icons/twitter.svg"
onClicked: { Qt.openUrlExternally("https://twitter.com/nomic_ai") }
}
MyFancyLink {
text: qsTr("Github")
imageSource: "qrc:/gpt4all/icons/github.svg"
onClicked: { Qt.openUrlExternally("https://github.com/nomic-ai/gpt4all") }
}
}
RowLayout {
Layout.alignment: Qt.AlignRight
spacing: 40
MyFancyLink {
text: qsTr("GPT4All.io")
imageSource: "qrc:/gpt4all/icons/globe.svg"
onClicked: { Qt.openUrlExternally("https://gpt4all.io") }
}
}
}
}
}
}
// MyToolButton {
// id: networkButton
// backgroundColor: theme.iconBackgroundViewBar
// backgroundColorHovered: toggled ? backgroundColor : theme.iconBackgroundViewBarHovered
// toggledColor: theme.iconBackgroundViewBar
// Layout.preferredWidth: 40
// Layout.preferredHeight: 40
// scale: 1.2
// toggled: MySettings.networkIsActive
// source: "qrc:/gpt4all/icons/network.svg"
// Accessible.name: qsTr("Network")
// Accessible.description: qsTr("Reveals a dialogue where you can opt-in for sharing data over network")
// onClicked: {
// if (MySettings.networkIsActive) {
// MySettings.networkIsActive = false
// Network.sendNetworkToggled(false);
// } else
// networkDialog.open()
// }
// }
// MyToolButton {
// id: infoButton
// backgroundColor: theme.iconBackgroundViewBar
// backgroundColorHovered: theme.iconBackgroundViewBarHovered
// Layout.preferredWidth: 40
// Layout.preferredHeight: 40
// scale: 1.2
// source: "qrc:/gpt4all/icons/info.svg"
// Accessible.name: qsTr("About")
// Accessible.description: qsTr("Reveals an about dialog")
// onClicked: {
// aboutDialog.open()
// }
// }

@ -0,0 +1,397 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import llm
import chatlistmodel
import download
import modellist
import network
import gpt4all
import mysettings
import localdocs
Rectangle {
id: localDocsView
Theme {
id: theme
}
color: theme.viewBackground
signal chatViewRequested()
signal localDocsViewRequested()
signal settingsViewRequested(int page)
signal downloadViewRequested(bool showEmbeddingModels)
ColumnLayout {
id: mainArea
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: 30
spacing: 50
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 50
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
Layout.minimumWidth: 200
spacing: 5
Text {
id: welcome
text: qsTr("LocalDocs")
font.pixelSize: theme.fontSizeBanner
color: theme.titleTextColor
}
Text {
text: qsTr("Chat with your local files")
font.pixelSize: theme.fontSizeLarge
color: theme.mutedTextColor
}
}
Rectangle {
Layout.fillWidth: true
height: 0
}
MyButton {
Layout.alignment: Qt.AlignTop | Qt.AlignRight
text: qsTr("\uFF0B Add Doc Collection")
}
}
ScrollView {
id: scrollView
ScrollBar.vertical.policy: ScrollBar.AsNeeded
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
ListView {
id: collectionListView
model: LocalDocs.localDocsModel
boundsBehavior: Flickable.StopAtBounds
spacing: 30
delegate: Rectangle {
width: collectionListView.width
height: childrenRect.height + 60
color: theme.conversationBackground
radius: 10
border.width: 1
border.color: theme.controlBorder
property bool removing: false
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 30
spacing: 10
RowLayout {
Layout.fillWidth: true
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: collection
elide: Text.ElideRight
color: theme.titleTextColor
font.pixelSize: theme.fontSizeLargest
font.bold: true
}
Item {
Layout.alignment: Qt.AlignRight
Layout.preferredWidth: state.contentWidth + 50
Layout.preferredHeight: state.contentHeight + 10
ProgressBar {
id: itemProgressBar
anchors.fill: parent
value: {
if (model.error !== "")
return 0
if (model.indexing)
return (model.totalBytesToIndex - model.currentBytesToIndex) / model.totalBytesToIndex
if (model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex)
return (model.currentEmbeddingsToIndex / model.totalEmbeddingsToIndex)
return 0
}
background: Rectangle {
implicitHeight: 45
color: {
if (model.error !== "")
return "transparent"
if (model.indexing)
return "#fff9d2"//theme.progressBackground
if (model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex)
return "#fff9d2"//theme.progressBackground
if (model.forceIndexing)
return theme.red200
return theme.green200
}
radius: 6
}
contentItem: Item {
implicitHeight: 40
Rectangle {
width: itemProgressBar.visualPosition * parent.width
height: parent.height
radius: 2
color: "#fcf0c9" //theme.progressForeground
}
}
Accessible.role: Accessible.ProgressBar
Accessible.name: qsTr("Indexing progressBar")
Accessible.description: qsTr("Shows the progress made in the indexing")
ToolTip.text: model.error
ToolTip.visible: hovered && model.error !== ""
}
Label {
id: state
anchors.centerIn: itemProgressBar
horizontalAlignment: Text.AlignHCenter
color: {
if (model.error !== "")
return theme.textErrorColor
if (model.indexing)
return "#d16f0e"//theme.progressText
if (model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex)
return "#d16f0e"//theme.progressText
if (model.forceIndexing)
return theme.textErrorColor
return theme.green600
}
text: {
if (model.error !== "")
return qsTr("ERROR")
// indicates extracting snippets from documents
if (model.indexing)
return qsTr("INDEXING")
// indicates generating the embeddings for any outstanding snippets
if (model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex)
return qsTr("EMBEDDING")
if (model.forceIndexing)
return qsTr("REQUIRES UPDATE")
if (model.installed)
return qsTr("READY")
return qsTr("INSTALLING")
}
elide: Text.ElideRight
font.bold: true
font.pixelSize: theme.fontSizeSmaller
}
}
}
RowLayout {
Layout.fillWidth: true
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
text: folder_path
elide: Text.ElideRight
color: theme.titleTextColor
font.pixelSize: theme.fontSizeSmall
}
Text {
Layout.alignment: Qt.AlignRight
text: {
if (model.error !== "")
return model.error
if (model.indexing)
return qsTr("Indexing in progress")
if (model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex)
return qsTr("Embedding in progress")
if (model.forceIndexing)
return qsTr("This collection requires an update after version change")
if (model.installed)
return qsTr("Automatically reindexes upon changes to the folder")
return qsTr("Installation in progress")
}
elide: Text.ElideRight
color: theme.logoColor
font.pixelSize: theme.fontSizeSmaller
}
Text {
visible: {
return model.indexing || model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex
}
Layout.alignment: Qt.AlignRight
text: {
var percentComplete = Math.round(itemProgressBar.value * 100);
var formattedPercent = percentComplete < 10 ? " " + percentComplete : percentComplete.toString();
return formattedPercent + qsTr("%")
}
elide: Text.ElideRight
color: theme.logoColor
font.family: "monospace"
font.pixelSize: theme.fontSizeSmaller
}
}
RowLayout {
Text {
text: model.totalDocs + (model.totalDocs > 1 ? qsTr(" files ") : qsTr(" file ")) + model.totalWords + " words"
elide: Text.ElideRight
color: theme.green500
font.pixelSize: theme.fontSizeSmaller
}
Text {
text: model.lastUpdate
elide: Text.ElideRight
color: theme.gray500
font.pixelSize: theme.fontSizeSmaller
}
Text {
text: model.embeddingModel
elide: Text.ElideRight
color: theme.logoColor
font.bold: true
font.pixelSize: theme.fontSizeSmaller
}
Text {
Layout.leftMargin: 15
visible: model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex
text: model.currentEmbeddingsToIndex + " of " + model.totalEmbeddingsToIndex + " embeddings"
elide: Text.ElideRight
color: theme.gray500
font.pixelSize: theme.fontSizeSmaller
}
}
Rectangle {
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
RowLayout {
id: fileProcessingRow
Layout.topMargin: 15
Layout.bottomMargin: 15
visible: model.fileCurrentlyProcessing !== "" && (model.indexing || model.currentEmbeddingsToIndex !== model.totalEmbeddingsToIndex)
MyBusyIndicator {
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 12
Layout.preferredHeight: 12
running: true
size: 12
color: theme.textColor
}
Text {
id: filename
Layout.alignment: Qt.AlignCenter
text: model.fileCurrentlyProcessing
elide: Text.ElideRight
color: theme.textColor
font.bold: true
font.pixelSize: theme.fontSizeLarge
}
}
Rectangle {
visible: fileProcessingRow.visible
Layout.fillWidth: true
height: 1
color: theme.dividerColor
}
RowLayout {
Layout.fillWidth: true
spacing: 30
Layout.leftMargin: 15
Layout.topMargin: 15
Text {
text: qsTr("Local Folder")
elide: Text.ElideRight
color: theme.green600
font.bold: true
font.pixelSize: theme.fontSizeSmall
}
Text {
text: qsTr("Remove")
elide: Text.ElideRight
color: theme.red500
font.bold: true
font.pixelSize: theme.fontSizeSmall
}
Item {
Layout.fillWidth: true
}
Text {
Layout.alignment: Qt.AlignRight
visible: model.forceIndexing
text: qsTr("Update")
elide: Text.ElideRight
color: theme.red500
font.bold: true
font.pixelSize: theme.fontSizeSmall
TapHandler {
onTapped: {
LocalDocs.forceIndexing(collection)
}
}
}
}
}
// Item {
// id: buttons
// anchors.right: parent.right
// anchors.verticalCenter: parent.verticalCenter
// anchors.margins: 20
// width: removeButton.width
// height:removeButton.height
// MySettingsButton {
// id: removeButton
// anchors.centerIn: parent
// text: qsTr("Remove")
// visible: !item.removing
// onClicked: {
// item.removing = true
// LocalDocs.removeFolder(collection, folder_path)
// }
// }
// }
}
}
}
}
}

@ -11,21 +11,15 @@ import modellist
import network
import mysettings
MyDialog {
Rectangle {
id: modelDownloaderDialog
modal: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
padding: 10
property bool showEmbeddingModels: false
onOpened: {
Network.trackEvent("download_dialog")
if (showEmbeddingModels) {
ModelList.downloadableModels.expanded = true
var targetModelIndex = ModelList.defaultEmbeddingModelIndex
modelListView.positionViewAtIndex(targetModelIndex, ListView.Beginning)
}
color: theme.containerBackground
function showEmbeddingModels() {
Network.sendModelDownloaderDialog();
ModelList.downloadableModels.expanded = true
var targetModelIndex = ModelList.defaultEmbeddingModelIndex
modelListView.positionViewAtIndex(targetModelIndex, ListView.Beginning)
}
PopupDialog {
@ -36,7 +30,7 @@ MyDialog {
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
anchors.margins: 20
spacing: 30
Label {

@ -5,16 +5,19 @@ import QtQuick.Controls.Basic
BusyIndicator {
id: control
property real size: 48
property color color: theme.accentColor
contentItem: Item {
implicitWidth: 48
implicitHeight: 48
implicitWidth: control.size
implicitHeight: control.size
Item {
id: item
x: parent.width / 2 - width / 2
y: parent.height / 2 - height / 2
width: 48
height: 48
width: control.size
height: control.size
opacity: control.running ? 1 : 0
Behavior on opacity {
@ -40,21 +43,21 @@ BusyIndicator {
id: delegate
x: item.width / 2 - width / 2
y: item.height / 2 - height / 2
implicitWidth: 10
implicitHeight: 10
radius: 5
color: theme.accentColor
implicitWidth: control.size * .2
implicitHeight: control.size * .2
radius: control.size * .1
color: control.color
required property int index
transform: [
Translate {
y: -Math.min(item.width, item.height) * 0.5 + 5
y: -Math.min(item.width, item.height) * 0.5 + delegate.radius
},
Rotation {
angle: delegate.index / repeater.count * 360
origin.x: 5
origin.y: 5
origin.x: delegate.radius
origin.y: delegate.radius
}
]
}

@ -17,11 +17,13 @@ Button {
property real borderWidth: MySettings.chatTheme === "LegacyDark" ? 1 : 0
property color borderColor: theme.buttonBorder
property real fontPixelSize: theme.fontSizeLarge
property bool fontPixelBold: false
contentItem: Text {
text: myButton.text
horizontalAlignment: Text.AlignHCenter
color: myButton.enabled ? textColor : mutedTextColor
font.pixelSize: fontPixelSize
font.bold: fontPixelBold
Accessible.role: Accessible.Button
Accessible.name: text
}

@ -0,0 +1,45 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import Qt5Compat.GraphicalEffects
import mysettings
MyButton {
id: fancyLink
property alias imageSource: myimage.source
Image {
id: myimage
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 15
sourceSize.width: 24
sourceSize.height: 24
mipmap: true
visible: false
}
ColorOverlay {
anchors.fill: myimage
source: myimage
color: fancyLink.hovered ? theme.fancyLinkTextHovered : theme.fancyLinkText
}
leftPadding: 50
borderWidth: 0
backgroundColor: "transparent"
backgroundColorHovered: "transparent"
fontPixelBold: true
padding: 15
topPadding: 8
bottomPadding: 8
textColor: fancyLink.hovered ? theme.fancyLinkTextHovered : theme.fancyLinkText
fontPixelSize: theme.fontSizeSmall
background: Rectangle {
color: "transparent"
}
Accessible.name: qsTr("Fancy link")
Accessible.description: qsTr("A stylized link")
}

@ -31,9 +31,10 @@ Button {
Image {
id: image
anchors.centerIn: parent
visible: false
mipmap: true
width: 20
height: 20
sourceSize.width: 20
sourceSize.height: 20
}
ColorOverlay {
anchors.fill: image

@ -11,8 +11,8 @@ Button {
leftPadding: 18
property color textColor: MySettings.chatTheme === "Dark" ? theme.green800 : theme.green600
property color mutedTextColor: textColor
property color backgroundColor: MySettings.chatTheme === "Dark" ? theme.green400 : theme.green200
property color backgroundColorHovered: theme.green300
property color backgroundColor: MySettings.chatTheme === "Dark" ? theme.green400 : theme.green100
property color backgroundColorHovered: theme.green200
property real borderWidth: 0
property color borderColor: "transparent"
property real fontPixelSize: theme.fontSizeLarge

@ -9,9 +9,13 @@ Button {
padding: 10
property color backgroundColor: theme.iconBackgroundDark
property color backgroundColorHovered: theme.iconBackgroundHovered
property color toggledColor: theme.accentColor
property real toggledWidth: 1
property bool toggled: false
property alias source: image.source
property alias fillMode: image.fillMode
property alias imageWidth: image.sourceSize.width
property alias imageHeight: image.sourceSize.height
contentItem: Text {
text: myButton.text
horizontalAlignment: Text.AlignHCenter
@ -25,18 +29,20 @@ Button {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "transparent"
color: myButton.toggledColor
visible: myButton.toggled
border.color: theme.accentColor
border.width: 1
radius: 10
border.color: myButton.toggledColor
border.width: myButton.toggledWidth
radius: 15
}
Image {
id: image
anchors.centerIn: parent
visible: false
fillMode: Image.PreserveAspectFit
mipmap: true
width: 30
height: 30
sourceSize.width: 32
sourceSize.height: 32
}
ColorOverlay {
anchors.fill: image

@ -0,0 +1,77 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import Qt5Compat.GraphicalEffects
import QtQuick.Layouts
import mysettings
Button {
id: myButton
property alias imageSource: myimage.source
property alias description: description.text
contentItem: Item {
id: item
anchors.centerIn: parent
RowLayout {
anchors.fill: parent
Rectangle {
id: rec
color: "transparent"
Layout.preferredWidth: item.width * 1/5.5
Layout.preferredHeight: item.width * 1/5.5
Layout.alignment: Qt.AlignCenter
Image {
id: myimage
anchors.centerIn: parent
sourceSize.width: rec.width
sourceSize.height: rec.height
mipmap: true
visible: false
}
ColorOverlay {
anchors.fill: myimage
source: myimage
color: theme.welcomeButtonBorder
}
}
ColumnLayout {
Layout.preferredWidth: childrenRect.width
Text {
text: myButton.text
horizontalAlignment: Text.AlignHCenter
color: myButton.hovered ? theme.welcomeButtonTextHovered : theme.welcomeButtonText
font.pixelSize: theme.fontSizeBannerSmall
font.bold: true
Accessible.role: Accessible.Button
Accessible.name: text
}
Text {
id: description
horizontalAlignment: Text.AlignHCenter
color: myButton.hovered ? theme.welcomeButtonTextHovered : theme.welcomeButtonText
font.pixelSize: theme.fontSizeSmall
font.bold: false
Accessible.role: Accessible.Button
Accessible.name: text
}
}
}
}
background: Rectangle {
radius: 10
border.width: 1
border.color: myButton.hovered ? theme.welcomeButtonBorderHovered : theme.welcomeButtonBorder
color: theme.welcomeButtonBackground
}
Accessible.role: Accessible.Button
Accessible.name: text
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
}

@ -1,132 +0,0 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Dialogs
import QtQuick.Layouts
import Qt.labs.folderlistmodel
import download
import modellist
import network
import llm
import mysettings
MyDialog {
id: settingsDialog
modal: true
padding: 20
onOpened: {
Network.trackEvent("settings_dialog")
}
signal downloadClicked
property alias pageToDisplay: listView.currentIndex
Item {
Accessible.role: Accessible.Dialog
Accessible.name: qsTr("Settings")
Accessible.description: qsTr("Contains various application settings")
}
ListModel {
id: stacksModel
ListElement {
title: qsTr("Models")
}
ListElement {
title: qsTr("Application")
}
ListElement {
title: qsTr("LocalDocs")
}
}
Rectangle {
id: stackList
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 220
color: theme.controlBackground
radius: 10
ScrollView {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 10
ScrollBar.vertical.policy: ScrollBar.AsNeeded
clip: true
ListView {
id: listView
anchors.fill: parent
model: stacksModel
delegate: Rectangle {
id: item
width: listView.width
height: titleLabel.height + 10
color: "transparent"
MyButton {
id: titleLabel
backgroundColor: index === listView.currentIndex ? theme.buttonBackground : theme.controlBackground
backgroundColorHovered: index === listView.currentIndex ? backgroundColor : theme.containerBackground
borderColor: index === listView.currentIndex ? theme.accentColor : "transparent"
borderWidth: index === listView.currentIndex ? 1 : 0
textColor: index === listView.currentIndex ? theme.oppositeTextColor : theme.titleTextColor
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 10
font.bold: index === listView.currentIndex
text: title
font.pixelSize: theme.fontSizeLarge
onClicked: {
listView.currentIndex = index
}
}
}
}
}
}
StackLayout {
id: stackLayout
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: stackList.right
anchors.right: parent.right
currentIndex: listView.currentIndex
MySettingsStack {
title: qsTr("Model/Character Settings")
tabs: [
Component { ModelSettings { } }
]
}
MySettingsStack {
title: qsTr("Application General Settings")
tabs: [
Component { ApplicationSettings { } }
]
}
MySettingsStack {
title: qsTr("Local Document Collections")
tabs: [
Component {
LocalDocsSettings {
id: localDocsSettings
Component.onCompleted: {
localDocsSettings.downloadClicked.connect(settingsDialog.downloadClicked);
}
}
}
]
}
}
}

@ -0,0 +1,132 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Dialogs
import QtQuick.Layouts
import Qt.labs.folderlistmodel
import download
import modellist
import network
import llm
import mysettings
Rectangle {
id: settingsDialog
color: theme.containerBackground
signal downloadClicked
property alias pageToDisplay: listView.currentIndex
Item {
Accessible.role: Accessible.Dialog
Accessible.name: qsTr("Settings")
Accessible.description: qsTr("Contains various application settings")
}
ListModel {
id: stacksModel
ListElement {
title: qsTr("Models")
}
ListElement {
title: qsTr("Application")
}
ListElement {
title: qsTr("LocalDocs")
}
}
Item {
anchors.fill: parent
anchors.margins: 20
Rectangle {
id: stackList
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 220
color: theme.controlBackground
radius: 10
ScrollView {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 10
ScrollBar.vertical.policy: ScrollBar.AsNeeded
clip: true
ListView {
id: listView
anchors.fill: parent
model: stacksModel
delegate: Rectangle {
id: item
width: listView.width
height: titleLabel.height + 10
color: "transparent"
MyButton {
id: titleLabel
backgroundColor: index === listView.currentIndex ? theme.buttonBackground : theme.controlBackground
backgroundColorHovered: index === listView.currentIndex ? backgroundColor : theme.containerBackground
borderColor: index === listView.currentIndex ? theme.accentColor : "transparent"
borderWidth: index === listView.currentIndex ? 1 : 0
textColor: index === listView.currentIndex ? theme.oppositeTextColor : theme.titleTextColor
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 10
font.bold: index === listView.currentIndex
text: title
font.pixelSize: theme.fontSizeLarge
onClicked: {
listView.currentIndex = index
}
}
}
}
}
}
StackLayout {
id: stackLayout
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: stackList.right
anchors.right: parent.right
currentIndex: listView.currentIndex
MySettingsStack {
title: qsTr("Model/Character Settings")
tabs: [
Component { ModelSettings { } }
]
}
MySettingsStack {
title: qsTr("Application General Settings")
tabs: [
Component { ApplicationSettings { } }
]
}
MySettingsStack {
title: qsTr("Local Document Collections")
tabs: [
Component {
LocalDocsSettings {
id: localDocsSettings
Component.onCompleted: {
localDocsSettings.downloadClicked.connect(settingsDialog.downloadClicked);
}
}
}
]
}
}
}
}

@ -3,6 +3,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import download
import network
import llm
@ -31,13 +32,20 @@ MyDialog {
id: img
anchors.top: parent.top
anchors.left: parent.left
width: 60
height: 60
source: "qrc:/gpt4all/icons/logo.svg"
sourceSize.width: 60
sourceSize.height: 60
mipmap: true
visible: false
source: "qrc:/gpt4all/icons/globe.svg"
}
ColorOverlay {
anchors.fill: img
source: img
color: theme.titleTextColor
}
Text {
anchors.left: img.right
anchors.leftMargin: 30
anchors.leftMargin: 10
anchors.verticalCenter: img.verticalCenter
text: qsTr("Welcome!")
color: theme.textColor

@ -26,6 +26,10 @@ QtObject {
property color gray900: Qt.hsla(25/360, 0.05, 0.31)
property color gray950: Qt.hsla(25/360, 0.05, 0.15)
property color grayRed0: "#e7dfdf"
property color grayRed500: "#a48e8e"
property color grayRed900: "#766060"
// darkmode
property color darkgray0: Qt.hsla(25/360, 0.05, 0.23)
property color darkgray50: Qt.hsla(25/360, 0.05, 0.21)
@ -169,12 +173,43 @@ QtObject {
}
}
property color dividerColor: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue950;
case "Dark":
return darkgray200;
default:
return grayRed0;
}
}
property color conversationDivider: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue900;
case "Dark":
return darkgray100;
default:
return gray100;
}
}
property color conversationBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue500;
default:
return containerBackground;
return white;
}
}
property color viewBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue600;
default:
return gray50;
}
}
@ -196,7 +231,18 @@ QtObject {
case "Dark":
return darkgray200;
default:
return gray200;
return gray100;
}
}
property color viewBarBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return blue950;
case "Dark":
return darkgray300;
default:
return gray100;
}
}
@ -229,7 +275,7 @@ QtObject {
case "Dark":
return "#000000";
default:
return "#000000";
return white;
}
}
@ -343,6 +389,90 @@ QtObject {
}
}
property color collectionButtonBackground: {
switch (MySettings.chatTheme) {
default:
return green50;
}
}
property color collectionButtonBackgroundHovered: {
switch (MySettings.chatTheme) {
default:
return green100;
}
}
property color welcomeButtonBackground: {
switch (MySettings.chatTheme) {
default:
return theme.green100;
}
}
property color welcomeButtonBorder: {
switch (MySettings.chatTheme) {
default:
return green300;
}
}
property color welcomeButtonBorderHovered: {
switch (MySettings.chatTheme) {
default:
return green400;
}
}
property color welcomeButtonText: {
switch (MySettings.chatTheme) {
default:
return green700;
}
}
property color welcomeButtonTextHovered: {
switch (MySettings.chatTheme) {
default:
return green800;
}
}
property color fancyLinkText: {
switch (MySettings.chatTheme) {
default:
return grayRed900;
}
}
property color fancyLinkTextHovered: {
switch (MySettings.chatTheme) {
default:
return textColor;
}
}
property color changeLogColor: {
switch (MySettings.chatTheme) {
default:
return grayRed900;
}
}
property color logoColor: {
switch (MySettings.chatTheme) {
default:
return grayRed500;
}
}
property color logoColorHovered: {
switch (MySettings.chatTheme) {
default:
return grayRed900;
}
}
property color iconBackgroundDark: {
switch (MySettings.chatTheme) {
case "LegacyDark":
@ -361,7 +491,7 @@ QtObject {
case "Dark":
return darkwhite;
default:
return white;
return gray500;
}
}
@ -376,6 +506,39 @@ QtObject {
}
}
property color iconBackgroundViewBar: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return iconBackgroundLight;
case "Dark":
return iconBackgroundLight;
default:
return green500;
}
}
property color iconBackgroundViewBarToggled: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return iconBackgroundLight;
case "Dark":
return iconBackgroundLight;
default:
return green200;
}
}
property color iconBackgroundViewBarHovered: {
switch (MySettings.chatTheme) {
case "LegacyDark":
return iconBackgroundHovered;
case "Dark":
return iconBackgroundHovered;
default:
return green600;
}
}
property color slugBackground: {
switch (MySettings.chatTheme) {
case "LegacyDark":
@ -515,7 +678,7 @@ QtObject {
case "Dark":
return green700;
default:
return green700;
return "transparent";
}
}
@ -566,4 +729,10 @@ QtObject {
property real fontSizeLargest: MySettings.fontSize === "Small" ?
fontSize + 7 : MySettings.fontSize === "Medium" ?
fontSize + 12 : fontSize + 14
property real fontSizeBannerSmall: MySettings.fontSize === "Small" ?
fontSize + 17 : MySettings.fontSize === "Medium" ?
fontSize + 22 : fontSize + 24
property real fontSizeBanner: MySettings.fontSize === "Small" ?
fontSize + 47 : MySettings.fontSize === "Medium" ?
fontSize + 52 : fontSize + 54
}

Loading…
Cancel
Save