Style: Apply deno lint and deno fmt across codebase

This commit is contained in:
lifeadventurer
2024-10-31 19:56:47 +08:00
parent df772b0bde
commit 778cb316c0
20 changed files with 882 additions and 702 deletions

View File

@@ -5,65 +5,73 @@
### Fortune Events and Descriptions ### Fortune Events and Descriptions
1. Fortune Type: 1. Fortune Type:
- Good fortunes - Good fortunes
- These should be added under the `"goodFortunes"` section in the JSON file. - These should be added under the `"goodFortunes"` section in the JSON
- Represent positive or beneficial events. file.
- Bad fortunes - Represent positive or beneficial events.
- These should be added under the `"badFortunes"` section in the JSON file. - Bad fortunes
- Represent challenging or less favorable events. - These should be added under the `"badFortunes"` section in the JSON file.
- Represent challenging or less favorable events.
2. Unique Content: 2. Unique Content:
- Ensure your event and descriptions are original and not repeated in existing entries. - Ensure your event and descriptions are original and not repeated in
existing entries.
3. Event Structure - Each fortune event should be added as new JSON object with the following structure: 3. Event Structure - Each fortune event should be added as new JSON object with
```json the following structure:
{ ```json
"event": "Event Name", {
"description": [ "event": "Event Name",
"Description 1", "description": [
"Description 2", "Description 1",
"Description 3", "Description 2",
"Description 4" "Description 3",
] "Description 4"
} ]
``` }
```
2. Maintain a positive and encouraging tone. 4. Maintain a positive and encouraging tone.
### Special Events ### Special Events
Special events require a more detailed structure. Special events require a more detailed structure.
1. Structure: 1. Structure:
```json ```json
{ {
"event": "Event Name", "event": "Event Name",
"year": "Year", "year": "Year",
"month": "Month", "month": "Month",
"date": "Date", "date": "Date",
"status_index": "Status Index", "status_index": "Status Index",
"goodFortunes": { "goodFortunes": {
"l_1_event": "Good Fortune 1", "l_1_event": "Good Fortune 1",
"l_1_desc": "Description 1", "l_1_desc": "Description 1",
"l_2_event": "Good Fortune 2", "l_2_event": "Good Fortune 2",
"l_2_desc": "Description 2" "l_2_desc": "Description 2"
}, },
"badFortunes": { "badFortunes": {
"r_1_event": "Bad Fortune 1", "r_1_event": "Bad Fortune 1",
"r_1_desc": "Description 1", "r_1_desc": "Description 1",
"r_2_event": "Bad Fortune 2", "r_2_event": "Bad Fortune 2",
"r_2_desc": "Description 2" "r_2_desc": "Description 2"
} }
} }
``` ```
2. Empty Fields: If there are no fortunes to add, leave the corresponding fields as empty strings (`""`). 2. Empty Fields: If there are no fortunes to add, leave the corresponding fields
as empty strings (`""`).
## Quote Generator ## Quote Generator
### Quotes ### Quotes
- Exclude content that includes any unlawful, defamatory, abusive, threatening or obscene text. - Exclude content that includes any unlawful, defamatory, abusive, threatening
- Verify that your contribution meets JSON standards, specifically avoiding trailing comma at the end of a list. or obscene text.
- Verify that your contribution meets JSON standards, specifically avoiding
trailing comma at the end of a list.
- Ensure that the added quotes are not duplicates of any existing ones. - Ensure that the added quotes are not duplicates of any existing ones.
- Remember to name your pull request properly. For example, if you are adding new quotes, your pull request should be named `Impr(quotes): Add {count} new quotes`. - Remember to name your pull request properly. For example, if you are adding
new quotes, your pull request should be named
`Impr(quotes): Add {count} new quotes`.

View File

@@ -1,12 +1,15 @@
# List of Generators # List of Generators
### [Quote_Generator](https://lifeadventurer.github.io/generators/quote_generator) ### [Quote_Generator](https://lifeadventurer.github.io/generators/quote_generator)
- Generate your daily quote with a button.
- Generate your daily quote with a button.
- Background with matrix animation when generating. - Background with matrix animation when generating.
- If you want to contribute quotes, check the quote section in [CONTRIBUTING.md](./CONTRIBUTING.md#quote) - If you want to contribute quotes, check the quote section in
[CONTRIBUTING.md](./CONTRIBUTING.md#quote)
### [Daily_Fortune_Generator](https://lifeadventurer.github.io/generators/fortune_generator) ### [Daily_Fortune_Generator](https://lifeadventurer.github.io/generators/fortune_generator)
- Generate your daily fortune with a generate button. - Generate your daily fortune with a generate button.
- Background with matrix animation when generating. - Background with matrix animation when generating.
- Testing some features for an online judge. - Testing some features for an online judge.
- remind future special events - remind future special events

View File

@@ -2,16 +2,19 @@
## Generators Gallery ## Generators Gallery
Visit the [Generators Gallery](https://lifeadventurer.github.io/generators) to explore a collection of generators, each accompanied by a concise description, and with links to generators. Visit the [Generators Gallery](https://lifeadventurer.github.io/generators) to
explore a collection of generators, each accompanied by a concise description,
and with links to generators.
## List of Generators ## List of Generators
| Generators | Brief Description | | Generators | Brief Description |
|--------------------------------------------------|---------------------------------------------------------------| | ------------------------------------------------ | ------------------------------------------------------------- |
| **[Quote Generator][Quote Generator]** | Generate inspiring and thought-provoking quotes effortlessly. | | **[Quote Generator][Quote Generator]** | Generate inspiring and thought-provoking quotes effortlessly. |
| **[Daily Fortune Generator][Fortune Generator]** | Get your daily fortune with just a click. | | **[Daily Fortune Generator][Fortune Generator]** | Get your daily fortune with just a click. |
For more in-depth information about each generator, refer to [LIST_OF_GENERATORS.md](./LIST_OF_GENERATORS.md) For more in-depth information about each generator, refer to
[LIST_OF_GENERATORS.md](./LIST_OF_GENERATORS.md)
## Contribute ## Contribute
@@ -22,4 +25,5 @@ Please refer to [CONTRIBUTING.md](./CONTRIBUTING.md)
## License ## License
This project is licensed under the GNU General Public License v3.0 (GPL-3.0). See the [LICENSE](./LICENSE) file for more details. This project is licensed under the GNU General Public License v3.0 (GPL-3.0).
See the [LICENSE](./LICENSE) file for more details.

View File

@@ -1,165 +1,165 @@
const fs = require('fs') const fs = require("fs");
const goodFortunes = [ const goodFortunes = [
{ {
"event": "睡覺", "event": "睡覺",
"description": "品質良好,精神煥發" "description": "品質良好,精神煥發",
}, },
{ {
"event": "做家務", "event": "做家務",
"description": "整潔使人心情愉悅" "description": "整潔使人心情愉悅",
}, },
{ {
"event": "冥想", "event": "冥想",
"description": "平靜心靈,緩解焦慮" "description": "平靜心靈,緩解焦慮",
}, },
{ {
"event": "攝影", "event": "攝影",
"description": "捕捉到美好瞬間" "description": "捕捉到美好瞬間",
}, },
{ {
"event": "喝咖啡", "event": "喝咖啡",
"description": "精力充沛燃燒脂肪" "description": "精力充沛燃燒脂肪",
}, },
{ {
"event": "朋友聚會", "event": "朋友聚會",
"description": "充滿歡笑和美好回憶" "description": "充滿歡笑和美好回憶",
}, },
{ {
"event": "體育鍛鍊", "event": "體育鍛鍊",
"description": "能量滿滿,效果顯著" "description": "能量滿滿,效果顯著",
}, },
{ {
"event": "出遊" , "event": "出遊",
"description": "好天氣,好心情" "description": "好天氣,好心情",
}, },
{ {
"event": "吃大餐", "event": "吃大餐",
"description": "聯絡感情" "description": "聯絡感情",
}, },
{ {
"event": "逛書店", "event": "逛書店",
"description": "新書上架,打折推銷" "description": "新書上架,打折推銷",
}, },
{ {
"event": "學新技能", "event": "學新技能",
"description": "快速上手" "description": "快速上手",
}, },
{ {
"event": "唱歌", "event": "唱歌",
"description": "被星探發掘" "description": "被星探發掘",
}, },
{ {
"event": "上課", "event": "上課",
"description": "整天不累100% 消化" "description": "整天不累100% 消化",
}, },
{ {
"event": "洗澡", "event": "洗澡",
"description": "重獲能量" "description": "重獲能量",
}, },
{ {
"event": "請教問題", "event": "請教問題",
"description": "問題皆獲高人指點" "description": "問題皆獲高人指點",
}, },
{ {
"event": "網購", "event": "網購",
"description": "心儀商品皆促銷" "description": "心儀商品皆促銷",
}, },
{ {
"event": "放假", "event": "放假",
"description": "休息充電,明日再戰" "description": "休息充電,明日再戰",
}, },
{ {
"event": "早睡", "event": "早睡",
"description": "好夢連連" "description": "好夢連連",
}, },
{ {
"event": "早起", "event": "早起",
"description": "朝氣蓬勃,神采飛揚" "description": "朝氣蓬勃,神采飛揚",
}, },
{ {
"event": "發文章", "event": "發文章",
"description": "瀏覽數暴增" "description": "瀏覽數暴增",
}, },
{ {
"event": "點外賣", "event": "點外賣",
"description": "準時到達,新鮮好吃" "description": "準時到達,新鮮好吃",
}, },
{ {
"event": "做善事", "event": "做善事",
"description": "積善成福" "description": "積善成福",
}, },
{ {
"event": "散步", "event": "散步",
"description": "空氣良好,放鬆身心" "description": "空氣良好,放鬆身心",
} },
]; ];
const badFortunes = [ const badFortunes = [
{ {
"event": "體育鍛鍊", "event": "體育鍛鍊",
"description": "不慎受傷" "description": "不慎受傷",
}, },
{ {
"event": "攝影", "event": "攝影",
"description": "照片全消失" "description": "照片全消失",
}, },
{ {
"event": "出遊", "event": "出遊",
"description": "天氣不晴朗" "description": "天氣不晴朗",
}, },
{ {
"event": "吃大餐", "event": "吃大餐",
"description": "被要求請客" "description": "被要求請客",
}, },
{ {
"event": "學新技能", "event": "學新技能",
"description": "屢試不爽,始終不懂" "description": "屢試不爽,始終不懂",
}, },
{ {
"event": "唱歌", "event": "唱歌",
"description": "嗓子發炎" "description": "嗓子發炎",
}, },
{ {
"event": "洗澡", "event": "洗澡",
"description": "水溫不穩" "description": "水溫不穩",
}, },
{ {
"event": "請教問題", "event": "請教問題",
"description": "疑難雜症,均無解答" "description": "疑難雜症,均無解答",
}, },
{ {
"event": "網購", "event": "網購",
"description": "錯過促銷" "description": "錯過促銷",
}, },
{ {
"event": "放假", "event": "放假",
"description": "隔日工作量倍增" "description": "隔日工作量倍增",
}, },
{ {
"event": "晚睡", "event": "晚睡",
"description": "失眠,明日精神渙散" "description": "失眠,明日精神渙散",
}, },
{ {
"event": "晚起", "event": "晚起",
"description": "整天都不順" "description": "整天都不順",
}, },
{ {
"event": "發文章", "event": "發文章",
"description": "搜索枯腸,不知所云" "description": "搜索枯腸,不知所云",
}, },
{ {
"event": "點外賣", "event": "點外賣",
"description": "路況壅塞,餐點冷掉" "description": "路況壅塞,餐點冷掉",
}, },
{ {
"event": "喝咖啡", "event": "喝咖啡",
"description": "晚上失眠" "description": "晚上失眠",
}, },
{ {
"event": "散步", "event": "散步",
"description": "被害蟲咬傷" "description": "被害蟲咬傷",
} },
]; ];
const badLen = badFortunes.length; const badLen = badFortunes.length;
@@ -172,106 +172,118 @@ let day = 0;
let run_cnt = 0; let run_cnt = 0;
while (run_cnt != 2000) { while (run_cnt != 2000) {
let n1 = parseInt(Math.random() * 255 + 1); let n1 = parseInt(Math.random() * 255 + 1);
let n2 = parseInt(Math.random() * 255 + 1); let n2 = parseInt(Math.random() * 255 + 1);
let n3 = parseInt(Math.random() * 255 + 1); let n3 = parseInt(Math.random() * 255 + 1);
let n4 = parseInt(Math.random() * 255 + 1); let n4 = parseInt(Math.random() * 255 + 1);
if (!check_ip_valid(n1, n2, n3, n4)) continue; if (!check_ip_valid(n1, n2, n3, n4)) continue;
let index = `${n1}.${n2}.${n3}.${n4}`; let index = `${n1}.${n2}.${n3}.${n4}`;
buckets[index] = [0, 0, 0, 0]; buckets[index] = [0, 0, 0, 0];
for (let i = 1; i <= 12; i++) { for (let i = 1; i <= 12; i++) {
for (let j = 1; j <= dates[i - 1]; j++) { for (let j = 1; j <= dates[i - 1]; j++) {
day %= 7; day %= 7;
run(2023, i, j, day, [n1, n2, n3, n4]); run(2023, i, j, day, [n1, n2, n3, n4]);
day++; day++;
}
} }
}
run_cnt++; run_cnt++;
} }
fs.writeFile('./res.txt', JSON.stringify(buckets), err => { fs.writeFile("./res.txt", JSON.stringify(buckets), (err) => {
console.log(err); console.log(err);
}); });
function check_ip_valid(n1, n2, n3, n4) { function check_ip_valid(n1, n2, n3, n4) {
if (n1 > 255 || n2 > 255 || n3 > 255 || n4 > 255) return false; if (n1 > 255 || n2 > 255 || n3 > 255 || n4 > 255) return false;
// private network // private network
if (n1 === 10) return false; if (n1 === 10) return false;
// Carrier-grade NAT // Carrier-grade NAT
if (n1 == 100 && n2 == 64) return false; if (n1 == 100 && n2 == 64) return false;
// localhost // localhost
if (n1 === 127 && n2 === 0 && n3 === 0) return false; if (n1 === 127 && n2 === 0 && n3 === 0) return false;
// link-local address // link-local address
if (n1 == 169 && n2 == 254) return false; if (n1 == 169 && n2 == 254) return false;
// private network // private network
if (n1 === 172) if (n2 >= 16 && n2 <= 31) return false; if (n1 === 172) { if (n2 >= 16 && n2 <= 31) return false; }
if (n1 === 192) { if (n1 === 192) {
if (n2 === 168) return false; // private network if (n2 === 168) return false; // private network
if (n2 === 0 && n3 === 0) return false; // IANA RFC 5735 if (n2 === 0 && n3 === 0) return false; // IANA RFC 5735
if (n2 === 0 && n3 === 2) return false; // TEST-NET-1 RFC 5735 if (n2 === 0 && n3 === 2) return false; // TEST-NET-1 RFC 5735
if (n2 === 88 && n3 === 99) return false; // 6to4 if (n2 === 88 && n3 === 99) return false; // 6to4
} }
if (n1 == 198) { if (n1 == 198) {
if (n2 == 18) return false; // RFC 2544 if (n2 == 18) return false; // RFC 2544
if (n2 == 51 && n3 == 100) return false; // TEST-NET-2 RFC 5735 if (n2 == 51 && n3 == 100) return false; // TEST-NET-2 RFC 5735
} }
if (n1 == 203 && n3 == 113) return false; // TEST-NET-3 RFC 5735 if (n1 == 203 && n3 == 113) return false; // TEST-NET-3 RFC 5735
// class D network // class D network
if (n1 == 224) return false; if (n1 == 224) return false;
// class E network // class E network
if (n1 == 255) return false; if (n1 == 255) return false;
return true; return true;
} }
// calculate hash and write result // calculate hash and write result
function run(year, month, date, day, ip) { function run(year, month, date, day, ip) {
let num = ip; let num = ip;
let index = `${ip[0]}.${ip[1]}.${ip[2]}.${ip[3]}`; let index = `${ip[0]}.${ip[1]}.${ip[2]}.${ip[3]}`;
// original hash function // original hash function
let hashDate = Math.round(Math.log10(year * ((month << (Math.log10(num[3]) + day - 1)) * (date << Math.log10(num[2] << day))))); let hashDate = Math.round(
let seed1 = (num[0] >> hashDate) * (num[1] >> Math.min(hashDate, 2)) + (num[2] << 1) * (num[3] >> 3) + (date << 3) * (month << hashDate) + ((year * day) >> 2); Math.log10(
let seed2 = (num[0] << (hashDate + 2)) * (num[1] << hashDate) + (num[2] << 1) * (num[3] << 3) + (date << (hashDate - 1)) * (month << 4) + (year >> hashDate) + ((date * day) >> 1); year *
((month << (Math.log10(num[3]) + day - 1)) *
(date << Math.log10(num[2] << day))),
),
);
let seed1 = (num[0] >> hashDate) * (num[1] >> Math.min(hashDate, 2)) +
(num[2] << 1) * (num[3] >> 3) + (date << 3) * (month << hashDate) +
((year * day) >> 2);
let seed2 = (num[0] << (hashDate + 2)) * (num[1] << hashDate) +
(num[2] << 1) * (num[3] << 3) + (date << (hashDate - 1)) * (month << 4) +
(year >> hashDate) + ((date * day) >> 1);
// make sure the events won't collide // make sure the events won't collide
let set = new Set(); let set = new Set();
let l1 = (seed1 % goodLen + goodLen) % goodLen; let l1 = (seed1 % goodLen + goodLen) % goodLen;
let l2 = (((seed1 << 1) + date) % goodLen + goodLen) % goodLen; let l2 = (((seed1 << 1) + date) % goodLen + goodLen) % goodLen;
while (l1 == l2) { while (l1 == l2) {
l2 = (l2 + 1) % goodLen; l2 = (l2 + 1) % goodLen;
} }
set.add(goodFortunes[l1].event); set.add(goodFortunes[l1].event);
set.add(goodFortunes[l2].event); set.add(goodFortunes[l2].event);
let r1 = (((seed1 >> 1) + (month << 3)) % badLen + badLen) % badLen; let r1 = (((seed1 >> 1) + (month << 3)) % badLen + badLen) % badLen;
while (set.has(badFortunes[r1].event)) { while (set.has(badFortunes[r1].event)) {
r1 = (r1 + 2) % badLen; r1 = (r1 + 2) % badLen;
} }
set.add(badFortunes[r1].event); set.add(badFortunes[r1].event);
let r2 = ((((((seed1 << 3) + (year >> 5) * (date << 2)) % badLen) * seed2) >> 6) % badLen + badLen) % badLen; let r2 =
while (set.has(badFortunes[r2].event)) { ((((((seed1 << 3) + (year >> 5) * (date << 2)) % badLen) * seed2) >> 6) %
r2 = (r2 + 1) % badLen; badLen + badLen) % badLen;
} while (set.has(badFortunes[r2].event)) {
r2 = (r2 + 1) % badLen;
}
// write l1, l2, r1, r2 // write l1, l2, r1, r2
buckets[index][0] = l1; buckets[index][0] = l1;
buckets[index][1] = l2; buckets[index][1] = l2;
buckets[index][2] = r1; buckets[index][2] = r1;
buckets[index][3] = r2; buckets[index][3] = r2;
} }

View File

@@ -5,7 +5,7 @@
### 2000 IPs for 365 days, two groups in total ### 2000 IPs for 365 days, two groups in total
| Fortune Status | Percentage (1st time) | Percentage (2nd time) | | Fortune Status | Percentage (1st time) | Percentage (2nd time) |
|----------------|-----------------------|-----------------------| | -------------- | --------------------- | --------------------- |
| 大吉 | 20.33% | 20.30% | | 大吉 | 20.33% | 20.30% |
| 中吉 | 14.37% | 14.34% | | 中吉 | 14.37% | 14.34% |
| 小吉 | 10.57% | 10.59% | | 小吉 | 10.57% | 10.59% |
@@ -17,12 +17,13 @@
## Distribution statistics of daily fortune events ## Distribution statistics of daily fortune events
Statistical method: The sum of the number of fortune events that occurred for 2,000 random IPs on the same day. Statistical method: The sum of the number of fortune events that occurred for
2,000 random IPs on the same day.
The x-axis is the index value and the y-axis is the number of times. The x-axis is the index value and the y-axis is the number of times.
| 宜 (Good Fortune) | 忌 (Bad Fortune) | | 宜 (Good Fortune) | 忌 (Bad Fortune) |
|------------------------------------------------|----------------------------------------------| | ---------------------------------------------- | -------------------------------------------- |
| ![Good Fortune](./good_fortune_statistics.png) | ![Bad Fortune](./bad_fortune_statistics.png) | | ![Good Fortune](./good_fortune_statistics.png) | ![Bad Fortune](./bad_fortune_statistics.png) |
[Statistics code](../dev/main.js) [Statistics code](../dev/main.js)

View File

@@ -3,4 +3,4 @@
"fortune_generator", "fortune_generator",
"quote_generator" "quote_generator"
] ]
} }

View File

@@ -1,14 +1,14 @@
:root { :root {
--button-color: #73a3eb; --button-color: #73a3eb;
--button-hover-color: #459aef; --button-hover-color: #459aef;
--bg-color: #FFFFFF; --bg-color: #ffffff;
--good-fortune-color: #e74c3c; --good-fortune-color: #e74c3c;
--bad-fortune-color: #000000bf; --bad-fortune-color: #000000bf;
--middle-fortune-color: #5eb95e; --middle-fortune-color: #5eb95e;
--desc-color: #7f7f7f; --desc-color: #7f7f7f;
--date-color: #096e1bC9; --date-color: #096e1bc9;
--special-event-color: #3e4fbb; --special-event-color: #3e4fbb;
--title-color: #000000CC; --title-color: #000000cc;
} }
.dark-mode { .dark-mode {
@@ -25,7 +25,6 @@
--title-color: #cdcdcd; --title-color: #cdcdcd;
} }
* { * {
overflow: hidden; overflow: hidden;
text-align: center; text-align: center;
@@ -114,4 +113,4 @@ button:hover {
margin-top: 20px; margin-top: 20px;
font-size: 1.5rem; font-size: 1.5rem;
color: var(--dark-mode-icon-color); color: var(--dark-mode-icon-color);
} }

View File

@@ -1,113 +1,136 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Daily Fortune Generator</title> <title>Daily Fortune Generator</title>
<link rel="icon" href="../images/lifeadventurer_rounded_logo.png"> <link rel="icon" href="../images/lifeadventurer_rounded_logo.png" />
<link rel="manifest" href="./manifest.json"> <link rel="manifest" href="./manifest.json" />
<!-- bootstrap --> <!-- bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <link
<!-- box icons --> href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
<link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'> rel="stylesheet"
<!-- jquery --> integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> crossorigin="anonymous"
/>
<!-- box icons -->
<link
href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css"
rel="stylesheet"
/>
<!-- jquery -->
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"
></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet"> <link
<script src="https://cdnjs.cloudflare.com/ajax/libs/html-to-image/1.11.11/html-to-image.min.js" integrity="sha512-7tWCgq9tTYS/QkGVyKrtLpqAoMV9XIUxoou+sPUypsaZx56cYR/qio84fPK9EvJJtKvJEwt7vkn6je5UVzGevw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"
<link rel="stylesheet" href="./css/styles.css"> rel="stylesheet"
<script> />
if ('serviceWorker' in navigator) { <script
navigator.serviceWorker.register('./js/service-worker.js'); src="https://cdnjs.cloudflare.com/ajax/libs/html-to-image/1.11.11/html-to-image.min.js"
} integrity="sha512-7tWCgq9tTYS/QkGVyKrtLpqAoMV9XIUxoou+sPUypsaZx56cYR/qio84fPK9EvJJtKvJEwt7vkn6je5UVzGevw=="
</script> crossorigin="anonymous"
</head> referrerpolicy="no-referrer"
<body> ></script>
<div class="container"> <link rel="stylesheet" href="./css/styles.css" />
<div class="row"> <script>
<p id="title"></p> if ("serviceWorker" in navigator) {
</div> navigator.serviceWorker.register("./js/service-worker.js");
<!-- init page start --> }
<div id="init-page"> </script>
</head>
<body>
<div class="container">
<div class="row"> <div class="row">
<div class="col-3"> <p id="title"></p>
<p id="month"></p> </div>
<!-- init page start -->
<div id="init-page">
<div class="row">
<div class="col-3">
<p id="month"></p>
</div>
<div class="col-6">
<p id="date"></p>
</div>
<div class="col-3">
<p id="weekday"></p>
</div>
</div> </div>
<div class="col-6"> <div class="row">
<p id="date"></p> <div class="col">
<p id="special-day"></p>
</div>
</div> </div>
<div class="col-3"> <div class="row">
<p id="weekday"></p> <p id="upcoming-event-1"></p>
</div>
<div class="row">
<p id="upcoming-event-2"></p>
</div> </div>
</div> </div>
<div class="row"> <!-- init page end -->
<div class="col"> <!-- page after button clicked start -->
<p id="special-day"></p> <div id="result-page">
<div class="row">
<p id="ip-to-fortune"></p>
</div>
<div class="row">
<div class="col">
<div class="row">
<p id="l-1-event"></p>
</div>
<div class="row">
<p id="l-1-desc"></p>
</div>
</div>
<div class="col">
<div class="row">
<p id="r-1-event"></p>
</div>
<div class="row">
<p id="r-1-desc"></p>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="row">
<p id="l-2-event"></p>
</div>
<div class="row">
<p id="l-2-desc"></p>
</div>
</div>
<div class="col">
<div class="row">
<p id="r-2-event"></p>
</div>
<div class="row">
<p id="r-2-desc"></p>
</div>
</div>
</div> </div>
</div> </div>
<!-- page after button click end -->
<div class="row"> <div class="row">
<p id="upcoming-event-1"></p> <i class="col-2 bx bx-moon" id="dark-mode-icon"></i>
</div> <button class="col-4 offset-2 bi bi-files" id="btn" onclick="getLuck()">
<div class="row"> 點擊打卡
<p id="upcoming-event-2"></p> </button>
<i
class="col-2 offset-2 fas fa-clone d-none"
id="copy-result"
onclick="copyResultImageToClipboard()"
></i>
</div> </div>
</div> </div>
<!-- init page end -->
<!-- page after button clicked start -->
<div id="result-page">
<div class="row">
<p id="ip-to-fortune"></p>
</div>
<div class="row">
<div class="col">
<div class="row">
<p id="l-1-event"></p>
</div>
<div class="row">
<p id="l-1-desc"></p>
</div>
</div>
<div class="col">
<div class="row">
<p id="r-1-event"></p>
</div>
<div class="row">
<p id="r-1-desc"></p>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="row">
<p id="l-2-event"></p>
</div>
<div class="row">
<p id="l-2-desc"></p>
</div>
</div>
<div class="col">
<div class="row">
<p id="r-2-event"></p>
</div>
<div class="row">
<p id="r-2-desc"></p>
</div>
</div>
</div>
</div>
<!-- page after button click end -->
<div class="row"> <canvas id="Matrix"></canvas>
<i class="col-2 bx bx-moon" id="dark-mode-icon"></i> <script src="./js/scripts.js"></script>
<button class="col-4 offset-2 bi bi-files" id="btn" onclick="getLuck()">點擊打卡</button> <script src="./js/fortune.js"></script>
<i class="col-2 offset-2 fas fa-clone d-none" id="copy-result" onclick="copyResultImageToClipboard()"></i> <script src="./js/matrix.js"></script>
</div> </body>
</div>
<canvas id="Matrix"></canvas>
<script src="./js/scripts.js"></script>
<script src="./js/fortune.js"></script>
<script src="./js/matrix.js"></script>
</body>
</html> </html>

View File

@@ -1,20 +1,19 @@
let ip = null; let ip = null;
fetch("https://api.ipify.org?format=json").then(response => { fetch("https://api.ipify.org?format=json").then((response) => {
if (response.ok) { if (response.ok) {
return response.json(); return response.json();
} }
throw new Error("Network response was not ok."); throw new Error("Network response was not ok.");
}).then(res => { }).then((res) => {
ip = res.ip; ip = res.ip;
}).catch((_error) => {
}).catch(_error => { if ("caches" in window) {
if ('caches' in window) { caches.match("https://api.ipify.org?format=json").then((response) => {
caches.match('https://api.ipify.org?format=json').then(response => {
if (response) { if (response) {
return response.json(); return response.json();
} }
}).then(data => { }).then((data) => {
if (ip === null && data !== undefined) { if (ip === null && data !== undefined) {
ip = JSON.parse(data).ip; ip = JSON.parse(data).ip;
} }
@@ -22,7 +21,6 @@ fetch("https://api.ipify.org?format=json").then(response => {
} }
}); });
let goodFortunes = []; let goodFortunes = [];
let badFortunes = []; let badFortunes = [];
let special_events = []; let special_events = [];
@@ -31,27 +29,61 @@ let fortune_generated = false;
// using async and await to prevent fetching the data too late... // using async and await to prevent fetching the data too late...
async function fetch_data() { async function fetch_data() {
await fetch("./json/fortune.json") await fetch("./json/fortune.json")
.then(response => response.json()) .then((response) => response.json())
.then(data => { .then((data) => {
goodFortunes = data.goodFortunes; goodFortunes = data.goodFortunes;
badFortunes = data.badFortunes; badFortunes = data.badFortunes;
}) });
await fetch("./json/special.json") await fetch("./json/special.json")
.then(response => response.json()) .then((response) => response.json())
.then(data => { .then((data) => {
special_events = data.special_events; special_events = data.special_events;
}) });
} }
const textColorClass = ["good-fortune", "good-fortune", "good-fortune", "good-fortune", "good-fortune", "middle-fortune", "bad-fortune", "bad-fortune"]; const textColorClass = [
const fortuneStatus = ["大吉", "中吉", "小吉", "吉", "末吉", "中平", "凶", "大凶"]; "good-fortune",
const chineseMonth = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"]; "good-fortune",
const week = ['日', '一', '二', '三', '四', '五', '六']; "good-fortune",
"good-fortune",
"good-fortune",
"middle-fortune",
"bad-fortune",
"bad-fortune",
];
const fortuneStatus = [
"大吉",
"中吉",
"小吉",
"吉",
"末吉",
"中平",
"凶",
"大凶",
];
const chineseMonth = [
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九",
"十",
"十一",
"十二",
];
const week = ["日", "一", "二", "三", "四", "五", "六"];
const title = `<span class="title" style="font-size:8vmin;"><b>今日運勢</b></span>`; const title =
const allGood = `<span class="bad-fortune" style="font-size:6vmin;"><b>萬事皆宜</b></span>`; `<span class="title" style="font-size:8vmin;"><b>今日運勢</b></span>`;
const allBad = `<span class="good-fortune" style="font-size:6vmin;"><b>諸事不宜</b></span>`; const allGood =
`<span class="bad-fortune" style="font-size:6vmin;"><b>萬事皆宜</b></span>`;
const allBad =
`<span class="good-fortune" style="font-size:6vmin;"><b>諸事不宜</b></span>`;
// date // date
const d = new Date(); const d = new Date();
@@ -63,7 +95,11 @@ const year = d.getFullYear();
function daysDiff(eventIndex) { function daysDiff(eventIndex) {
// define the date right now and the special event date // define the date right now and the special event date
const startDate = new Date(year, month - 1, date); const startDate = new Date(year, month - 1, date);
const endDate = new Date(special_events[eventIndex].year, special_events[eventIndex].month - 1, special_events[eventIndex].date); const endDate = new Date(
special_events[eventIndex].year,
special_events[eventIndex].month - 1,
special_events[eventIndex].date,
);
// calculate the difference in milliseconds and convert it to days // calculate the difference in milliseconds and convert it to days
const timeDiff = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24)); const timeDiff = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24));
@@ -71,15 +107,15 @@ function daysDiff(eventIndex) {
} }
// pre-search jquery - save to a variable to improve performance // pre-search jquery - save to a variable to improve performance
const J_l_1_event = $('#l-1-event'); const J_l_1_event = $("#l-1-event");
const J_l_1_desc = $('#l-1-desc'); const J_l_1_desc = $("#l-1-desc");
const J_l_2_event= $('#l-2-event'); const J_l_2_event = $("#l-2-event");
const J_l_2_desc = $('#l-2-desc'); const J_l_2_desc = $("#l-2-desc");
const J_r_1_event = $('#r-1-event'); const J_r_1_event = $("#r-1-event");
const J_r_1_desc = $('#r-1-desc'); const J_r_1_desc = $("#r-1-desc");
const J_r_2_event= $('#r-2-event'); const J_r_2_event = $("#r-2-event");
const J_r_2_desc = $('#r-2-desc'); const J_r_2_desc = $("#r-2-desc");
const J_ip_to_fortune = $('#ip-to-fortune'); const J_ip_to_fortune = $("#ip-to-fortune");
let special = false; let special = false;
let special_events_index = 0; let special_events_index = 0;
@@ -90,23 +126,34 @@ async function init_page() {
await fetch_data(); await fetch_data();
// hide the elements of show fortune page // hide the elements of show fortune page
$('#result-page').hide(); $("#result-page").hide();
// show date before button pressed // show date before button pressed
const showMonth = `<span class="date-color" style="font-size:10vmin; -webkit-writing-mode:vertical-lr;"><b>${chineseMonth[month - 1] + "月"}</b></span>`; const showMonth =
const showDate = `<span class="date-color" style="font-size:25vmin;"><b>${("0" + date).slice(-2)}</b></span>`; `<span class="date-color" style="font-size:10vmin; -webkit-writing-mode:vertical-lr;"><b>${
const showDay = `<span class="date-color" style="font-size:10vmin; -webkit-writing-mode:vertical-lr; margin-right:10%;"><b>${"星期" + week[day]}</b></span>`; chineseMonth[month - 1] + "月"
}</b></span>`;
const showDate = `<span class="date-color" style="font-size:25vmin;"><b>${
("0" + date).slice(-2)
}</b></span>`;
const showDay =
`<span class="date-color" style="font-size:10vmin; -webkit-writing-mode:vertical-lr; margin-right:10%;"><b>${
"星期" + week[day]
}</b></span>`;
$("#month").html(showMonth);
$("#date").html(showDate);
$("#weekday").html(showDay);
$('#month').html(showMonth);
$('#date').html(showDate);
$('#weekday').html(showDay);
const showSpecialEventCount = 2; const showSpecialEventCount = 2;
let eventIndexPtr = 0, eventIndexList = Array(showSpecialEventCount).fill(-1); let eventIndexPtr = 0, eventIndexList = Array(showSpecialEventCount).fill(-1);
// check if there is special event today // check if there is special event today
for (let i = 0; i < special_events.length; i++) { for (let i = 0; i < special_events.length; i++) {
if (daysDiff(i) > 0) { if (daysDiff(i) > 0) {
if (eventIndexPtr < showSpecialEventCount && eventIndexList[eventIndexPtr] == -1) { if (
eventIndexPtr < showSpecialEventCount &&
eventIndexList[eventIndexPtr] == -1
) {
eventIndexList[eventIndexPtr] = i; eventIndexList[eventIndexPtr] = i;
eventIndexPtr++; eventIndexPtr++;
} }
@@ -119,23 +166,33 @@ async function init_page() {
for (let eventIndex = 0; eventIndex < showSpecialEventCount; eventIndex++) { for (let eventIndex = 0; eventIndex < showSpecialEventCount; eventIndex++) {
if (eventIndexList[eventIndex] != -1) { if (eventIndexList[eventIndex] != -1) {
const days = daysDiff(eventIndexList[eventIndex]); const days = daysDiff(eventIndexList[eventIndex]);
const upcoming_event = `<span class="desc" style="font-size:5vmin;">距離<b class="special-event">${special_events[eventIndexList[eventIndex]].event}</b>還剩<b class="special-event">${days}</b>天</span>`; const upcoming_event =
$(`#upcoming-event-${eventIndex + 1}`).html(upcoming_event) `<span class="desc" style="font-size:5vmin;">距離<b class="special-event">${
special_events[eventIndexList[eventIndex]].event
}</b>還剩<b class="special-event">${days}</b>天</span>`;
$(`#upcoming-event-${eventIndex + 1}`).html(upcoming_event);
} }
} }
// show special event if today is a special day // show special event if today is a special day
if (special) { if (special) {
const special_event_today = `<span class="desc" style="font-size:9vmin;">今日是<b class="good-fortune">${special_events[special_events_index].event}</b></span>`; const special_event_today =
$('#special-day').html(special_event_today); `<span class="desc" style="font-size:9vmin;">今日是<b class="good-fortune">${
special_events[special_events_index].event
}</b></span>`;
$("#special-day").html(special_event_today);
} }
const last_date_str = localStorage.getItem('last_date'); const last_date_str = localStorage.getItem("last_date");
if (last_date_str !== null && last_date_str !== undefined) { if (last_date_str !== null && last_date_str !== undefined) {
const now_date = new Date(); const now_date = new Date();
const last_date = new Date(last_date_str); const last_date = new Date(last_date_str);
if (now_date.getFullYear() === last_date.getFullYear() && now_date.getMonth() === last_date.getMonth() && now_date.getDate() === last_date.getDate()) { if (
now_date.getFullYear() === last_date.getFullYear() &&
now_date.getMonth() === last_date.getMonth() &&
now_date.getDate() === last_date.getDate()
) {
fortune_generated = true; fortune_generated = true;
Appear(); Appear();
} }
@@ -143,59 +200,78 @@ async function init_page() {
} }
// event bar // event bar
const good_span = event => `<span class="good-fortune" style="font-size:5.6vmin;"><b>宜: </b>${event}</span>`; const good_span = (event) =>
const bad_span = event => `<span class="bad-fortune" style="font-size:5.6vmin;"><b>: </b>${event}</span>`; `<span class="good-fortune" style="font-size:5.6vmin;"><b>: </b>${event}</span>`;
const desc_span = desc => `<span class="desc" style="font-size:3.5vmin;">${desc}</span>`; const bad_span = (event) =>
`<span class="bad-fortune" style="font-size:5.6vmin;"><b>忌: </b>${event}</span>`;
const desc_span = (desc) =>
`<span class="desc" style="font-size:3.5vmin;">${desc}</span>`;
function Appear() { function Appear() {
$('#title').html(title); $("#title").html(title);
$('#btn').html('打卡成功'); $("#btn").html("打卡成功");
// disable the btn // disable the btn
$('#btn').attr("disabled", "disabled"); $("#btn").attr("disabled", "disabled");
//change page //change page
$('#init-page').hide(); $("#init-page").hide();
$('#result-page').show(); $("#result-page").show();
// some lengths // some lengths
const goodLen = goodFortunes.length; const goodLen = goodFortunes.length;
const badLen = badFortunes.length; const badLen = badFortunes.length;
const statusLen = fortuneStatus.length; const statusLen = fortuneStatus.length;
let status_index = -1; let status_index = -1;
let seed1 = -1; let seed1 = -1;
let seed2 = -1; let seed2 = -1;
if (!fortune_generated) { if (!fortune_generated) {
// transform ip to four numbers // transform ip to four numbers
const num = ip.split(".").map(num => parseInt(num)); const num = ip.split(".").map((num) => parseInt(num));
// TODO: improve the hash process // TODO: improve the hash process
const hashDate = Math.round(Math.log10(year * ((month << (Math.log10(num[3]) + day - 1)) * (date << Math.log10(num[2] << day))))); const hashDate = Math.round(
seed1 = (num[0] >> hashDate) * (num[1] >> Math.min(hashDate, 2)) + (num[2] << 1) * (num[3] >> 3) + (date << 3) * (month << hashDate) + (year * day) >> 2; Math.log10(
seed2 = (num[0] << (hashDate + 2)) * (num[1] << hashDate) + (num[2] << 1) * (num[3] << 2) + (date << (hashDate - 1)) * (month << 4) + year >> hashDate + (date * day) >> 1; year *
((month << (Math.log10(num[3]) + day - 1)) *
(date << Math.log10(num[2] << day))),
),
);
seed1 = (num[0] >> hashDate) * (num[1] >> Math.min(hashDate, 2)) +
(num[2] << 1) * (num[3] >> 3) + (date << 3) * (month << hashDate) +
(year * day) >> 2;
seed2 = (num[0] << (hashDate + 2)) * (num[1] << hashDate) +
(num[2] << 1) * (num[3] << 2) +
(date << (hashDate - 1)) * (month << 4) + year >>
hashDate + (date * day) >> 1;
// decide the status // decide the status
status_index = ((seed1 + seed2) % statusLen + statusLen) % statusLen; status_index = ((seed1 + seed2) % statusLen + statusLen) % statusLen;
// update last record // update last record
localStorage.setItem('last_date', d.toISOString()); localStorage.setItem("last_date", d.toISOString());
localStorage.setItem('last_status_index', status_index.toString()); localStorage.setItem("last_status_index", status_index.toString());
localStorage.setItem('last_seed1', seed1.toString()); localStorage.setItem("last_seed1", seed1.toString());
localStorage.setItem('last_seed2', seed2.toString()); localStorage.setItem("last_seed2", seed2.toString());
} else { } else {
status_index = parseInt(localStorage.getItem('last_status_index')); status_index = parseInt(localStorage.getItem("last_status_index"));
seed1 = parseInt(localStorage.getItem('last_seed1')); seed1 = parseInt(localStorage.getItem("last_seed1"));
seed2 = parseInt(localStorage.getItem('last_seed2')); seed2 = parseInt(localStorage.getItem("last_seed2"));
} }
const status = `<span class=${textColorClass[status_index]} style="font-size:12vmin;"><b>§ ${fortuneStatus[status_index]} §</b></span>`; const status = `<span class=${
textColorClass[status_index]
} style="font-size:12vmin;"><b>§ ${fortuneStatus[status_index]} §</b></span>`;
if (special) { if (special) {
status_index = special_events[special_events_index].status_index; status_index = special_events[special_events_index].status_index;
const special_status = `<span class=${textColorClass[status_index]} style="font-size:12vmin;"><b>§ ${fortuneStatus[status_index]} §</b></span>`; const special_status = `<span class=${
textColorClass[status_index]
} style="font-size:12vmin;"><b>§ ${
fortuneStatus[status_index]
} §</b></span>`;
J_ip_to_fortune.html(special_status); J_ip_to_fortune.html(special_status);
} } else {
else {
J_ip_to_fortune.html(status); J_ip_to_fortune.html(status);
} }
@@ -206,31 +282,40 @@ function Appear() {
let l2 = (((seed1 << 1) + date) % goodLen + goodLen) % goodLen; let l2 = (((seed1 << 1) + date) % goodLen + goodLen) % goodLen;
while (set.has(goodFortunes[l2].event)) { while (set.has(goodFortunes[l2].event)) {
l2 = (l2 + 1) % goodLen; l2 = (l2 + 1) % goodLen;
} }
set.add(goodFortunes[l2].event); set.add(goodFortunes[l2].event);
let r1 = (((seed1 >> 1) + (d.getMonth() << 3)) % badLen + badLen) % badLen; let r1 = (((seed1 >> 1) + (d.getMonth() << 3)) % badLen + badLen) % badLen;
while (set.has(badFortunes[r1].event)) { while (set.has(badFortunes[r1].event)) {
r1 = (r1 + 2) % badLen; r1 = (r1 + 2) % badLen;
} }
set.add(badFortunes[r1].event); set.add(badFortunes[r1].event);
let r2 = ((((((seed1 << 3) + (d.getFullYear() >> 5) * (date << 2)) % badLen) * seed2) >> 6) % badLen + badLen) % badLen; let r2 = ((((((seed1 << 3) + (d.getFullYear() >> 5) * (date << 2)) % badLen) *
seed2) >> 6) % badLen + badLen) % badLen;
while (set.has(badFortunes[r2].event)) { while (set.has(badFortunes[r2].event)) {
r2 = (r2 + 1) % badLen; r2 = (r2 + 1) % badLen;
} }
// organize the stuffs below this line... // organize the stuffs below this line...
const l1_desc_list = goodFortunes[l1].description; const l1_desc_list = goodFortunes[l1].description;
const l2_desc_list = goodFortunes[l2].description; const l2_desc_list = goodFortunes[l2].description;
const r1_desc_list = badFortunes[r1].description; const r1_desc_list = badFortunes[r1].description;
const r2_desc_list = badFortunes[r2].description; const r2_desc_list = badFortunes[r2].description;
const l_1_event = good_span(goodFortunes[l1].event); const l_1_event = good_span(goodFortunes[l1].event);
const l_1_desc = desc_span(l1_desc_list[Math.abs(seed1) % l1_desc_list.length]); const l_1_desc = desc_span(
l1_desc_list[Math.abs(seed1) % l1_desc_list.length],
);
const l_2_event = good_span(goodFortunes[l2].event); const l_2_event = good_span(goodFortunes[l2].event);
const l_2_desc = desc_span(l2_desc_list[Math.abs(seed2) % l2_desc_list.length]); const l_2_desc = desc_span(
l2_desc_list[Math.abs(seed2) % l2_desc_list.length],
);
const r_1_event = bad_span(badFortunes[r1].event); const r_1_event = bad_span(badFortunes[r1].event);
const r_1_desc = desc_span(r1_desc_list[Math.abs(seed1) % r1_desc_list.length]); const r_1_desc = desc_span(
r1_desc_list[Math.abs(seed1) % r1_desc_list.length],
);
const r_2_event = bad_span(badFortunes[r2].event); const r_2_event = bad_span(badFortunes[r2].event);
const r_2_desc = desc_span(r2_desc_list[Math.abs(seed2) % r2_desc_list.length]); const r_2_desc = desc_span(
r2_desc_list[Math.abs(seed2) % r2_desc_list.length],
);
if (special) { if (special) {
// instead clear variable name, use short variable name for here... cuz it's too repetitive // instead clear variable name, use short variable name for here... cuz it's too repetitive
@@ -242,7 +327,7 @@ function Appear() {
J_r_1_desc.html(desc_span(Data.badFortunes.r_1_desc)); J_r_1_desc.html(desc_span(Data.badFortunes.r_1_desc));
J_r_2_event.html(bad_span(Data.badFortunes.r_2_event)); J_r_2_event.html(bad_span(Data.badFortunes.r_2_event));
J_r_2_desc.html(desc_span(Data.badFortunes.r_2_desc)); J_r_2_desc.html(desc_span(Data.badFortunes.r_2_desc));
if (Data.badFortunes.r_1_event.length == 0) { if (Data.badFortunes.r_1_event.length == 0) {
J_r_1_event.html(r_1_event); J_r_1_event.html(r_1_event);
J_r_1_desc.html(r_1_desc); J_r_1_desc.html(r_1_desc);
@@ -259,7 +344,7 @@ function Appear() {
J_l_1_desc.html(desc_span(Data.goodFortunes.l_1_desc)); J_l_1_desc.html(desc_span(Data.goodFortunes.l_1_desc));
J_l_2_event.html(good_span(Data.goodFortunes.l_2_event)); J_l_2_event.html(good_span(Data.goodFortunes.l_2_event));
J_l_2_desc.html(desc_span(Data.goodFortunes.l_2_desc)); J_l_2_desc.html(desc_span(Data.goodFortunes.l_2_desc));
if (Data.goodFortunes.l_1_event.length == 0) { if (Data.goodFortunes.l_1_event.length == 0) {
J_l_1_event.html(l_1_event); J_l_1_event.html(l_1_event);
J_l_1_desc.html(l_1_desc); J_l_1_desc.html(l_1_desc);
@@ -269,8 +354,7 @@ function Appear() {
J_l_2_desc.html(l_2_desc); J_l_2_desc.html(l_2_desc);
} }
} }
} } else {
else{
if (status_index == 0) { if (status_index == 0) {
J_r_1_event.html(allGood); J_r_1_event.html(allGood);
} else { } else {

View File

@@ -1,13 +1,14 @@
const canvas = document.getElementById("Matrix") const canvas = document.getElementById("Matrix");
const context = canvas.getContext("2d") const context = canvas.getContext("2d");
canvas.height = window.innerHeight + 100; canvas.height = globalThis.innerHeight + 100;
canvas.width = window.innerWidth + 5; canvas.width = globalThis.innerWidth + 5;
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./*-+#$%^@!~?><:;[]{}=_αβΓγΔδεζηΘθικΛλμΞξΠπρΣσςτυΦφχΨψΩω×≦≧≠∞≒≡∩∠∟⊿∫∮∵∴¥〒¢£℃€℉╩◢ⅨⅧⅦⅥⅣⅢⅡあいうえおがぎぐげござじずぜぞだぢつでづどにぬのばひぴぶへぺぼみゃょァゐゎè"; const chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./*-+#$%^@!~?><:;[]{}=_αβΓγΔδεζηΘθικΛλμΞξΠπρΣσςτυΦφχΨψΩω×≦≧≠∞≒≡∩∠∟⊿∫∮∵∴¥〒¢£℃€℉╩◢ⅨⅧⅦⅥⅣⅢⅡあいうえおがぎぐげござじずぜぞだぢつでづどにぬのばひぴぶへぺぼみゃょァゐゎè";
const fontSize = 16; const fontSize = 16;
const columns = canvas.width / fontSize; const columns = canvas.width / fontSize;
const charArr = []; const charArr = [];
for (let i = 0; i < columns; i++) { for (let i = 0; i < columns; i++) {
@@ -23,14 +24,14 @@ context.fillRect(0, 0, canvas.width, canvas.height);
function Update() { function Update() {
context.fillStyle = "rgba(0, 0, 0, 0.05)"; context.fillStyle = "rgba(0, 0, 0, 0.05)";
context.fillRect(0, 0, canvas.width, canvas.height); context.fillRect(0, 0, canvas.width, canvas.height);
if (frame == 0) { if (frame == 0) {
const a = parseInt(Math.random() * 255); const a = parseInt(Math.random() * 255);
str = `rgba(${a}, ${Math.abs(a - 127)}, ${Math.abs(a - 255)}, 0.9)`; str = `rgba(${a}, ${Math.abs(a - 127)}, ${Math.abs(a - 255)}, 0.9)`;
} }
context.fillStyle = str; context.fillStyle = str;
context.font = fontSize + "px monospace"; context.font = fontSize + "px monospace";
for (let i = 0; i < columns; i++) { for (let i = 0; i < columns; i++) {
const text = chars[Math.floor(Math.random() * chars.length)]; const text = chars[Math.floor(Math.random() * chars.length)];
context.fillText(text, i * fontSize, charArr[i] * fontSize); context.fillText(text, i * fontSize, charArr[i] * fontSize);
@@ -39,7 +40,7 @@ function Update() {
} }
charArr[i]++; charArr[i]++;
} }
frame++; frame++;
if (frame <= 40 * (Math.floor(Math.random() * 10) + 3)) { if (frame <= 40 * (Math.floor(Math.random() * 10) + 3)) {
requestAnimationFrame(Update); // 40 frames a cycle requestAnimationFrame(Update); // 40 frames a cycle

View File

@@ -1,49 +1,50 @@
let darkModeIcon = document.querySelector('#dark-mode-icon'); let darkModeIcon = document.querySelector("#dark-mode-icon");
darkModeIcon.onclick = () => { darkModeIcon.onclick = () => {
darkModeIcon.classList.toggle('bx-sun'); darkModeIcon.classList.toggle("bx-sun");
document.body.classList.toggle('dark-mode'); document.body.classList.toggle("dark-mode");
}; };
function copyResultImageToClipboard() { function copyResultImageToClipboard() {
try { try {
const $title = $('#title').clone().wrap('<div class="row"></div>'); const $title = $("#title").clone().wrap('<div class="row"></div>');
$('#result-page').prepend($title.parent()); $("#result-page").prepend($title.parent());
const backgroundColor = getComputedStyle($('.container')[0]).backgroundColor; const backgroundColor =
htmlToImage.toBlob($('#result-page')[0], { getComputedStyle($(".container")[0]).backgroundColor;
htmlToImage.toBlob($("#result-page")[0], {
skipFonts: true, skipFonts: true,
preferredFontFormat: 'woff2', preferredFontFormat: "woff2",
backgroundColor: backgroundColor, // Set background color dynamically backgroundColor: backgroundColor, // Set background color dynamically
}).then(blob => { }).then((blob) => {
navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]); navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]);
showCopiedNotice(); showCopiedNotice();
$title.parent().remove(); $title.parent().remove();
}).catch(error => { }).catch((error) => {
console.error('Error converting result page to image:', error); console.error("Error converting result page to image:", error);
$title.parent().remove(); $title.parent().remove();
}); });
} catch(error) { } catch (error) {
console.error('Error copying result image to clipboard:', error); console.error("Error copying result image to clipboard:", error);
} }
} }
function showCopiedNotice() { function showCopiedNotice() {
const notice = $('<div>', { const notice = $("<div>", {
text: 'Copied to clipboard!', text: "Copied to clipboard!",
css: { css: {
position: 'fixed', position: "fixed",
bottom: '20px', bottom: "20px",
right: '20px', right: "20px",
padding: '10px 20px', padding: "10px 20px",
backgroundColor: 'rgba(0, 0, 0, 0.7)', backgroundColor: "rgba(0, 0, 0, 0.7)",
color: '#fff', color: "#fff",
borderRadius: '5px', borderRadius: "5px",
zIndex: 1000, zIndex: 1000,
} },
}); });
$('body').append(notice); $("body").append(notice);
setTimeout(() => { setTimeout(() => {
notice.fadeOut(300, () => { notice.fadeOut(300, () => {

View File

@@ -1,35 +1,35 @@
const pre_cache_file_version = 'pre-v1.1.0'; const pre_cache_file_version = "pre-v1.1.0";
const auto_cache_file_version = 'auto-v1.1.0' const auto_cache_file_version = "auto-v1.1.0";
const ASSETS = [ const ASSETS = [
'/images/lifeadventurer-192x192.png', "/images/lifeadventurer-192x192.png",
'/images/lifeadventurer-512x512.png', "/images/lifeadventurer-512x512.png",
'/images/lifeadventurer-180x180.png', "/images/lifeadventurer-180x180.png",
'/images/lifeadventurer-270x270.png', "/images/lifeadventurer-270x270.png",
'/images/lifeadventurer.jpg', "/images/lifeadventurer.jpg",
'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css', "https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css",
'https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js' "https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js",
]; ];
const NEED_UPDATE = [ const NEED_UPDATE = [
'/fortune_generator/', "/fortune_generator/",
'/fortune_generator/index.html', "/fortune_generator/index.html",
'/fortune_generator/css/styles.css', "/fortune_generator/css/styles.css",
'/fortune_generator/js/fortune.js', "/fortune_generator/js/fortune.js",
'/fortune_generator/js/matrix.js', "/fortune_generator/js/matrix.js",
'/fortune_generator/json/special.json', "/fortune_generator/json/special.json",
'/fortune_generator/json/fortune.json', "/fortune_generator/json/fortune.json",
'/fortune_generator/json/manifest.json', "/fortune_generator/json/manifest.json",
'https://api.ipify.org/?format=json', "https://api.ipify.org/?format=json",
] ];
const limit_cache_size = (name, size) => { const limit_cache_size = (name, size) => {
caches.open(name).then(cache => { caches.open(name).then((cache) => {
cache.keys().then(keys => { cache.keys().then((keys) => {
if (keys.length > size) { if (keys.length > size) {
cache.delete(keys[0]).then(() => { cache.delete(keys[0]).then(() => {
limit_cache_size(name, size) limit_cache_size(name, size);
}); });
} }
}); });
@@ -37,8 +37,8 @@ const limit_cache_size = (name, size) => {
}; };
const is_in_array = (str, array) => { const is_in_array = (str, array) => {
let path = ''; let path = "";
// Check the request's domain is the same as the current domain. // Check the request's domain is the same as the current domain.
if (str.indexOf(self.origin) === 0) { if (str.indexOf(self.origin) === 0) {
path = str.substring(self.origin.length); // Remove https://lifeadventurer.github.io path = str.substring(self.origin.length); // Remove https://lifeadventurer.github.io
@@ -47,56 +47,58 @@ const is_in_array = (str, array) => {
} }
return array.indexOf(path) > -1; return array.indexOf(path) > -1;
} };
// install // install
self.addEventListener('install', event => { self.addEventListener("install", (event) => {
self.skipWaiting(); self.skipWaiting();
//pre-cache files //pre-cache files
event.waitUntil( event.waitUntil(
caches.open(pre_cache_file_version).then(cache => { caches.open(pre_cache_file_version).then((cache) => {
cache.addAll(ASSETS); cache.addAll(ASSETS);
}) }),
); );
}); });
// activate // activate
self.addEventListener('activate', event => { self.addEventListener("activate", (event) => {
event.waitUntil( event.waitUntil(
caches.keys().then(keys => { caches.keys().then((keys) => {
return Promise.all(keys.map(key => { return Promise.all(keys.map((key) => {
if (pre_cache_file_version.indexOf(key) === -1 && auto_cache_file_version.indexOf(key) === -1) { if (
pre_cache_file_version.indexOf(key) === -1 &&
auto_cache_file_version.indexOf(key) === -1
) {
return caches.delete(key); return caches.delete(key);
} }
})); }));
}) }),
) );
}); });
// fetch event // fetch event
self.addEventListener('fetch', event => { self.addEventListener("fetch", (event) => {
if (is_in_array(event.request.url, ASSETS)) { if (is_in_array(event.request.url, ASSETS)) {
// cache only strategy // cache only strategy
event.respondWith( event.respondWith(
caches.match(event.request.url) caches.match(event.request.url),
); );
} else if (is_in_array(event.request.url, NEED_UPDATE)) { } else if (is_in_array(event.request.url, NEED_UPDATE)) {
event.respondWith( event.respondWith(
fetch(event.request.url).then(async response => { fetch(event.request.url).then(async (response) => {
if (response.ok) { if (response.ok) {
const cache = await caches.open(auto_cache_file_version); const cache = await caches.open(auto_cache_file_version);
cache.put(event.request.url, response.clone()); cache.put(event.request.url, response.clone());
return response; return response;
} }
throw new Error("Network response was not ok."); throw new Error("Network response was not ok.");
}).catch(async (_error) => {
}).catch(async _error => {
const cache = await caches.open(auto_cache_file_version); const cache = await caches.open(auto_cache_file_version);
return cache.match(event.request.url); return cache.match(event.request.url);
}) }),
) );
} }
}); });

View File

@@ -1,66 +1,99 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Generators</title> <title>Generators</title>
<link rel="icon" href="./images/lifeadventurer_rounded_logo.png"> <link rel="icon" href="./images/lifeadventurer_rounded_logo.png" />
<!-- bootstrap 5.3.2 --> <!-- bootstrap 5.3.2 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <link
<!-- jquery 3.7.1 --> href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> rel="stylesheet"
<!-- box icons --> integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
<link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'> crossorigin="anonymous"
<link rel="stylesheet" href="./styles.css"> />
</head> <!-- jquery 3.7.1 -->
<body> <script
<header> src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"
<div class="row"> ></script>
<h1 class="col-md-4 col-sm-6 offset-md-4 offset-sm-3">Generators Gallery</h1> <!-- box icons -->
<div class="col-md-1 col-sm-1 offset-md-3 offset-sm-2 bx bx-moon" id="dark-mode-icon"></div> <link
</div> href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css"
</header> rel="stylesheet"
<section> />
<div class="container"> <link rel="stylesheet" href="./styles.css" />
</head>
<body>
<header>
<div class="row"> <div class="row">
<div class="col-md-6"> <h1 class="col-md-4 col-sm-6 offset-md-4 offset-sm-3">
<div class="card mb-3 border-0"> Generators Gallery
<img class="card-img-top" src="./images/fortune_generator_example.png" alt="fortune generator example"> </h1>
<div class="card-body"> <div
<h4 class="card-title">Fortune Generator</h4> class="col-md-1 col-sm-1 offset-md-3 offset-sm-2 bx bx-moon"
<p class="card-text">Get your daily fortune with just a click.</p> id="dark-mode-icon"
<a class="btn" href="./fortune_generator/">Check this out</a> >
</div> </div>
<div class="card-footer"> </div>
<div id="last-update-1"></div> </header>
<section>
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="card mb-3 border-0">
<img
class="card-img-top"
src="./images/fortune_generator_example.png"
alt="fortune generator example"
/>
<div class="card-body">
<h4 class="card-title">Fortune Generator</h4>
<p class="card-text">
Get your daily fortune with just a click.
</p>
<a class="btn" href="./fortune_generator/">Check this out</a>
</div>
<div class="card-footer">
<div id="last-update-1"></div>
</div>
</div> </div>
</div> </div>
</div> <div class="col-md-6">
<div class="col-md-6"> <div class="card mb-3 border-0">
<div class="card mb-3 border-0"> <img
<img class="card-img-top" src="./images/quote_generator_example_(2).png" alt="quote generator example"> class="card-img-top"
<div class="card-body"> src="./images/quote_generator_example_(2).png"
<h4 class="card-title">Quote Generator</h4> alt="quote generator example"
<p class="card-text">Generate inspiring and thought-provoking quotes effortlessly.</p> />
<a class="btn" href="./quote_generator/">Check this out</a> <div class="card-body">
</div> <h4 class="card-title">Quote Generator</h4>
<div class="card-footer"> <p class="card-text">
<div id="last-update-2"></div> Generate inspiring and thought-provoking quotes effortlessly.
</p>
<a class="btn" href="./quote_generator/">Check this out</a>
</div>
<div class="card-footer">
<div id="last-update-2"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </section>
</section> <footer>
<footer> <div class="row text-muted py-3 me-3 float-end" id="footer-author">
<div class="row text-muted py-3 me-3 float-end" id="footer-author"> <h5>
<h5> Copyright © 2023-2024 LifeAdventurer | All Rights Reserved. Copyright © 2023-2024 LifeAdventurer | All Rights Reserved.
<a href="https://github.com/LifeAdventurer"> <a href="https://github.com/LifeAdventurer">
<img id="footer-author-icon" src="./images/lifeadventurer_rounded_logo.png" alt="footer image"> <img
</a> id="footer-author-icon"
</h5> src="./images/lifeadventurer_rounded_logo.png"
</div> alt="footer image"
</footer> />
<script src="./scripts.js"></script> </a>
</body> </h5>
</html> </div>
</footer>
<script src="./scripts.js"></script>
</body>
</html>

View File

@@ -1,5 +1,5 @@
:root { :root {
--button-color: #9DC4FF; --button-color: #9dc4ff;
--button-hover-color: #5ca8f3; --button-hover-color: #5ca8f3;
--bg-color: #ffffffd7; --bg-color: #ffffffd7;
--text-color: #000000; --text-color: #000000;
@@ -18,7 +18,7 @@ html {
height: 100%; height: 100%;
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
font-family: Georgia, 'Times New Roman', Times, serif; font-family: Georgia, "Times New Roman", Times, serif;
font-size: 24px; font-size: 24px;
} }
@@ -66,7 +66,7 @@ button {
padding: 17px 20px; padding: 17px 20px;
border-radius: 30px; border-radius: 30px;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
} }
button:hover { button:hover {
@@ -79,4 +79,4 @@ button:hover {
color: var(--dark-mode-icon-color); color: var(--dark-mode-icon-color);
cursor: pointer; cursor: pointer;
opacity: 85%; opacity: 85%;
} }

View File

@@ -1,33 +1,41 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title> Quote Generator </title> <title>Quote Generator</title>
<link rel="icon" href="../images/lifeadventurer_rounded_logo.png"> <link rel="icon" href="../images/lifeadventurer_rounded_logo.png" />
<!-- bootstrap --> <!-- bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <link
<!-- box icons --> href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
<link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'> rel="stylesheet"
<link rel="stylesheet" href="./css/styles.css"> integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
</head> crossorigin="anonymous"
/>
<body> <!-- box icons -->
<div class="container" id="imageContainer"> <link
<h1>Today's quote</h1> href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css"
<div class="quote-container"> rel="stylesheet"
<p id="quote"></p> />
<p id="author"></p> <link rel="stylesheet" href="./css/styles.css" />
</div> </head>
<div class="row">
<button class="col-4 offset-4" onclick="getQuote()">Generate </button> <body>
<div class="col-2 offset-2 bx bx-moon" id="dark-mode-icon"></div> <div class="container" id="imageContainer">
</div> <h1>Today's quote</h1>
</div> <div class="quote-container">
<p id="quote"></p>
<canvas id="Matrix"></canvas> <p id="author"></p>
<script src="./js/scripts.js"></script> </div>
<script src="./js/matrix.js"></script> <div class="row">
<script src="./js/quote.js"></script> <button class="col-4 offset-4" onclick="getQuote()">Generate</button>
</body> <div class="col-2 offset-2 bx bx-moon" id="dark-mode-icon"></div>
</html> </div>
</div>
<canvas id="Matrix"></canvas>
<script src="./js/scripts.js"></script>
<script src="./js/matrix.js"></script>
<script src="./js/quote.js"></script>
</body>
</html>

View File

@@ -1,13 +1,14 @@
const canvas = document.getElementById("Matrix") const canvas = document.getElementById("Matrix");
const context = canvas.getContext("2d") const context = canvas.getContext("2d");
canvas.height = window.innerHeight + 100; canvas.height = globalThis.innerHeight + 100;
canvas.width = window.innerWidth + 5; canvas.width = globalThis.innerWidth + 5;
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./*-+#$%^@!~?><:;[]{}=_αβΓγΔδεζηΘθικΛλμΞξΠπρΣσςτυΦφχΨψΩω×≦≧≠∞≒≡∩∠∟⊿∫∮∵∴¥〒¢£℃€℉╩◢ⅨⅧⅦⅥⅣⅢⅡあいうえおがぎぐげござじずぜぞだぢつでづどにぬのばひぴぶへぺぼみゃょァゐゎè"; const chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./*-+#$%^@!~?><:;[]{}=_αβΓγΔδεζηΘθικΛλμΞξΠπρΣσςτυΦφχΨψΩω×≦≧≠∞≒≡∩∠∟⊿∫∮∵∴¥〒¢£℃€℉╩◢ⅨⅧⅦⅥⅣⅢⅡあいうえおがぎぐげござじずぜぞだぢつでづどにぬのばひぴぶへぺぼみゃょァゐゎè";
const fontSize = 16; const fontSize = 16;
const columns = canvas.width / fontSize; const columns = canvas.width / fontSize;
const charArr = []; const charArr = [];
for (let i = 0; i < columns; i++) { for (let i = 0; i < columns; i++) {
@@ -30,7 +31,7 @@ function Update() {
} }
context.fillStyle = str; context.fillStyle = str;
context.font = fontSize + "px monospace"; context.font = fontSize + "px monospace";
for (let i = 0; i < columns; i++) { for (let i = 0; i < columns; i++) {
const text = chars[Math.floor(Math.random() * chars.length)]; const text = chars[Math.floor(Math.random() * chars.length)];
context.fillText(text, i * fontSize, charArr[i] * fontSize); context.fillText(text, i * fontSize, charArr[i] * fontSize);

View File

@@ -5,11 +5,10 @@ const buttonElement = document.querySelector("button");
let quotes = []; let quotes = [];
fetch("./json/quotes.json") fetch("./json/quotes.json")
.then(response => response.json()) .then((response) => response.json())
.then(data => { .then((data) => {
quotes = data.quotes; quotes = data.quotes;
}); });
function Appear() { function Appear() {
const index = Math.floor(Math.random() * quotes.length); const index = Math.floor(Math.random() * quotes.length);
@@ -24,7 +23,6 @@ function Appear() {
const numDarkImages = 0; const numDarkImages = 0;
const numLightImages = 0; const numLightImages = 0;
if (numDarkImages && numLightImages) { if (numDarkImages && numLightImages) {
const isDark = Math.random() < 0.5; const isDark = Math.random() < 0.5;
let randomIndex, randomImage; let randomIndex, randomImage;
@@ -33,7 +31,7 @@ function Appear() {
if (isDark) { if (isDark) {
randomIndex = Math.floor(Math.random() * numDarkImages) + 1; randomIndex = Math.floor(Math.random() * numDarkImages) + 1;
randomImage = folderPath + "dark/" + randomIndex + ".jpg"; randomImage = folderPath + "dark/" + randomIndex + ".jpg";
darkModeIcon.onclick() darkModeIcon.onclick();
} else { } else {
randomIndex = Math.floor(Math.random() * numLightImages) + 1; randomIndex = Math.floor(Math.random() * numLightImages) + 1;
randomImage = folderPath + "light/" + randomIndex + ".jpg"; randomImage = folderPath + "light/" + randomIndex + ".jpg";

View File

@@ -1,7 +1,6 @@
const darkModeIcon = document.querySelector('#dark-mode-icon'); const darkModeIcon = document.querySelector("#dark-mode-icon");
darkModeIcon.onclick = () => { darkModeIcon.onclick = () => {
darkModeIcon.classList.toggle('bx-sun'); darkModeIcon.classList.toggle("bx-sun");
document.body.classList.toggle('dark-mode'); document.body.classList.toggle("dark-mode");
}; };

View File

@@ -1,33 +1,36 @@
// fetch all folder paths of the generators from `folders.json` // fetch all folder paths of the generators from `folders.json`
let folderPaths = [] let folderPaths = [];
async function fetch_folders() { async function fetch_folders() {
await fetch('./folders.json') await fetch("./folders.json")
.then(response => response.json()) .then((response) => response.json())
.then(data => { .then((data) => {
folderPaths = data.folder_paths; folderPaths = data.folder_paths;
}) });
} }
async function get_generator_card_footer() { async function get_generator_card_footer() {
await fetch_folders() await fetch_folders();
const repoOwner = 'LifeAdventurer'; const repoOwner = "LifeAdventurer";
const repoName = 'generators'; const repoName = "generators";
for (let folderIndex = 1; folderIndex <= folderPaths.length; folderIndex++) { for (let folderIndex = 1; folderIndex <= folderPaths.length; folderIndex++) {
const folderPath = folderPaths[folderIndex - 1]; const folderPath = folderPaths[folderIndex - 1];
const apiUrl = `https://api.github.com/repos/${repoOwner}/${repoName}/commits?path=${folderPath}`; const apiUrl =
`https://api.github.com/repos/${repoOwner}/${repoName}/commits?path=${folderPath}`;
fetch(apiUrl) fetch(apiUrl)
.then(response => response.json()) .then((response) => response.json())
.then(data => { .then((data) => {
// the latest commit will be at the top of the list // the latest commit will be at the top of the list
const lastCommit = data[0].commit.author.date; const lastCommit = data[0].commit.author.date;
const commitTimeStamp = new Date(lastCommit).getTime() / 1000; const commitTimeStamp = new Date(lastCommit).getTime() / 1000;
const currentTimeStamp = Math.floor(new Date().getTime() / 1000); const currentTimeStamp = Math.floor(new Date().getTime() / 1000);
const timeDifference = currentTimeStamp - commitTimeStamp; const timeDifference = currentTimeStamp - commitTimeStamp;
$(`#last-update-${folderIndex}`).html(`Last updated ${format_time_difference(timeDifference)} ago`) $(`#last-update-${folderIndex}`).html(
}) `Last updated ${format_time_difference(timeDifference)} ago`,
);
});
// .catch(error => console.error('Error fetching data:', error)); // .catch(error => console.error('Error fetching data:', error));
} }
} }
@@ -39,21 +42,21 @@ function format_time_difference(seconds) {
const days = Math.floor(hours / 24); const days = Math.floor(hours / 24);
if (days > 0) { if (days > 0) {
return `${days} day${days > 1 ? 's' : ''}`; return `${days} day${days > 1 ? "s" : ""}`;
} else if(hours > 0) { } else if (hours > 0) {
return `${hours} hour${hours > 1 ? 's' : ''}`; return `${hours} hour${hours > 1 ? "s" : ""}`;
} else if(minutes > 0) { } else if (minutes > 0) {
return `${minutes} minute${minutes > 1 ? 's' : ''}`; return `${minutes} minute${minutes > 1 ? "s" : ""}`;
} else { } else {
return `${seconds} second${seconds > 1 ? 's' : ''}`; return `${seconds} second${seconds > 1 ? "s" : ""}`;
} }
} }
get_generator_card_footer() get_generator_card_footer();
const darkModeIcon = document.querySelector('#dark-mode-icon'); const darkModeIcon = document.querySelector("#dark-mode-icon");
darkModeIcon.onclick = () => { darkModeIcon.onclick = () => {
darkModeIcon.classList.toggle('bx-sun'); darkModeIcon.classList.toggle("bx-sun");
document.body.classList.toggle('dark-mode'); document.body.classList.toggle("dark-mode");
}; };

View File

@@ -64,7 +64,7 @@ h5 {
.card-footer { .card-footer {
background-color: var(--card-footer-color); background-color: var(--card-footer-color);
color: var(--card-footer-text-color); color: var(--card-footer-text-color);
} }
#footer-author { #footer-author {
@@ -88,4 +88,4 @@ h5 {
color: var(--dark-mode-icon-color); color: var(--dark-mode-icon-color);
cursor: pointer; cursor: pointer;
opacity: 85%; opacity: 85%;
} }