diff --git a/bun.lockb b/bun.lockb
new file mode 100755
index 0000000..ecac4f9
Binary files /dev/null and b/bun.lockb differ
diff --git a/content/.gitkeep b/content/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/content/Notes/CP/T - Aula 2 - 19 Setembro.md b/content/Notes/CP/T - Aula 2 - 19 Setembro.md
new file mode 100644
index 0000000..307e4e0
--- /dev/null
+++ b/content/Notes/CP/T - Aula 2 - 19 Setembro.md
@@ -0,0 +1,7 @@
+## Conteúdo
+- cache em arquiteturas multicore
+- code profiling
+- instruction-level paralelism
+- Data dependency
+- branch prediction
+-
\ No newline at end of file
diff --git a/content/Notes/MFES/MFES - UC Details.md b/content/Notes/MFES/MFES - UC Details.md
new file mode 100644
index 0000000..2f9a300
--- /dev/null
+++ b/content/Notes/MFES/MFES - UC Details.md
@@ -0,0 +1,37 @@
+## Programa
+
+1. Lógicas para especificação formal
+ 1. [[T - Aula 2 - 18 Setembro 2023#Proposicional Logic (PL)| Lógica Proposicional (PL)]]
+ 2. Lógica de Primeira Ordem (FOL)
+ 3. Lógica relacional (RL)
+ 4. Lógica temporal linear (LTL)
+2. Técnicas de prova automática
+ 1. SAT solving para lógica proposicional
+ 2. SMT solving para lógica e teorias de primeira ordem
+ 3. Model-finding via SAT para lógica relacional
+ 4. Bounded model-checking via SAT para lógica temporal
+3. Concepção formal de software com Alloy
+ 1. Modelação estrutural
+ 2. Modelação comportamental
+4. Especificação e verificação de programas com Why3
+ 1. Linguagem lógica, teorias (biblioteca) e prova
+ 2. Linguagem de programas, especificação comportamental, e verificação de correção
+ 3. Desenvolvimento de sistemas com estado
+
+## Docentes
+- Maria João Frade - [mjf@di.uminho.pt](mailto:mjf@di.uminho.pt)
+- Alcino Cunha - [alcino@di.uminho.pt](mailto:alcino@di.uminho.pt)
+- Jorge Sousa Pinto - [jsp@di.uminho.pt](mailto:jsp@di.uminho.pt)
+
+## Avaliação
+- 20% - Exercícios de avaliação
+- 80% - Teste individual
+
+Nota: As notas acima de 18 valores (quer na avaliação contínua quer no exame) terão que ser defendidas através da realização de um pequeno projecto.
+
+
+## Planificação
+- 6 Outubro - Entrega do 1º exercício de avaliação. Modelação em PL e FOL.
+- 27 Outubro - Entrega do 2º exercício de avaliação. Modelação estrutural em Alloy.
+- 10 Novembro - Entrega do 3º exercício de avaliação. Modelação comportamental em Alloy.
+- 8 Dezembro - Entrega do 1º exercício de avaliação. Desenvolvimento e verificação de sistemas com estado em Why3.
\ No newline at end of file
diff --git a/content/Notes/MFES/T - Aula 2 - 18 Setembro 2023.md b/content/Notes/MFES/T - Aula 2 - 18 Setembro 2023.md
new file mode 100644
index 0000000..96bc7f1
--- /dev/null
+++ b/content/Notes/MFES/T - Aula 2 - 18 Setembro 2023.md
@@ -0,0 +1,121 @@
+# Conteúdo
+1. [[T - Aula 2 - 18 Setembro 2023#1. Intro|Intro]]
+ 1. [[T - Aula 2 - 18 Setembro 2023#1.1 SAT|SAT]]
+ 2. [[T - Aula 2 - 18 Setembro 2023#1.2 Proposicional Logic (PL)|Lógica Proposicional]]
+3. [[T - Aula 2 - 18 Setembro 2023#SAT Solvers|SAT Solvers]]
+
+# 1. Intro
+*Formal modeling* - formally represent the system and its properties in the syntactic conventions that the tool understands and can process.
+
+Formal Logic = logical language (logical symbols + non-logical symbols) + semantics +proof system
+
+### 1.1 SAT
+
+
+The Boolean satisfiability (SAT) problem:
+
+Find an assignment to the propositional variables of the formula such that the formula evaluates to TRUE, or prove that no such assignment exists.
+
+
+- SAT is an NP-complete decision problem.
+ - SAT was the first problem to be shown NP-complete.
+ - There are no known polynomial time algorithms for SAT.
+
+
+Usually SAT solvers deal with formulas in conjunctive normal form (CNF)
+- **literal**: propositional variable or its negation A, ¬A, B, ¬B, C, ¬C
+- **clause**: disjuntion of literals. (A _ ¬B _ C)
+- **conjunctive normal form**: conjuction of clauses. (A _ ¬B _ C) ^ (B _ ¬A) ^ ¬C
+
+ > [!info]+ Cook's theorem(1971)
+ > SAT is NP-complete
+
+
+## 1.2 Proposicional Logic (PL)
+
+>[!note] Nota
+>Esta secção basicamente só contém revisão de conceitos. Aconselha-se a ver a coisa rapidamente, porque é só a formalidade de lógica escrita por extenso.
+
+Let $A$ be an assignment and let $F$ be a formula. If $A(F) = 1$, then we say **$F$ holds under assignment**, or **$A$ models $F$.**
+We write A $\models F$ iff $A(F)=1$, and $A \not \models F$ iff $A(F) = 0$.
+
+
+An assignment is a function $A$ : $V_{prop} \implies {0,1}$ , that assigns to every
+propositional variable a truth value. An assignment $A$ naturally extends to all formulas, $A$ : **Form** $\implies {0,1}$. The truth value of a formula is computed using **truth tables**:
+
+| F | $A$ | $B$ | $\neg A$ | $A \land B$ | $A \lor B$ | $A \implies B$ | $A \iff B$ | $\bot$ | $\top$ |
+| --------- | --- | --- | -------- | ----------- | ---------- | -------------- | ---------- | ------ | ------ |
+| $A_1 (F)$ | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 |
+| $A_2 (F)$ | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
+| $A_3 (F)$ | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 |
+| $A_4 (F)$ | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 |
+
+
+
+A formula $F$ is:
+1. **valid** iff it holds under every assignment. We write $\models F$. A valid formula is called a *tautology*.
+2. **satisfiable** iff it folds (true) under some assignment.
+3. **unsatisfiable** iff it holds under no assignment. An unsatisfiable formula is called a *contradiction*.
+4. **refutable** iff it is not valid.
+
+ > [!tip]+ Proposition
+ > $F$ is **valid** iff $\neg F$ is **unsatisfiable**.
+
+
+- $F \models G$ iff for every assignment $A$, if $A \models F$ then $A \models G$. We say $G$ is a **consequence** of $F$.
+- $F \equiv G$ iff $F \models G$ and $G \models F$. We say $F$ and $G$ are **equivalent**.
+- Let $\Gamma = { F_1, F_2, F_3,... }$ be a set of formulas.
+ - $A \models \Gamma$ iff $A \models F_i$ for each formula $F_i$ in $\Gamma$. We say $A$ models $\Gamma$.
+ - $\Gamma \models G$ iff $A \models \Gamma$ implies $A \models G$ for every assignment $A$. We say $G$ is a **consequence** of $\Gamma$.
+
+ > [!tip]+ Proposition
+ > - $F \models G$ iff $\models F \implies G$.
+ > - $\Gamma \models G$ and $\Gamma$ finite iff $\models \land \Gamma \implies G$.
+ >
+
+ - $\Gamma$ is *consistent* or *satisfiable* iff there is an assignment that models $\Gamma$.
+ - We say that $\Gamma$ is inconsistent or unsatisfiable iff there is not consistent and denote this by $\Gamma \models \bot$.
+
+ > [!tip]+ Proposition
+ > - {$F, \neg F$} $\models \bot$
+ > - If $\Gamma \models \bot$ and $\Gamma \subseteq \Gamma '$, then $\Gamma ' \models \bot$
+ > - $\Gamma \models F$ iff $\Gamma, \neg F \models \bot$
+
+- Formula $G$ is a subformula of formula F if it occurs syntactically within F
+- Formula G is a strict subformula of F if G is a subformula of $F$ and $G \neg = F$
+
+
+**Basic Equivalences:**
+1. $\neg \neg A \equiv A$
+2. $A \lor A \equiv A$
+3. $A \land A \equiv A$
+4. $A \land \neg A \equiv \bot$
+5. $A \lor \neg A \equiv \top$
+6. $A \lor B \equiv B \lor A$
+7. $A \land B \equiv B \land A$
+8. $A \land \top \equiv A$
+9. $A \lor \top \equiv \top$
+10. $A \land \bot \equiv \bot$
+11. $A \lor \bot \equiv A$
+12. $A \land (B \lor A) \equiv A$
+13. $A \land (B \lor C) \equiv (A \land B) \lor (A \land C)$
+14. $A \lor (B \land C) \equiv (A \lor B) \land (A \lor C)$
+15. $\neg (A \lor B) \equiv \neg A \land \neg B$
+16. $\neg (A \land B) \equiv \neg A \lor \neg B$
+17. $A \implies B \equiv \neg A \lor B$
+18. $A \iff B \equiv (A \implies B) \land (B \implies A)$
+
+
+
+
+# 2. SAT Solvers
+- There are several techniques and algorithms for SAT solving.
+- Usually SAT solvers receive as input a formula in a specific syntatical format.
+- SAT solvers deal with formulas in **conjunctive normal form (CNF)**.
+
+- Most current state-of-the-art SAT solvers are based on the **Davis-Putnam-Logemann-Loveland (DPLL) framework**.
+
+## 2.1 DPLL Framework
+The idea is to **incrementally construct an assignment compatible with a CNF**, propagating the implications of the decisions made that are easy to detect and simplifying the clauses.
+
+A CNF is satisfied by an assignment if all its clauses are satisfied. And a clause is satisfied if at least one of its literals is satisfied.
diff --git a/content/Notes/MFES/TP - Aula 1 - 18 Setembro.md b/content/Notes/MFES/TP - Aula 1 - 18 Setembro.md
new file mode 100644
index 0000000..05cdc0e
--- /dev/null
+++ b/content/Notes/MFES/TP - Aula 1 - 18 Setembro.md
@@ -0,0 +1,88 @@
+## Ficha 1
+
+> [!help]+ Ex 1 (Configuração de produtos)
+> Certos produtos, como é o caso dos automóveis, são altamente personalizáveis, mas podem haver dependências entre as configurações. Os clientes podem não estar cientes de todas essas dependências, e poderão escolher opções de configuração inconsistentes.
+> Como são muitas configurações e muitas dependências, podemos usar um SAT solver para verificar se o cliente escolhe opções de configuração consistentes. Para isso, podemos seguir os seguintes passos:
+>
+> 1. Codificar as dependências entre configurações como uma formula proposicional $\psi$
+> 2. Codificar as opções selecionadas pelo cliente como uma fórmula proposicional $\phi$.
+> 3. Usar o SAT solver para verificar se $\psi \land \phi$ não é contraditório.
+>
+> Considere agora a seguinte dependência entre as configurações disponíveis para a personalização de um automóvel:
+>
+> *"O ar condicionado Thermotronic comfort requer uma bateria de alta capacidade, exceto quando combinado com motores a gasolina de 3,2 litros."*
+>
+> Será que um cliente pode escolher o ar condicionado Thermotronic comfort, uma bateria de pequena capacidade e não escolher o motor de 3,2 litros? Como poderia responder a esta pergunta com a ajuda de um SAT solver?
+>
+> > [!tip]- Resolução
+> > Legenda de variáveis utilizadas:
+> > A - ar condicionado
+> > B - bateria alta capacidade
+> > C - motor 3,2 L
+> >
+> >$A \land \neg B \implies G \equiv \neg (A \land \neg B) \lor G \equiv \neg A \lor B \lor G$
+> >
+> >$(\neg A \lor B \lor G) \land A \land \neg B \land \neg G$ ----- SAT?
+> >
+>
+
+
+> [!help]+ Ex 3 (Configuração de computadores)
+> Uma loja de eletrónica permite aos seus clientes personalizar o seu computador, escolhendo entre dois modelos de motherboards e dois modelos de monitor. Cada computador tem que ter obrigatoriamente uma única motherboard, um único CPU, uma única placa gráfica e uma única memória RAM. O computador poderá ou não ter um monitor. A personalização do computador deverá obedecer às regras:
+> 1. A motherboard MB1 quando combinada com a placa gráfica PG1, obriga à utilização da RAM1;
+> 2. A placa gráfica PG1 precisa do CPU1, exceto quando combinada com a memória RAM2;
+> 3. O CPU2 só pode estar instalado na motherboard MB2;
+> 4. O monitor MON1 para poder funcionar precisa da placa gráfca PG1 e da memória RAM2.
+>
+>Codifique este problema em lógica proposicional. Assinale claramente o que denota cada variável proposicional que introduzir e escreva um conjunto de fórmulas proposicionais adequado à sua modelação.
+>
+> > [!hint]- Resolução
+> > Legenda de variáveis utilizadas:
+> > $CPU_1; CPU_2; RAM_1; RAM_2; MB_1; MB_2; PG_1; PG_2; MON_1; MON_2$
+> >
+> > Problema modelado:
+> > 1. $CPU_1 \lor CPU_2$
+> > 2. $CPU_1 \implies \neg CPU_2$
+> > 3. $RAM_1 \lor RAM_2$
+> > 4. $RAM_1 \implies \neg RAM_2$
+> > 5. $MB_1 \lor MB_2$
+> > 6. $MB_1 \implies \neg MB_2$
+> > 7. $PG_1 \lor PG_2$
+> > 8. $PG_1 \implies \neg PG_2$
+> >
+> > 9. $MB_1 \land PG_1 \implies RAM_1$
+> > 10. $PG_1 \implies CPU_1 \lor RAM_2 \equiv PG_1 \land \neg RAM_2 \implies CPU_1$
+> > 11. $CPU_2 \implies MB_2$
+> > 12. $MON_1 \implies PG_1 \land RAM_2$
+>
+> Indique, apenas por palavras, como poderia usar um SAT solver para testar as consistências deste conjunto de regras.
+>
+> Indique, apenas por palavras, como usaria um SAT solver para se pronuncias quanto à velocidade das seguintes afirmações:
+> (a) O monitor MON1 só poderá ser usado com uma motherboard MB1.
+> > [!hint]- Resolução
+> > ??? $T \models MON_1 \implies MB_1$
+> > $T, \neg (MON_1 \implies MB_1) UNSAT$
+> > > [!info] $T \models F$ sse $T, \neg F UNSAT$
+>
+> (b) Um cliente pode personalizar o seu computador da seguinte forma: uma motherboard MB2, o CPU1, a placa gráfica PG2 e a memória RAM1.
+> >[!hint]- Resolução
+> >$T, MB_2 \land CPU_1 \land PG_2 \land RAM_1$ ---- SAT?
+
+> [!help]+ Ex 2 (Distribuição de Gabinetes)
+> Considere que temos 3 gabinetes e queremos distribuir 4 pessoas (Ana=1, Nuno=2, Pedro=3 e Maria=4) por esses gabinetes. Para codificar este problema em lógica proposicional, , vamos ter um conjunto de variáveis proposicionais $x_{p,g}$ com a seguinte semântica:
+> $x_{p,g}$ é verdade sse a pessoa $p$ ocupa o gabinete $g$, com $p=1..4$ e $g=1..3$
+>
+> Considere que forem estipuladas as seguintes regras de ocupação de gabinetes:
+> 1. Cada pessoa ocupa um único gabinete.
+> 2. O Nuno e o Pedro não podem partilhar gabinete.
+> 3. Se a Ana ficar sozinha num gabinete, então o Pedro também terá que ficar sozinho num gabinete.
+> 4. Cada gabinete só pode acomodar, no máximo, 2 pessoas.
+>
+> Escreve um conjunto de fórumlas proposicionais adequado à modelação destas regras.
+>
+> >[!tip]- Resolução (por passos)
+> >**Cada pessoa ocupa só um único gabinete.**
+> > 1. para cada pessoa p = 1..4
+> > 2. pelo menos um gabinete: $x_{p1} \lor x_{p2} \lor x_{p3}$
+> > 3. no máximo 1 gabinete: $x_{p1} \implies \neg x_{p2} \land x_{p3} \equiv x_{p1} \implies \neg (x_{p2} \lor x_{p3} ) \equiv x_{p2} \implies \neg x_{p3}$
+> > 4.
diff --git a/content/Notes/RAS/T - Aula 2 - 19 Setembro 2023.md b/content/Notes/RAS/T - Aula 2 - 19 Setembro 2023.md
new file mode 100644
index 0000000..27517ac
--- /dev/null
+++ b/content/Notes/RAS/T - Aula 2 - 19 Setembro 2023.md
@@ -0,0 +1,159 @@
+## Contents
+1. [[T - Aula 2 - 19 Setembro 2023#Definition of Requirement|Definition of requirement]]
+2. [[T - Aula 2 - 19 Setembro 2023#Functional requirements|Functional requirements]]
+3. [[T - Aula 2 - 19 Setembro 2023#Non-functional requirements|Non-functional requirements]]
+4. [[T - Aula 2 - 19 Setembro 2023#4. User and system requirements|User and system requirements]]
+5. [[T - Aula 2 - 19 Setembro 2023#Recap|Recap]]
+
+## 1. Definition of Requirement
+The requirements express the users necessities and restrictions that are
+placed on the system.
+
+A **requirement** is a capacity that a system must possess, to satisfy the
+users necessities.
+
+The IEEE 610.12-1990 standard definition divides requirements into
+two alternatives:
+1. user needs
+2. system capacities
+
+Requirements can be divided into:
+1. functional requirements
+2. non-functional requirements
+
+A r**equirement that for a stakeholder** can be perceived
+as being **functional**, can be considered as **non-functional**
+for **a different one**.
+
+> [!info] A candidate requirement is a requirement that was identified by some elicitation technique.
+
+
+## 2. Functional requirements
+
+> [!tip] Definition
+> A functional requirement describes a functionality to be made
+available to the users of the system.
+
+- This type of requirements should not mention any technological issue.
+- Ideally, functional requirements must be independent of design and
+implementation aspects.
+
+> [!note]- Note: Cohesion and Completion
+> Collectively, the set of functional requirements must be complete and
+coherent. The set is:
+> - *coherent*, if there are no contradictions among its elements;
+> - *complete*, if it considers all the necessities that the client wishes to see
+satisfied.
+>
+> Defining complete requirements is the most difficult attribute to
+achieve or evaluate.
+
+> [!note]- Note: Implicit and Explicit Requirements
+> Implicit requirements are referred like that because the client may not be aware about these requirements.
+>
+> An **implicit requirement** is a requirement included by the development team, based on the domain knowledge that it possesses, in spite of not having been explicitly requested by the stakeholders.
+>
+> An **explicit requirement** refers to a requirement that was requested by the clients and that is represented in the documentation.
+
+
+## 3. Non-functional requirements
+
+> [!tip] Definition
+> A non-functional requirement corresponds to a set of restrictions
+imposed on the system to be developed.
+
+- Alternative terms: quality requirement or quality attribute
+- It establishes how attractive, fast, or reliable the system is.
+- It includes time constraints, restrictions in the development process, or
+adoption of standards.
+
+> [!example]- Example: Technological restriction
+> The product must be developed in C++.
+
+> [!info] **A non-functional requirement does not change the essence of the system functionalities.**
+
+
+- Non-functional requirements are applicable to the system as a whole
+and not just to some of its parts, as, generally, non-functional requirements **cannot be modularized**.
+
+- The non-functional requirements are frequently **emergent properties** of the system at hand. *An emergent property of a system is a property that can be associated with the system as a whole, but not individually to each of its components.*
+ - *Reliability* is a good example of an emergent property.
+
+
+> [!info] **Non-functional requirements are crucial to decide the system architecture.**
+
+
+
+### 3.1 Classification of non-functional requirements
+
+> [!tip]- Classification: Sommerville (2010)
+> - **product requirements**: characterise aspects of the behaviour of the system itself (*reliability, performance, efficiency, portability, usability, testability, and readability*).
+> - **organisational requirements**: come from strategies and procedures established in the context of the manufacturing process of the system or the client organisation (process standards and implementation requirements).
+> - **external requirements**: have origin in external factors to the system and the development process (interoperability, legal, and ethical requirements).
+
+> [!tip]- Classification: Roberson and Roberson (2006)
+> - **appearance**: the aspect and the aesthetics of the system;
+> - **usability**: the easiness of utilization of the system and everything that permits a more friendly user experience;
+> - **performance**: aspects of speed, real-time, storage capacity, and execution correction;
+> - **operational**: characteristics about what the system must do to work correctly in the environment where it is inserted;
+> - **maintenance and support**: attributes that allow the system to be repaired or improved and new functionalities to be added;
+> - **security**: issues related to access, confidentiality, protection, and integrity of the data;
+> - **cultural and political**: factors related to the stakeholders culture and habits;
+> - **legal**: laws that apply to the system so that it can operate.
+
+#### 3.1.1 Usability
+ - **Ease of use** is related to the efficiency of utilizing a system and with the mechanisms that reduce the errors made by the users.
+ - **Personalization** is associated with the capacity of adapting the system to the tastes of the users.
+ - **Ease of learning** is concerned with the way users are trained to use the system.
+ - **Accessibility** indicates how easy it is to use the system, for people who
+are somehow physically or mentally disabled.
+
+> [!example]- Example: Usability requirements
+> 1. The product shall be easy to use for illiterate persons.
+> 2. The product shall be intuitive to use for children with 4 years old.
+> 3. The product shall be usable by visually impaired persons.
+
+#### 3.1.2 Maintenance and support
+- System maintenance is divided into four types: preventive, corrective, perfective, and adaptive.
+- **Modifiability** is related to maintenance and is dependent on how easy it is to locate the components that must be changed.
+
+> [!example]- Example: Maintenance and support requirements
+> 1. The source code of the product programs should contain comments.
+> 2. The product must be prepared to be translated to any language.
+
+#### 3.1.3 Legal
+> [!example]- Example: Legal requirements
+> 1. The product shall be aligned with the PMBoK guide.
+> 2. The product shall be certified by the Taxing Authority.
+> 3. The product shall fulfil with the copyright.
+
+
+
+## 4. User and system requirements
+
+A **user requirement** represents:
+1. a functionality that the system is expected to provide to its users;
+2. a restriction that is applicable to the operation of that system.
+
+- These requirements are related to the problem domain.
+- They are normally expressed without great mathematical rigour, using natural language and informal diagrams.
+
+
+A **system requirement** constitutes a more detailed specification of a requirement, being generally a formal model of the system. These requirements are oriented towards the solution domain, and are documented in a more technical language than the one
+adopted for the user requirements.
+
+### 4.1 Problem domain
+- The requirements result from necessities that exist in the problem domain to be addressed.
+- User requirements should be described with the problem domain terminology.
+
+
+
+
+
+# Recap
+1. Requirements represent the necessities of the users and the constraints that are applied to a system and that must be considered throughout the development.
+2. The requirements can be classified, according to a first criterion, as either functional or non-functional.
+3. Non-functional requirements are divided in 8 different types: appearance, usability, performance, operational, maintenance and support, security, cultural and political, and legal.
+4. The requirements can be designated as either user or system requirements.
+5. User requirements are related to the problem domain and are usually expressed in a natural language.
+6. A system requirement is oriented towards the solution domain and is a detailed specification of a requirement, generally in the form of a formal model of the system.
diff --git a/content/README.md b/content/README.md
new file mode 100644
index 0000000..af937a3
--- /dev/null
+++ b/content/README.md
@@ -0,0 +1,10 @@
+Basicamente, isto é uma sopa de letras com alguma lógica por detrás (mas não muita). Abandonem as expectativas. :)
+
+## Conteúdo
+### Ano 1 (Mestrado)
+1. [[MFES - UC Details| (MFES) Métodos Formais de Engenharia de Software]]
+2. (ASCN) Aplicações e Serviços de COmpitação em Nuvem
+3. (RAS) Requisitos e Arquiteturas de Software
+4. (CP) Computação Paralela
+5. (DAA) Dados e Aprendizagem Automática
+6. (ESR) Engenharia de Serviços em Rede
diff --git a/docs/features/explorer.md b/docs/features/explorer.md
index 17647de..6f941b8 100644
--- a/docs/features/explorer.md
+++ b/docs/features/explorer.md
@@ -4,9 +4,9 @@ tags:
- component
---
-Quartz features an explorer that allows you to navigate all files and folders on your site. It supports nested folders and has options for customization.
+Quartz features an explorer that allows you to navigate all files and folders on your site. It supports nested folders and is highly customizable.
-By default, it will show all folders and files on your page. To display the explorer in a different spot, you can edit the [[layout]].
+By default, it shows all folders and files on your page. To display the explorer in a different spot, you can edit the [[layout]].
> [!info]
> The explorer uses local storage by default to save the state of your explorer. This is done to ensure a smooth experience when navigating to different pages.
@@ -25,6 +25,14 @@ Component.Explorer({
folderClickBehavior: "collapse", // what happens when you click a folder ("link" to navigate to folder page on click or "collapse" to collapse folder on click)
folderDefaultState: "collapsed", // default state of folders ("collapsed" or "open")
useSavedState: true, // wether to use local storage to save "state" (which folders are opened) of explorer
+ // Sort order: folders first, then files. Sort folders and files alphabetically
+ sortFn: (a, b) => {
+ ... // default implementation shown later
+ },
+ filterFn: undefined,
+ mapFn: undefined,
+ // what order to apply functions in
+ order: ["filter", "map", "sort"],
})
```
@@ -33,9 +41,187 @@ When passing in your own options, you can omit any or all of these fields if you
Want to customize it even more?
- Removing table of contents: remove `Component.Explorer()` from `quartz.layout.ts`
- - (optional): After removing the explorer component, you can move the [[table of contents]] component back to the `left` part of the layout
+ - (optional): After removing the explorer component, you can move the [[table of contents | Table of Contents]] component back to the `left` part of the layout
+- Changing `sort`, `filter` and `map` behavior: explained in [[#Advanced customization]]
- Component:
- Wrapper (Outer component, generates file tree, etc): `quartz/components/Explorer.tsx`
- Explorer node (recursive, either a folder or a file): `quartz/components/ExplorerNode.tsx`
- Style: `quartz/components/styles/explorer.scss`
- Script: `quartz/components/scripts/explorer.inline.ts`
+
+## Advanced customization
+
+This component allows you to fully customize all of its behavior. You can pass a custom `sort`, `filter` and `map` function.
+All functions you can pass work with the `FileNode` class, which has the following properties:
+
+```ts title="quartz/components/ExplorerNode.tsx" {2-5}
+export class FileNode {
+ children: FileNode[] // children of current node
+ name: string // name of node (only useful for folders)
+ file: QuartzPluginData | null // set if node is a file, see `QuartzPluginData` for more detail
+ depth: number // depth of current node
+
+ ... // rest of implementation
+}
+```
+
+Every function you can pass is optional. By default, only a `sort` function will be used:
+
+```ts title="Default sort function"
+// Sort order: folders first, then files. Sort folders and files alphabetically
+Component.Explorer({
+ sortFn: (a, b) => {
+ if ((!a.file && !b.file) || (a.file && b.file)) {
+ return a.name.localeCompare(b.name)
+ }
+ if (a.file && !b.file) {
+ return 1
+ } else {
+ return -1
+ }
+ },
+})
+```
+
+---
+
+You can pass your own functions for `sortFn`, `filterFn` and `mapFn`. All functions will be executed in the order provided by the `order` option (see [[#Customization]]). These functions behave similarly to their `Array.prototype` counterpart, except they modify the entire `FileNode` tree in place instead of returning a new one.
+
+For more information on how to use `sort`, `filter` and `map`, you can check [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), [Array.prototype.filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) and [Array.prototype.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
+
+Type definitions look like this:
+
+```ts
+sortFn: (a: FileNode, b: FileNode) => number
+filterFn: (node: FileNode) => boolean
+mapFn: (node: FileNode) => void
+```
+
+> [!tip]
+> You can check if a `FileNode` is a folder or a file like this:
+>
+> ```ts
+> if (node.file) {
+> // node is a file
+> } else {
+> // node is a folder
+> }
+> ```
+
+## Basic examples
+
+These examples show the basic usage of `sort`, `map` and `filter`.
+
+### Use `sort` to put files first
+
+Using this example, the explorer will alphabetically sort everything, but put all **files** above all **folders**.
+
+```ts title="quartz.layout.ts"
+Component.Explorer({
+ sortFn: (a, b) => {
+ if ((!a.file && !b.file) || (a.file && b.file)) {
+ return a.name.localeCompare(b.name)
+ }
+ if (a.file && !b.file) {
+ return -1
+ } else {
+ return 1
+ }
+ },
+})
+```
+
+### Change display names (`map`)
+
+Using this example, the display names of all `FileNodes` (folders + files) will be converted to full upper case.
+
+```ts title="quartz.layout.ts"
+Component.Explorer({
+ mapFn: (node) => {
+ node.name = node.name.toUpperCase()
+ },
+})
+```
+
+### Remove list of elements (`filter`)
+
+Using this example, you can remove elements from your explorer by providing an array of folders/files using the `omit` set.
+
+```ts title="quartz.layout.ts"
+Component.Explorer({
+ filterFn: (node) => {
+ // set containing names of everything you want to filter out
+ const omit = new Set(["authoring content", "tags", "hosting"])
+ return !omit.has(node.name.toLowerCase())
+ },
+})
+```
+
+You can customize this by changing the entries of the `omit` set. Simply add all folder or file names you want to remove.
+
+## Advanced examples
+
+### Add emoji prefix
+
+To add emoji prefixes (📁 for folders, 📄 for files), you could use a map function like this:
+
+```ts title="quartz.layout.ts"
+Component.Explorer({
+ mapFn: (node) => {
+ // dont change name of root node
+ if (node.depth > 0) {
+ // set emoji for file/folder
+ if (node.file) {
+ node.name = "📄 " + node.name
+ } else {
+ node.name = "📁 " + node.name
+ }
+ }
+ },
+}})
+```
+
+### Putting it all together
+
+In this example, we're going to customize the explorer by using functions from examples above to [[#Add emoji prefix | add emoji prefixes]], [[#remove-list-of-elements-filter| filter out some folders]] and [[#use-sort-to-put-files-first | sort with files above folders]].
+
+```ts title="quartz.layout.ts"
+Component.Explorer({
+ filterFn: sampleFilterFn,
+ mapFn: sampleMapFn,
+ sortFn: sampleSortFn,
+ order: ["filter", "sort", "map"],
+})
+```
+
+Notice how we customized the `order` array here. This is done because the default order applies the `sort` function last. While this normally works well, it would cause unintended behavior here, since we changed the first characters of all display names. In our example, `sort` would be applied based off the emoji prefix instead of the first _real_ character.
+
+To fix this, we just changed around the order and apply the `sort` function before changing the display names in the `map` function.
+
+> [!tip]
+> When writing more complicated functions, the `layout` file can start to look very cramped.
+> You can fix this by defining your functions in another file.
+>
+> ```ts title="functions.ts"
+> import { Options } from "./quartz/components/ExplorerNode"
+> export const mapFn: Options["mapFn"] = (node) => {
+> // implement your function here
+> }
+> export const filterFn: Options["filterFn"] = (node) => {
+> // implement your function here
+> }
+> export const sortFn: Options["sortFn"] = (a, b) => {
+> // implement your function here
+> }
+> ```
+>
+> You can then import them like this:
+>
+> ```ts title="quartz.layout.ts"
+> import { mapFn, filterFn, sortFn } from "./functions.ts"
+> Component.Explorer({
+> mapFn: mapFn,
+> filterFn: filterFn,
+> sortFn: sortFn,
+> })
+> ```
diff --git a/package.json b/package.json
index 0a2085c..2c4edfb 100644
--- a/package.json
+++ b/package.json
@@ -78,6 +78,7 @@
"remark-smartypants": "^2.0.0",
"rimraf": "^5.0.1",
"serve-handler": "^6.1.5",
+ "shiki": "^0.14.4",
"source-map-support": "^0.5.21",
"to-vfile": "^7.2.4",
"toml": "^3.0.0",
diff --git a/quartz.config.ts b/quartz.config.ts
index f677a18..5d8a1f9 100644
--- a/quartz.config.ts
+++ b/quartz.config.ts
@@ -9,7 +9,7 @@ const config: QuartzConfig = {
analytics: {
provider: "plausible",
},
- baseUrl: "quartz.jzhao.xyz",
+ baseUrl: "notes.flup.dev",
ignorePatterns: ["private", "templates", ".obsidian"],
defaultDateType: "created",
theme: {
diff --git a/quartz/components/Explorer.tsx b/quartz/components/Explorer.tsx
index ce69491..8597075 100644
--- a/quartz/components/Explorer.tsx
+++ b/quartz/components/Explorer.tsx
@@ -6,23 +6,62 @@ import script from "./scripts/explorer.inline"
import { ExplorerNode, FileNode, Options } from "./ExplorerNode"
// Options interface defined in `ExplorerNode` to avoid circular dependency
-const defaultOptions = (): Options => ({
+const defaultOptions = {
title: "Explorer",
folderClickBehavior: "collapse",
folderDefaultState: "collapsed",
useSavedState: true,
-})
+ // Sort order: folders first, then files. Sort folders and files alphabetically
+ sortFn: (a, b) => {
+ if ((!a.file && !b.file) || (a.file && b.file)) {
+ return a.name.localeCompare(b.name)
+ }
+ if (a.file && !b.file) {
+ return 1
+ } else {
+ return -1
+ }
+ },
+ order: ["filter", "map", "sort"],
+} satisfies Options
+
export default ((userOpts?: Partial) => {
function Explorer({ allFiles, displayClass, fileData }: QuartzComponentProps) {
// Parse config
- const opts: Options = { ...defaultOptions(), ...userOpts }
+ const opts: Options = { ...defaultOptions, ...userOpts }
// Construct tree from allFiles
const fileTree = new FileNode("")
allFiles.forEach((file) => fileTree.add(file, 1))
- // Sort tree (folders first, then files (alphabetic))
- fileTree.sort()
+ /**
+ * Keys of this object must match corresponding function name of `FileNode`,
+ * while values must be the argument that will be passed to the function.
+ *
+ * e.g. entry for FileNode.sort: `sort: opts.sortFn` (value is sort function from options)
+ */
+ const functions = {
+ map: opts.mapFn,
+ sort: opts.sortFn,
+ filter: opts.filterFn,
+ }
+
+ // Execute all functions (sort, filter, map) that were provided (if none were provided, only default "sort" is applied)
+ if (opts.order) {
+ // Order is important, use loop with index instead of order.map()
+ for (let i = 0; i < opts.order.length; i++) {
+ const functionName = opts.order[i]
+ if (functions[functionName]) {
+ // for every entry in order, call matching function in FileNode and pass matching argument
+ // e.g. i = 0; functionName = "filter"
+ // converted to: (if opts.filterFn) => fileTree.filter(opts.filterFn)
+
+ // @ts-ignore
+ // typescript cant statically check these dynamic references, so manually make sure reference is valid and ignore warning
+ fileTree[functionName].call(fileTree, functions[functionName])
+ }
+ }
+ }
// Get all folders of tree. Initialize with collapsed state
const folders = fileTree.getFolderPaths(opts.folderDefaultState === "collapsed")
@@ -57,8 +96,9 @@ export default ((userOpts?: Partial) => {
-
+
+
diff --git a/quartz/components/ExplorerNode.tsx b/quartz/components/ExplorerNode.tsx
index 6718ec9..fd0c082 100644
--- a/quartz/components/ExplorerNode.tsx
+++ b/quartz/components/ExplorerNode.tsx
@@ -1,12 +1,18 @@
// @ts-ignore
-import { QuartzPluginData } from "vfile"
+import { QuartzPluginData } from "../plugins/vfile"
import { resolveRelative } from "../util/path"
+type OrderEntries = "sort" | "filter" | "map"
+
export interface Options {
title: string
folderDefaultState: "collapsed" | "open"
folderClickBehavior: "collapse" | "link"
useSavedState: boolean
+ sortFn: (a: FileNode, b: FileNode) => number
+ filterFn?: (node: FileNode) => boolean
+ mapFn?: (node: FileNode) => void
+ order?: OrderEntries[]
}
type DataWrapper = {
@@ -29,7 +35,7 @@ export class FileNode {
constructor(name: string, file?: QuartzPluginData, depth?: number) {
this.children = []
this.name = name
- this.file = file ?? null
+ this.file = file ? structuredClone(file) : null
this.depth = depth ?? 0
}
@@ -65,6 +71,25 @@ export class FileNode {
this.children.forEach((e) => e.print(depth + 1))
}
+ /**
+ * Filter FileNode tree. Behaves similar to `Array.prototype.filter()`, but modifies tree in place
+ * @param filterFn function to filter tree with
+ */
+ filter(filterFn: (node: FileNode) => boolean) {
+ this.children = this.children.filter(filterFn)
+ this.children.forEach((child) => child.filter(filterFn))
+ }
+
+ /**
+ * Filter FileNode tree. Behaves similar to `Array.prototype.map()`, but modifies tree in place
+ * @param mapFn function to use for mapping over tree
+ */
+ map(mapFn: (node: FileNode) => void) {
+ mapFn(this)
+
+ this.children.forEach((child) => child.map(mapFn))
+ }
+
/**
* Get folder representation with state of tree.
* Intended to only be called on root node before changes to the tree are made
@@ -90,19 +115,13 @@ export class FileNode {
}
// Sort order: folders first, then files. Sort folders and files alphabetically
- sort() {
- this.children = this.children.sort((a, b) => {
- if ((!a.file && !b.file) || (a.file && b.file)) {
- return a.name.localeCompare(b.name)
- }
- if (a.file && !b.file) {
- return 1
- } else {
- return -1
- }
- })
-
- this.children.forEach((e) => e.sort())
+ /**
+ * Sorts tree according to sort/compare function
+ * @param sortFn compare function used for `.sort()`, also used recursively for children
+ */
+ sort(sortFn: (a: FileNode, b: FileNode) => number) {
+ this.children = this.children.sort(sortFn)
+ this.children.forEach((e) => e.sort(sortFn))
}
}
@@ -131,7 +150,7 @@ export function ExplorerNode({ node, opts, fullPath, fileData }: ExplorerNodePro
// Single file node