running ok now
This commit is contained in:
parent
21f3b35db1
commit
8e4a4f5cba
18 changed files with 297 additions and 324 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -104,4 +104,5 @@ dist
|
|||
.tern-port
|
||||
|
||||
src/temp
|
||||
src/build
|
||||
src/build
|
||||
src/common/*.yaml
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
function loadCSS() {
|
||||
for (let c = 0; c < document.styleSheets.length; c++) {
|
||||
var declaration = document.styleSheets[c].cssRules[0];
|
||||
|
@ -14,4 +13,5 @@ function loadCSS() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
loadCSS();
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"greeting": {
|
||||
"morning": "Good morning!",
|
||||
"afternoon": "Good afternoon!",
|
||||
"evening": "Good evening!",
|
||||
"night": "Good night!"
|
||||
}
|
||||
}
|
5
src/languages/en.yaml
Normal file
5
src/languages/en.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
greeting:
|
||||
morning: Good morning!
|
||||
afternoon: Good afternoon!
|
||||
evening: Good evening!
|
||||
night: Good night!
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"greeting": {
|
||||
"morning": "Chào buổi sáng!",
|
||||
"afternoon": "Chiều làm việc hiệu quả!",
|
||||
"evening": "Chiều tối vui vẻ!",
|
||||
"night": "Chúc ngủ ngon!"
|
||||
}
|
||||
}
|
5
src/languages/vi.yaml
Normal file
5
src/languages/vi.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
greeting:
|
||||
morning: Chào buổi sáng!
|
||||
afternoon: Chiều làm việc hiệu quả!
|
||||
evening: Chiều tối vui vẻ!
|
||||
night: Chúc ngủ ngon!
|
61
src/main.go
61
src/main.go
|
@ -1,19 +1,33 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/help-14/magma/modules"
|
||||
)
|
||||
|
||||
var appConfig modules.Config
|
||||
var websiteData = struct {
|
||||
Config modules.WebsiteConfig
|
||||
Language modules.Language
|
||||
Contents []modules.GroupData
|
||||
}{}
|
||||
|
||||
func main() {
|
||||
prepareSampleFiles()
|
||||
appConfig = modules.LoadConfig()
|
||||
|
||||
websiteData.Config = appConfig.Website
|
||||
websiteData.Language = modules.LoadLanguage(appConfig.Website.Language)
|
||||
websiteData.Contents = modules.LoadContent().Data
|
||||
|
||||
commonfs := http.FileServer(http.Dir("./common"))
|
||||
http.Handle("/common/", http.StripPrefix("/common/", commonfs))
|
||||
|
||||
|
@ -24,6 +38,7 @@ func main() {
|
|||
themefs := http.FileServer(http.Dir("." + themePath))
|
||||
http.Handle("/theme/", http.StripPrefix("/theme/", themefs))
|
||||
|
||||
http.HandleFunc("/weather", serveWeather)
|
||||
http.HandleFunc("/", serveTemplate)
|
||||
|
||||
log.Println("Listening on http://localhost:7001 ...")
|
||||
|
@ -33,17 +48,45 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
var weatherTimeOut int64
|
||||
var weatherCache []byte
|
||||
|
||||
func serveWeather(w http.ResponseWriter, r *http.Request) {
|
||||
if time.Now().UnixMilli() >= weatherTimeOut {
|
||||
resp, err := http.Get("https://api.openweathermap.org/data/2.5/weather?lat=" + appConfig.OpenWeatherMap.Latitude + "&lon=" + appConfig.OpenWeatherMap.Longitude + "&limit=1&appid=" + appConfig.OpenWeatherMap.ApiKey)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
return
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
return
|
||||
}
|
||||
weatherCache = body
|
||||
weatherTimeOut = time.Now().UnixMilli() + 1800000
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(weatherCache)
|
||||
}
|
||||
|
||||
func serveTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
lp := filepath.Join("themes", appConfig.Website.Theme, "index.html")
|
||||
tmpl, _ := template.ParseFiles(lp)
|
||||
tmpl.Execute(w, struct {
|
||||
Config modules.WebsiteConfig
|
||||
}{appConfig.Website})
|
||||
tmpl.Execute(w, websiteData)
|
||||
}
|
||||
|
||||
// templ.Execute(file, struct {
|
||||
// Age int
|
||||
// Name string
|
||||
// }{42, "Dolphin"})
|
||||
|
||||
// {{.Age}}, {{.Name}}
|
||||
func prepareSampleFiles() {
|
||||
files, err := ioutil.ReadDir("./sample/")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
for _, file := range files {
|
||||
samplePath := filepath.Join("sample", file.Name())
|
||||
commonPath := filepath.Join("common", file.Name())
|
||||
if _, err := os.Stat(commonPath); errors.Is(err, os.ErrNotExist) {
|
||||
modules.CopyFile(samplePath, commonPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
47
src/modules/content.go
Normal file
47
src/modules/content.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type ContentData struct {
|
||||
Data []GroupData `yaml:"data"`
|
||||
}
|
||||
|
||||
type GroupData struct {
|
||||
Title string `yaml:"title"`
|
||||
Columns []ColumnData `yaml:"columns"`
|
||||
}
|
||||
|
||||
type ColumnData struct {
|
||||
Title string `yaml:"title"`
|
||||
Bookmarks []BookmarkData `yaml:"bookmarks"`
|
||||
}
|
||||
|
||||
type BookmarkData struct {
|
||||
Name string `yaml:"name"`
|
||||
Icon string `yaml:"icon"`
|
||||
Url string `yaml:"url"`
|
||||
}
|
||||
|
||||
func LoadContent() ContentData {
|
||||
emptyData := ContentData{}
|
||||
|
||||
yamlFile, err := ioutil.ReadFile(filepath.Join("common", "data.yaml"))
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading YAML file: %s\n", err)
|
||||
return emptyData
|
||||
}
|
||||
|
||||
var data ContentData
|
||||
err = yaml.Unmarshal(yamlFile, &data)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing YAML file: %s\n", err)
|
||||
return emptyData
|
||||
}
|
||||
return data
|
||||
}
|
27
src/modules/file.go
Normal file
27
src/modules/file.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func CopyFile(src string, dst string) {
|
||||
fin, err := os.Open(src)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer fin.Close()
|
||||
|
||||
fout, err := os.Create(dst)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer fout.Close()
|
||||
|
||||
_, err = io.Copy(fout, fin)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
38
src/modules/language.go
Normal file
38
src/modules/language.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type Language struct {
|
||||
Greeting LanguageGreeting `yaml:"greeting"`
|
||||
}
|
||||
|
||||
type LanguageGreeting struct {
|
||||
Morning string `yaml:"morning"`
|
||||
Afternoon string `yaml:"afternoon"`
|
||||
Evening string `yaml:"evening"`
|
||||
Night string `yaml:"night"`
|
||||
}
|
||||
|
||||
func LoadLanguage(language string) Language {
|
||||
yamlFile, err := ioutil.ReadFile(filepath.Join("languages", language+".yaml"))
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading YAML file: %s\n", err)
|
||||
return LoadLanguage("en")
|
||||
}
|
||||
|
||||
var data Language
|
||||
err = yaml.Unmarshal(yamlFile, &data)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing YAML file: %s\n", err)
|
||||
return LoadLanguage("en")
|
||||
}
|
||||
|
||||
fmt.Println("Loaded language: ", language)
|
||||
return data
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
export class Language {
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
import { opine, serveStatic } from "https://deno.land/x/opine/mod.ts";
|
||||
import { Language, minify } from "https://deno.land/x/minifier/mod.ts";
|
||||
import {
|
||||
ensureDirSync,
|
||||
ensureFileSync,
|
||||
existsSync,
|
||||
walkSync,
|
||||
} from "https://deno.land/std/fs/mod.ts";
|
||||
|
||||
const tempFolder = `${Deno.cwd()}/temp`;
|
||||
let weatherCache = "";
|
||||
let weatherTimeOut = new Date().getTime();
|
||||
|
||||
export async function startServer(): Promise<void> {
|
||||
// Create web server
|
||||
const app = opine();
|
||||
|
||||
// Add resource folder
|
||||
app.use(serveStatic(tempFolder));
|
||||
|
||||
// Add route for weather
|
||||
app.get("/weather", async (req, res) => {
|
||||
if (new Date().getTime() >= weatherTimeOut) {
|
||||
const lat = "21.0425886";
|
||||
const lon = "105.8129389";
|
||||
const apiKey = "7b093bee7461b669e34c363d887cfdec";
|
||||
const response = await fetch(
|
||||
`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&limit=1&appid=${apiKey}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
},
|
||||
},
|
||||
);
|
||||
weatherCache = await response.json();
|
||||
weatherTimeOut = new Date().getTime() + 1800000;
|
||||
}
|
||||
res.send(weatherCache);
|
||||
});
|
||||
|
||||
// Minify all files and copy to temp folder
|
||||
await Compile();
|
||||
|
||||
// Start web server
|
||||
app.listen(7001, () =>
|
||||
console.log(
|
||||
`Server has started on http://localhost:7001 🚀`,
|
||||
));
|
||||
}
|
||||
|
||||
export async function Compile(): Promise<void> {
|
||||
ensureDirSync(tempFolder);
|
||||
|
||||
[`private/themes/${window.config.website.theme}`, "public"].forEach(
|
||||
(folder) => {
|
||||
for (
|
||||
const entry of walkSync(`${Deno.cwd()}/${folder}/`, {
|
||||
includeDirs: false,
|
||||
})
|
||||
) {
|
||||
console.log("Preparing: " + entry.path);
|
||||
|
||||
let language = null;
|
||||
if (!entry.path.includes(".min.")) {
|
||||
if (entry.path.includes(".css")) {
|
||||
language = Language.CSS;
|
||||
} else if (entry.path.includes(".json")) {
|
||||
language = Language.JSON;
|
||||
}
|
||||
// minifier module make error when minify js and html file 🥲
|
||||
//else if (entry.path.includes(".js")) {
|
||||
// language = Language.JS;
|
||||
//}
|
||||
//else if (entry.path.includes(".htm")) {
|
||||
//language = Language.HTML;
|
||||
//}
|
||||
}
|
||||
|
||||
const moveToPath = convertOutputPath(entry.path, folder);
|
||||
ensureFileSync(moveToPath);
|
||||
|
||||
if (language) {
|
||||
let content = Deno.readTextFileSync(entry.path);
|
||||
content = minify(Language.HTML, content);
|
||||
Deno.writeTextFileSync(moveToPath, content);
|
||||
} else {
|
||||
Deno.copyFileSync(entry.path, moveToPath);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
// Copy language
|
||||
let languagePath =
|
||||
`${Deno.cwd()}/public/languages/${window.config.website.language}.json`;
|
||||
const languageOutput = convertOutputPath(languagePath, "public/languages");
|
||||
if (!existsSync(languagePath)) {
|
||||
languagePath =
|
||||
`${Deno.cwd()}/private/languages/${window.config.website.language}.json`;
|
||||
}
|
||||
Deno.copyFileSync(languagePath, languageOutput);
|
||||
}
|
||||
|
||||
function convertOutputPath(path: string, from: string) {
|
||||
return Deno.cwd() + path.replace(Deno.cwd(), "").replace(from, "temp");
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
website:
|
||||
theme: "flame"
|
||||
title: "Help-14 Dashboard"
|
||||
title: "Magma Dashboard"
|
||||
description: ""
|
||||
language: "vi"
|
||||
localization: "vi-vn"
|
||||
language: "en"
|
||||
localization: "en-US"
|
||||
useMetric: true
|
||||
|
||||
addons:
|
||||
openweathermap:
|
||||
apiKey:
|
||||
lon:
|
||||
lat:
|
||||
addons:
|
||||
|
|
|
@ -21,7 +21,7 @@ data:
|
|||
icon: fa-solid fa-server
|
||||
url: https://www.truenas.com
|
||||
- name: Kerberos
|
||||
icon: fa-solid fa-camera-web
|
||||
icon: fa-solid fa-video
|
||||
url: https://kerberos.io
|
||||
- name: jDownloader
|
||||
icon: fa-solid fa-cloud-arrow-down
|
||||
|
@ -61,10 +61,10 @@ data:
|
|||
icon: fa-solid fa-bag-shopping
|
||||
url: https://shopee.vn
|
||||
- name: Lazada
|
||||
icon: fa-solid fa-heart-half-stroke
|
||||
url: https://www.lazada.com
|
||||
icon: fa-brands fa-amazon
|
||||
url: https://www.amazon.com
|
||||
- title: Tools
|
||||
bookmarks:
|
||||
- name: Maps
|
||||
icon: fa-solid fa-map
|
||||
url: https://www.google.com/maps
|
||||
url: https://www.google.com/maps
|
||||
|
|
|
@ -68,20 +68,29 @@ body {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.group-items .icon {
|
||||
.group-items .icon-container {
|
||||
margin-top: 0px !important;
|
||||
margin-left: 0.5em !important;
|
||||
margin-right: 0.5em !important;
|
||||
text-align: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.group-items .icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.group-items a:hover {
|
||||
background-color: rgba(0, 0, 0, 0.3) !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@supports (-webkit-backdrop-filter: none) or (backdrop-filter: none) {
|
||||
.group-items a:hover {
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,22 +41,108 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div id="content" class="column twelve"></div>
|
||||
<div id="content" class="column twelve">
|
||||
{{range .Contents}}
|
||||
<div class="row group-title"><h4 class="strong">{{.Title}}</h4></div>
|
||||
<div class="row">
|
||||
{{range .Columns}}
|
||||
<div class="three columns group-items">
|
||||
<h6 class="accent">{{.Title}}</h6>
|
||||
{{range .Bookmarks}}
|
||||
<a href="{{.Url}}">
|
||||
<div class="icon-container">
|
||||
<i class="{{.Icon}} fa-xl icon"></i>
|
||||
</div>
|
||||
<h6>{{.Name}}</h6>
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer" class="row"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.config = {
|
||||
localization: {{ .Config.Localization }},
|
||||
language: {{ .Config.Language }},
|
||||
useMetric: {{ .Config.UseMetric }}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script src="theme/js/skycons.min.js"></script>
|
||||
<script src="common/js/core.js"></script>
|
||||
<script src="theme/js/magma.js"></script>
|
||||
<script>
|
||||
window.config = {
|
||||
localization: {{.Config.Localization}},
|
||||
language: {{.Config.Language}},
|
||||
useMetric: {{.Config.UseMetric}}
|
||||
};
|
||||
|
||||
(function setTimer() {
|
||||
const clock = document.querySelector("#clock");
|
||||
const clockOptions = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' };
|
||||
(function clockTick() {
|
||||
clock.innerText = new Date().toLocaleTimeString(window.config.localization, clockOptions);
|
||||
setTimeout(clockTick, 2000);
|
||||
})();
|
||||
//Set greeting
|
||||
const greeting = document.querySelector("#greeting");
|
||||
const hour = new Date().getHours();
|
||||
if (hour >= 5 && hour < 12) {
|
||||
greeting.innerText = {{.Language.Greeting.Morning}};
|
||||
}
|
||||
else if (hour >= 12 && hour < 17) {
|
||||
greeting.innerText = {{.Language.Greeting.Afternoon}};
|
||||
}
|
||||
else if (hour >= 17 && hour < 20) {
|
||||
greeting.innerText = {{.Language.Greeting.Evening}};
|
||||
}
|
||||
else {
|
||||
greeting.innerText = {{.Language.Greeting.Night}};
|
||||
}
|
||||
})();
|
||||
|
||||
(async function loadWeather() {
|
||||
// Get info from api
|
||||
const weather = await (await fetch("./weather")).json();
|
||||
// Parse weather id
|
||||
let icon = null;
|
||||
let isDay = Date.now().hour >= 6 && Date.now().hour < 18;
|
||||
const weatherCode = weather.weather[0].id;
|
||||
if ([200, 201, 202, 210, 211, 212, 221, 230, 231, 232].includes(weatherCode)) {
|
||||
icon = Skycons.RAIN; //Thunderstorm
|
||||
} else if ([300, 301, 302, 310, 311, 312, 313, 314, 321].includes(weatherCode)) {
|
||||
icon = Skycons.RAIN; //Drizzle
|
||||
} else if ([500, 501, 502, 503, 504, 511, 520, 521, 522, 531].includes(weatherCode)) {
|
||||
icon = Skycons.RAIN;
|
||||
} else if ([600, 601, 602, 611, 612, 613, 615, 616, 620, 621, 622].includes(weatherCode)) {
|
||||
icon = Skycons.SNOW;
|
||||
} else if (weatherCode === 800) {
|
||||
icon = isDay ? Skycons.CLEAR_DAY : Skycons.CLEAR_NIGHT;
|
||||
} else if ([801, 802, 803, 804].includes(weatherCode)) {
|
||||
if (weatherCode >= 803) {
|
||||
icon = Skycons.CLOUDY;
|
||||
} else {
|
||||
icon = isDay ? Skycons.PARTLY_CLOUDY_DAY : Skycons.PARTLY_CLOUDY_NIGHT;
|
||||
}
|
||||
} else if ([762, 761, 751, 731, 721].includes(weatherCode)) {
|
||||
icon = Skycons.SLEET;
|
||||
} else if ([771, 781].includes(weatherCode)) {
|
||||
icon = Skycons.WIND;
|
||||
} else if ([701, 711, 741].includes(weatherCode)) {
|
||||
icon = Skycons.FOG;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
// Set weather icon to canvas
|
||||
var skycons = new Skycons({ "color": window.cssRoot["--accentColor"] });
|
||||
skycons.add("weather-icon", icon);
|
||||
// Set weather info
|
||||
if (window.config.useMetric) {
|
||||
document.querySelector("#temp").innerText = Math.floor(weather.main.temp - 273.15) + "°C";
|
||||
} else {
|
||||
document.querySelector("#temp").innerText = Math.floor((weather.main.temp - 32) * 5 / 9) + "°F";
|
||||
}
|
||||
document.querySelector("#humidity").innerText = Math.floor(weather.main.humidity) + "%";
|
||||
document.querySelector("#weather-info").style.visibility = "visible";
|
||||
})();
|
||||
</script>
|
||||
<script src="common/js/custom.js"></script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
// async function loadConfig() {
|
||||
// window.config = await (await fetch("./common/config.json")).json();
|
||||
// // Set website language
|
||||
// document.documentElement.setAttribute("lang", window.config.website.language);
|
||||
// // Set website title
|
||||
// document.title = window.config.website.title;
|
||||
// // Set website description
|
||||
// document.querySelector('meta[name="description"]').setAttribute("content", window.config.website.description);
|
||||
// }
|
||||
|
||||
async function loadLanguage() {
|
||||
try {
|
||||
window.language = await (await fetch(`./languages/${window.config.language}.json`)).json();
|
||||
} catch {
|
||||
console.error("Language file not found");
|
||||
window.language = await (await fetch(`./languages/en.json`)).json();
|
||||
}
|
||||
}
|
||||
|
||||
async function loadWeather() {
|
||||
return;
|
||||
// Get info from api
|
||||
const weather = await (await fetch("./weather")).json();
|
||||
// Parse weather id
|
||||
let icon = null;
|
||||
let isDay = Date.now().hour >= 6 && Date.now().hour < 18;
|
||||
const weatherCode = weather.weather[0].id;
|
||||
if ([200, 201, 202, 210, 211, 212, 221, 230, 231, 232].includes(weatherCode)) {
|
||||
icon = Skycons.RAIN; //Thunderstorm
|
||||
} else if ([300, 301, 302, 310, 311, 312, 313, 314, 321].includes(weatherCode)) {
|
||||
icon = Skycons.RAIN; //Drizzle
|
||||
} else if ([500, 501, 502, 503, 504, 511, 520, 521, 522, 531].includes(weatherCode)) {
|
||||
icon = Skycons.RAIN;
|
||||
} else if ([600, 601, 602, 611, 612, 613, 615, 616, 620, 621, 622].includes(weatherCode)) {
|
||||
icon = Skycons.SNOW;
|
||||
} else if (weatherCode === 800) {
|
||||
icon = isDay ? Skycons.CLEAR_DAY : Skycons.CLEAR_NIGHT;
|
||||
} else if ([801, 802, 803, 804].includes(weatherCode)) {
|
||||
if (weatherCode >= 803) {
|
||||
icon = Skycons.CLOUDY;
|
||||
} else {
|
||||
icon = isDay ? Skycons.PARTLY_CLOUDY_DAY : Skycons.PARTLY_CLOUDY_NIGHT;
|
||||
}
|
||||
} else if ([762, 761, 751, 731, 721].includes(weatherCode)) {
|
||||
icon = Skycons.SLEET;
|
||||
} else if ([771, 781].includes(weatherCode)) {
|
||||
icon = Skycons.WIND;
|
||||
} else if ([701, 711, 741].includes(weatherCode)) {
|
||||
icon = Skycons.FOG;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
// Set weather icon to canvas
|
||||
var skycons = new Skycons({ "color": window.cssRoot["--accentColor"] });
|
||||
skycons.add("weather-icon", icon);
|
||||
// Set weather info
|
||||
if (window.config.useMetric) {
|
||||
document.querySelector("#temp").innerText = Math.floor(weather.main.temp - 273.15) + "°C";
|
||||
} else {
|
||||
document.querySelector("#temp").innerText = Math.floor((weather.main.temp - 32) * 5 / 9) + "°F";
|
||||
}
|
||||
document.querySelector("#humidity").innerText = Math.floor(weather.main.humidity) + "%";
|
||||
document.querySelector("#weather-info").style.visibility = "visible";
|
||||
}
|
||||
|
||||
async function loadBookmarks() {
|
||||
const data = await (await fetch("./common/data.json")).json();
|
||||
let contentHtml = "";
|
||||
|
||||
function splitToChunks(arr) {
|
||||
var chunks = [[], [], [], []];
|
||||
var i = 0;
|
||||
for (let j = 0; j < arr.length; j++) {
|
||||
chunks[i].push(arr[j]);
|
||||
i++;
|
||||
if (i === 4) i = 0;
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
function splitToEqualChunks(arr) {
|
||||
var chunks = [];
|
||||
var i = 0;
|
||||
while (i < arr.length) {
|
||||
chunks.push(arr.slice(i, Math.min(i + 4, arr.length)));
|
||||
i += 4;
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
data.forEach(section => {
|
||||
contentHtml += `<div class="row group-title"><h4 class="strong">${section.title}</h4></div>`
|
||||
if (section.columns) {
|
||||
const chunks = splitToEqualChunks(section.columns)
|
||||
chunks.forEach(chunk => {
|
||||
contentHtml += '<div class="row">';
|
||||
chunk.forEach(column => {
|
||||
contentHtml += `
|
||||
<div class="three columns group-items">
|
||||
<h6 class="accent">${column.title}</h6>`;
|
||||
column.bookmarks.forEach(bookmark => {
|
||||
contentHtml += `
|
||||
<a href="${bookmark.url}">
|
||||
<i class="${bookmark.icon} fa-xl icon"></i>
|
||||
<h6>${bookmark.title}</h6>
|
||||
</a>`;
|
||||
});
|
||||
contentHtml += "</div>";
|
||||
});
|
||||
contentHtml += "</div>";
|
||||
});
|
||||
|
||||
} else if (section.bookmarks) {
|
||||
contentHtml += '<div class="row">';
|
||||
const chunks = splitToChunks(section.bookmarks)
|
||||
chunks.forEach(chunk => {
|
||||
contentHtml += '<div class="three columns group-items">';
|
||||
chunk.forEach(bookmark => {
|
||||
contentHtml += `
|
||||
<a href="${bookmark.url}">
|
||||
<i class="${bookmark.icon} fa-xl icon"></i>
|
||||
<h6>${bookmark.title}</h6>
|
||||
</a>`;
|
||||
});
|
||||
contentHtml += "</div>";
|
||||
});
|
||||
contentHtml += "</div>";
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelector("#content").innerHTML = contentHtml;
|
||||
}
|
||||
|
||||
function setClock() {
|
||||
//Set clock
|
||||
const clock = document.querySelector("#clock");
|
||||
const clockOptions = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' };
|
||||
(function clockTick() {
|
||||
clock.innerText = new Date().toLocaleTimeString(window.config.localization, clockOptions);
|
||||
setTimeout(clockTick, 2000);
|
||||
})();
|
||||
//Set greeting
|
||||
const greeting = document.querySelector("#greeting");
|
||||
const hour = new Date().getHours();
|
||||
if (hour >= 5 && hour < 12) {
|
||||
greeting.innerText = window.language.greeting.morning;
|
||||
}
|
||||
else if (hour >= 12 && hour < 17) {
|
||||
greeting.innerText = window.language.greeting.afternoon;
|
||||
}
|
||||
else if (hour >= 17 && hour < 20) {
|
||||
greeting.innerText = window.language.greeting.evening;
|
||||
}
|
||||
else {
|
||||
greeting.innerText = window.language.greeting.night;
|
||||
}
|
||||
}
|
||||
|
||||
async function startWebsite() {
|
||||
loadBookmarks();
|
||||
await loadLanguage();
|
||||
setClock();
|
||||
loadCSS();
|
||||
loadWeather();
|
||||
}
|
||||
startWebsite();
|
Loading…
Add table
Reference in a new issue