Skip to content

Commit 7c2a76a

Browse files
authored
feat(sorting): add more sorting kinds and fix loading slowness
* feat(sorting): add clone functionality * feat(sorting): add github functionality * feat(sorting): allow github api to make calls without token * feat(sorting): add gitlab api * feat(sorting): add codeberg api * feat(themes): add repository field over link because of the theme ficeFox * fix(themes): remove deleted theme * feat(sorting): fix cloning to allow any source * themes.json: add new info for sorting * themes.json: update info for freeplay/firefox-onebar * feat(sorting): update, if necessary, instead of force-adding fields and values * fix(pug): replace fontawesome * feat(sorting): add update (pushed_at) and stars sorting kinds * build(site): add sorting features * docs(scripts): add small guide for contribution for theme info * docs(contribution): add repository field in guide to add theme * docs(issues): add repository field for issue template when adding theme * fix(tests): allow theme to have more fields and accept repository field * fix(tests): remove img-switch.sh, it's not used anymore * feat(sorting): replace trigger with menu * fix(disclaimer): do not show theme filter buttons * build(site): add menu for sorting and fix disclaimer page * feat(front): slowly render cards to improve performance
1 parent fa18e8c commit 7c2a76a

File tree

15 files changed

+3349
-626
lines changed

15 files changed

+3349
-626
lines changed
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
2-
name: "❤ Send Your Theme"
2+
name: " Send Your Theme"
33
about: An easy way to submit your theme if you don't know how to do it via pull request.
44
title: "[NEWTHEME] Name of your theme"
55
labels: new theme
6-
assignees: Neikon
6+
assignees: Neikon, BeyondMagic
77

88
---
99

@@ -12,10 +12,11 @@ Replace the .......... with the corresponding information. Example:
1212
```
1313
{
1414
"title": "the best dark theme",
15-
"link": "https://github.com/myTheme",
15+
"link": "https://github.com/myuser/myTheme",
1616
"description": "a dark theme",
17-
"image": "https://raw.githubusercontent.com/previewthemepicture.png"
18-
"tags": [ "John", "dark", "minimal","oneline", "............." ]
17+
"image": "https://raw.githubusercontent.com/previewthemepicture.png",
18+
"tags": [ "John", "dark", "minimal","oneline", "............." ],
19+
"repository": "https://github.com/myuser/myTheme"
1920
}
2021
```
2122
################# DELETE UNTIL HERE #################
@@ -25,7 +26,8 @@ Replace the .......... with the corresponding information. Example:
2526
"title": "..........",
2627
"link": "..........",
2728
"description": "..........",
28-
"image": ".........."
29-
"tags": [ "your username/name", "theme type: dark", "theme type: light", "............." ]
29+
"image": "..........",
30+
"tags": [ "your username/name", "theme type: dark", "theme type: light", "............." ],
31+
"repository": ".........."
3032
}
3133
```

README.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@ A collection site of Firefox userchrome themes, mostly from FirefoxCSS Reddit.<b
3636

3737
---
3838

39-
## Add your theme <3
39+
## Contribution
40+
41+
### Add your theme <3
4042

4143
+ If you have a Github account:
4244
1. Fork this repository
4345
2. Look for a file called `themes.json`, open and edit it
4446
3. Below the last `}` add `,` right after a copy the [code below](#code) and paste it in the file
45-
4. Add the properties of your theme: **title**, **link**, **description**, **image** and **tag** (Cannot be left empty)
47+
4. Add the properties of your theme: **title**, **link**, **description**, **image**, **tag** (cannot be left empty), and **repository**.
4648
5. **Avoid the use of escaped characters, and the order matters**
4749
6. Please, do not use a very big image, preferably (650x500)
4850
7. Image property:
@@ -54,20 +56,42 @@ A collection site of Firefox userchrome themes, mostly from FirefoxCSS Reddit.<b
5456
1. When creating an issue, you will find a template for submitting a theme. Use that one. It's easy.
5557

5658
+ If you have a Twitter account:
57-
1. Send **at least** the following properties: **tags**, **title**, **link**, **description**, and **picture** to [@Neikon66](https://twitter.com/Neikon66).
59+
1. Send **at least** the following properties: **title**, **link**, **description**, **image**, **tags**, and **repository** to [@Neikon66](https://twitter.com/Neikon66).
5860

5961
```
6062
{
6163
"title": "..........",
6264
"link": "..........",
6365
"description": "..........",
6466
"image": "..........",
65-
"tags": [ "your username/name", "theme type: dark", "theme type: light", "............." ]
67+
"tags": [ "your username/name", "theme type: dark", "theme type: light", "............." ],
68+
"repository": ".........."
6669
}
6770
```
6871

6972
---
7073

74+
### Contribution: themes information
75+
76+
1. Install [nushell](https://www.nushell.sh/) in your machine.
77+
2. Generate a [Github token API](https://github.com/settings/tokens) for your account and save it;
78+
2. Clone the repository;
79+
3. In your terminal, change directory into the `/scripts/` folder.
80+
4. Run `nu`.
81+
5. Run `use sort_themes.nu`;
82+
6. Run `sort_themes --help` and read and understand the flags;
83+
7. Run `sort_themes --github YOUR_GITHUB_TOKEN`;
84+
8. Check if everything ran fine, if yes, replace the new generated `themes.json` file.
85+
9. Commit your changes.
86+
10. Open a pull request and send your contribution for us to review.
87+
11. Thank you :)
88+
89+
**Why generate a token API for only Github?**
90+
91+
Most themes' repositories are in Gitub, so it's pretty easy to hit the anonymous rate limit for API calls. With a token, that limit is higher, making it easier to contribute.
92+
93+
---
94+
7195
<h1 align="center">What do you think =?</h1>
7296

7397
<p align="center">Feel free to send me any feedback via issue or my twitter <a href="https://twitter.com/Neikon66">@Neikon66</a>.</p>

dev/js/main.js

Lines changed: 115 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -81,109 +81,134 @@ function createLightbox (id) {
8181
* ======================
8282
*/
8383

84-
document.getElementById('searchInput').addEventListener('keydown', e => {
84+
const search = /** @type {HTMLInputElement} */ (document.getElementById('searchInput'))
8585

86-
if (e.key === "Enter") toggleSortType(false)
86+
search.addEventListener('keydown', e => {
87+
88+
if (e.key === "Enter")
89+
sort(localStorage.sort, search.value)
8790

8891
})
8992

90-
document.getElementById('searchButton').addEventListener('click', () => toggleSortType(false))
93+
const search_button = /** @type {HTMLInputElement} */ (document.getElementById('searchButton'))
94+
search_button.addEventListener('click', () => sort(localStorage.sort, search.value))
9195

9296
/* Load Content
9397
* ============
9498
*/
9599

96-
// add our sorting button
97-
const sortTrigger = document.getElementById('js-sortSwitcher')
98-
sortTrigger.addEventListener('click', () => toggleSortType(true))
99-
100-
// When localstorage is not set, use "latest" order type
101-
if (!localStorage['sort']) localStorage['sort'] = 'latest'
102-
103-
function repeatToggle (nextType) {
104-
105-
localStorage['sort'] = nextType
106-
return toggleSortType(false)
107-
108-
}
109-
110-
function toggleSortType (change) {
111-
112-
if (document.querySelectorAll('.card'))
113-
document.querySelectorAll('.card').forEach(e => e.remove());
114-
115-
fetch('themes.json')
116-
.then(data => data.json())
117-
.then(parsedData => {
118-
119-
const search = document.getElementById('searchInput').value
120-
121-
if (search) {
122-
123-
function matches (text, partial) { return text.toLowerCase().indexOf(partial.toLowerCase()) > -1 }
124-
125-
const parsedAsArray = Object.entries(parsedData)
126-
let searchResults = parsedAsArray.filter(element => matches(`${element[1].title}, ${element[1].tags}`, search))
127-
128-
searchResults.forEach(result => {
129-
130-
const card = new Card(result[1], +result[0])
131-
card.render(outputContainer)
132-
133-
})
134-
135-
sortTrigger.title = `"${search}"`
136-
137-
return
138-
139-
}
140-
141-
switch (localStorage['sort']) {
142-
143-
// sort from the oldest theme added
144-
case 'latest':
145-
if (change) return repeatToggle('random')
146-
parsedData.reverse()
147-
break;
148-
149-
// sort randomly
150-
case 'random':
151-
if (change) return repeatToggle('oldest')
152-
for (let i = parsedData.length - 1; i > 0; i--) {
153-
154-
const j = Math.floor(Math.random() * (i + 1));
155-
[parsedData[i], parsedData[j]] = [parsedData[j], parsedData[i]]
156-
157-
}
158-
break;
159-
160-
// sort from the most recent theme added
161-
default:
162-
if (change) return repeatToggle('latest');
163-
164-
}
165-
166-
// TODO: make a better way to preview the current sorting
167-
sortTrigger.title = localStorage['sort']
168-
169-
parsedData.forEach((entry, index) => {
170-
171-
const card = new Card (entry, index)
172-
card.render(outputContainer)
100+
/*
101+
* If sorting is not set yet in `localStorage`,
102+
* then use as default `latest` kind.
103+
*/
104+
if (!localStorage.sort)
105+
localStorage.sort = 'latest'
106+
107+
/*
108+
* Add event to sort when an option is chosen..
109+
*/
110+
const sort_menu = /** @type {HTMLSelectElement} */ (document.getElementById('js-sort-menu'))
111+
sort_menu.addEventListener('change', () => {
112+
const name = /** @type {string} */ (sort_menu.selectedOptions[0].getAttribute('name'))
113+
sort(name)
114+
})
115+
116+
sort(localStorage.sort)
117+
const current_option = sort_menu.options.namedItem(localStorage.sort)
118+
if (current_option)
119+
current_option.selected = true
120+
121+
/**
122+
* Toggle the sorting type of the themes.
123+
*
124+
* @param {string} kind How to sort the themes.
125+
* @param {string=} filter Term to filter the themes.
126+
**/
127+
function sort (kind, filter) {
128+
129+
localStorage.sort = kind
130+
131+
// Remove all themes cards from the page.
132+
const cards_container = document.getElementById('themes_container')
133+
if (cards_container)
134+
cards_container.innerHTML = ''
135+
136+
fetch('themes.json')
137+
.then(data => data.json())
138+
.then(async data => {
139+
140+
data = Object.entries(data)
141+
142+
if (filter) {
143+
144+
/**
145+
* Match any substring (partial) from a string (text).
146+
* @param {string} text
147+
* @param {string} partial
148+
*/
149+
function matches (text, partial) {
150+
return text.toLowerCase().indexOf(partial.toLowerCase()) > -1
151+
}
152+
153+
data = data.filter(element => matches(`${element[1].title}, ${element[1].tags}`, search.value))
154+
155+
}
156+
157+
switch (localStorage.sort) {
158+
159+
/*
160+
* Sort from the most recent theme added.
161+
*/
162+
case 'latest':
163+
data.reverse()
164+
break
165+
166+
/*
167+
* Ascending sorting of stars from repositories.
168+
*/
169+
case 'updated':
170+
// item1.attr.localeCompare(item2.attr);
171+
data.sort((a, b) => b[1].pushed_at.localeCompare(a[1].pushed_at))
172+
break
173+
174+
/*
175+
* Ascending sorting of stars from repositories.
176+
*/
177+
case 'stars':
178+
data.sort((a, b) => b[1].stargazers_count - a[1].stargazers_count)
179+
break
180+
181+
/*
182+
* Randomly sorting of themes.
183+
*/
184+
case 'random':
185+
for (let i = data.length - 1; i > 0; i--) {
186+
const j = Math.floor(Math.random() * (i + 1));
187+
[data[i], data[j]] = [data[j], data[i]]
188+
}
189+
break
190+
191+
/*
192+
* Sort from the least recent theme added (oldest).
193+
* Since it's sorted like this by default from the file, do nothing.
194+
*/
195+
default:
196+
197+
}
198+
199+
for (const [index, entry] of data)
200+
{
201+
const card = new Card(entry, index)
202+
card.render(outputContainer)
203+
await new Promise(r => setTimeout(r, 666));
204+
}
205+
206+
})
207+
}
173208

174-
})
175-
176-
})
177-
}
178-
179209
// add themes
180210
const outputContainer = document.getElementById('themes_container')
181211

182-
if (outputContainer) toggleSortType(false);
183-
184-
185-
186-
187212
/* Theme Handling
188213
* ==============
189214
*/

dev/pug/disclaimer.pug

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
extends layout/default
22

3+
block header
4+
header#main_header
5+
h3.header-branding FirefoxCSS Store
6+
7+
nav#main_nav
8+
a(href='index.html') Theme List
9+
a#js-themeSwitcher(href='#')
10+
i.fas.fa-moon
311

412
block content
513

dev/pug/includes/header.pug

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ header#main_header
55
a(href='index.html') Theme List
66
a#js-themeSwitcher(href='#')
77
i.fas.fa-moon
8-
a#js-sortSwitcher(href='#')
9-
i.fas.fa-sort
8+
select#js-sort-menu
9+
option(name='updated') Updated
10+
option(name='stars') Stars
11+
option(name='latest') Latest
12+
option(name='oldest') Oldest
13+
option(name='random') Random
1014
div.searchform(method='get')
1115
.inputgroup
1216
input.searchinput#searchInput(type='text', placeholder='Search')

dev/scss/base/_typography.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ body {
1313
}
1414

1515

16-
1716
a {
1817

1918
text-decoration: none;
@@ -25,6 +24,7 @@ a {
2524
&:hover { color: var(--linkc-hover) }
2625
&:focus { outline: var(--focus-thickness) solid var(--focus-colour); }
2726

27+
2828
}
2929

3030

0 commit comments

Comments
 (0)