Skip to content

Commit

Permalink
Merge branch 'main' into frameworks-frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
levxyca authored Oct 10, 2024
2 parents fc4b9fa + 75583af commit e8f89d5
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 25 deletions.
24 changes: 19 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,32 @@ Existem diversas formas de contribuir com o projeto:
* **Recomendação:** Visual Studio Code (gratuito, open-source, amplamente utilizado)
* **Outras opções:** Sublime Text, Atom

### 2. **Instale um pré-processador SASS**
### 2. **Execute o Projeto**
Para visualizar seu projeto, você pode abrir o arquivo `index.html` em um navegador. Se quiser usar um servidor local (opcional), você pode instalar uma extensão no seu editor ou usar ferramentas como o **Live Server** no Visual Studio Code.

<details>
<summary>
:rotating_light: Para efetuar alterações em documentações
</summary>
Você pode utilizar o Github.Dev para efetuar as alterações em arquivos do tipo markdown para isso é só ir no repositório e apertar a tecla . (ponto)
</details>
<br>
<details>
<summary>
:rotating_light: Para efetuar alterações visuais
</summary>
Caso queira mexer na parte visual do Diciotech, você também vai precisar, antes de executar o projeto:

#### 1. **Instale um pré-processador SASS**
Para compilar SASS em CSS, você precisará de um compilador. Recomendo a leitura do https://sass-lang.com/guide/ 👀

### 3. **Compile seu SASS**
#### 2. **Compile seu SASS**
Para compilar seu SASS em CSS, abra o terminal na pasta do seu projeto e execute:
```bash
sass scss/styles.scss css/styles.css --watch
```
O `--watch` faz com que o SASS fique monitorando alterações no arquivo `.scss` e compile automaticamente.

### 4. **Execute o Projeto**
Para visualizar seu projeto, você pode abrir o arquivo `index.html` em um navegador. Se quiser usar um servidor local (opcional), você pode instalar uma extensão no seu editor ou usar ferramentas como o **Live Server** no Visual Studio Code.
</details>

### Adicionando um novo termo técnico no Diciotech

Expand Down
101 changes: 101 additions & 0 deletions assets/js/levenshtein.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Levenshtein algorithm by Gustaf Andersson: https://github.com/gustf/js-levenshtein
function _min(d0, d1, d2, bx, ay)
{
return d0 < d1 || d2 < d1
? d0 > d2
? d2 + 1
: d0 + 1
: bx === ay
? d1
: d1 + 1;
}

export function levenshtein(a, b)
{
if (a === b) {
return 0;
}

if (a.length > b.length) {
var tmp = a;
a = b;
b = tmp;
}

var la = a.length;
var lb = b.length;

while (la > 0 && (a.charCodeAt(la - 1) === b.charCodeAt(lb - 1))) {
la--;
lb--;
}

var offset = 0;

while (offset < la && (a.charCodeAt(offset) === b.charCodeAt(offset))) {
offset++;
}

la -= offset;
lb -= offset;

if (la === 0 || lb < 3) {
return lb;
}

var x = 0;
var y;
var d0;
var d1;
var d2;
var d3;
var dd;
var dy;
var ay;
var bx0;
var bx1;
var bx2;
var bx3;

var vector = [];

for (y = 0; y < la; y++) {
vector.push(y + 1);
vector.push(a.charCodeAt(offset + y));
}

var len = vector.length - 1;

for (; x < lb - 3;) {
bx0 = b.charCodeAt(offset + (d0 = x));
bx1 = b.charCodeAt(offset + (d1 = x + 1));
bx2 = b.charCodeAt(offset + (d2 = x + 2));
bx3 = b.charCodeAt(offset + (d3 = x + 3));
dd = (x += 4);
for (y = 0; y < len; y += 2) {
dy = vector[y];
ay = vector[y + 1];
d0 = _min(dy, d0, d1, bx0, ay);
d1 = _min(d0, d1, d2, bx1, ay);
d2 = _min(d1, d2, d3, bx2, ay);
dd = _min(d2, d3, dd, bx3, ay);
vector[y] = dd;
d3 = d2;
d2 = d1;
d1 = d0;
d0 = dy;
}
}

for (; x < lb;) {
bx0 = b.charCodeAt(offset + (d0 = x));
dd = ++x;
for (y = 0; y < len; y += 2) {
dy = vector[y];
vector[y] = dd = _min(dy, d0, dd, bx0, vector[y + 1]);
d0 = dy;
}
}

return dd;
}
162 changes: 142 additions & 20 deletions assets/js/script.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import "./dark_mode.js";
import { levenshtein } from "./levenshtein.js";

const exactWordScore = 12;
const partialWordScore = 10;
const levenshteinScore = 10;
const levenshteinThreshold = 3;

const searchInput = document.querySelector("#search-input");
const cardsSection = document.querySelector("#cards");
const filterSelect = document.querySelector("#tags-filter");
let listOfCardsFiltered = [];
let favoriteCards = [];

const starIcon = "https://img.icons8.com/ios/50/star--v1.png";
const starIconFilled =
"https://img.icons8.com/ios-glyphs/30/ffe100/star--v1.png";
Expand Down Expand Up @@ -52,30 +59,145 @@ function filterCards() {
searchCards();
}

function sortCards(sortingArray) {
if (listOfCardsFiltered.length > 0) {
if (!Array.isArray(sortingArray) || !sortingArray.length) {
const cards = document.querySelector("#cards");
// selects all cards that are not hidden and sorts them by title
// every child is re-appended to cards in the order of the now sorted array. When an element is re-appended it is actually moved from its previous location
[...cards.querySelectorAll(".card:not([style*='display: none;'])")]
.sort((a, b) => a.querySelector(".card__title").textContent.toLowerCase().localeCompare(b.querySelector(".card__title").textContent.toLowerCase()))
.forEach(node => cards.appendChild(node));
} else {
const cards = document.querySelector("#cards");
// selects all cards that are not hidden and sorts them by the order of the sortingArray
// every child is re-appended to cards in the order of the now sorted array. When an element is re-appended it is actually moved from its previous location
[...cards.querySelectorAll(".card:not([style*='display: none;'])")]
.sort((a, b) => sortingArray.indexOf(a) - sortingArray.indexOf(b))
.forEach(node => cards.appendChild(node));
}
}
}

function searchCards() {
const inputValue = searchInput.value.toLowerCase();
let cardsFiltered = [];
const inputValue = searchInput.value.toLowerCase().trim();
let cardsScores = [];

for (const card of listOfCardsFiltered) {
const cardContent = card.textContent.toLowerCase();
if (inputValue.length > 0) {
const searchWords = inputValue.split(/\s+/);

if (cardContent.includes(inputValue)){
card.style.display = "";
cardsFiltered.push(card);
for (const card of listOfCardsFiltered) {
let cardScore = 0;

// search for words inside the title that either contains the search words or have a low levenshtein distance
// only consider the best case for each search word
const cardTitle = card.querySelector(".card__title").textContent.toLowerCase();
const titleWords = cardTitle.split(/\s+/);
let titleScore = 0;

searchWords.forEach((searchWord) => {
let wordScore = 0;

titleWords.some((word) => {
if (word == searchWord) {
// breaks the loop if the word is an exact match, since no other word can have a higher score
wordScore = exactWordScore;
return true;

} else if (wordScore < partialWordScore) {
if (word.includes(searchWord)) {
wordScore = partialWordScore;

} else if (word.length > 3) {
const levenshteinDistance = levenshtein(searchWord, word);

// only the word with the lowest levenshtein distance will be considered
if ((levenshteinDistance <= levenshteinThreshold) && (levenshteinScore - levenshteinDistance > wordScore)) {
wordScore = levenshteinScore - levenshteinDistance;
}
}
}
});

titleScore += wordScore;
});

// give extra points for words in title
cardScore += titleScore * 10;

// search for words inside the description that either contains the search words or have a low levenshtein distance
// only consider the best case for each search word
const cardDescription = card.querySelector(".card__description").textContent.toLowerCase();
const descriptionWords = cardDescription.split(/\s+/);
let descriptionScore = 0;

searchWords.forEach((searchWord) => {
let wordScore = 0;

descriptionWords.some((word) => {
if (word == searchWord) {
// breaks the loop if the word is an exact match, since no other word can have a higher score
wordScore = exactWordScore;
return true;

} else if (wordScore < partialWordScore) {
if (word.includes(searchWord)) {
wordScore = partialWordScore;

} else if (word.length > 3) {
const levenshteinDistance = levenshtein(searchWord, word);

// only the word with the lowest levenshtein distance will be considered
if ((levenshteinDistance <= levenshteinThreshold) && (levenshteinScore - levenshteinDistance > wordScore)) {
wordScore = levenshteinScore - levenshteinDistance;
}
}
}
});

descriptionScore += wordScore;
});

cardScore += descriptionScore;

if (cardScore > 0) {
card.style.display = "";
cardsScores.push([card, cardScore]);
} else {
card.style.display = "none";
}
}

const msgNotFound = document.querySelector("div.msg");

if (cardsScores.length > 0) {
msgNotFound.style.display = "none";
// sort the array of cards by score
cardsScores.sort((a, b) => b[1] - a[1]);
// remove the scores from the array
cardsScores = cardsScores.map((card) => card[0]);
sortCards(cardsScores);
} else {
card.style.display = "none";
msgNotFound.style.display = "";
}
}

const msgNotFound = document.querySelector("div.msg");
msgNotFound.style.display = cardsFiltered.length==0 ? "" : "none";

} else {
// display all cards if search input is empty
for (const card of listOfCardsFiltered) {
card.style.display = "";
cardsScores.push(card);
}

const msgNotFound = document.querySelector("div.msg");
msgNotFound.style.display = "none";
sortCards();
}
}

function insertCardsIntoHtml(data) {
let cards = `<div class="msg">
<div class=collumn-1>
<img src="assets/img/no-results-found.png" alt="Mulher olhando para site sem dados" />
<img src="assets/img/no-results-found.png" alt="Mulher olhando para site sem dados" />
<a href="https://storyset.com/data">Data illustrations by Storyset</a>
</div>
<div class=collumn-2>
Expand Down Expand Up @@ -220,12 +342,12 @@ function generateCardId(defaultCardId, title, description) {
* @returns {string} The hashed representation of the content.
*/
function generateContentId(title = '', description = '', hash = 5381) {
const data = (title + description).slice(0, 32).split(' ').join('')
const data = (title + description).slice(0, 32).split(' ').join('')

for (let i = 0; i < data.length; i++) {
hash = ((hash << 5) + hash) + data.charCodeAt(i);
}
for (let i = 0; i < data.length; i++) {
hash = ((hash << 5) + hash) + data.charCodeAt(i);
}

const hashString = Math.abs(hash).toString(36); // Convert to base-36 string
return hashString;
}
const hashString = Math.abs(hash).toString(36); // Convert to base-36 string
return hashString;
}

0 comments on commit e8f89d5

Please sign in to comment.