Add backend

This commit is contained in:
2023-09-23 18:23:46 +02:00
parent a894717e52
commit 95dbb74b47
45 changed files with 6831 additions and 28 deletions

687
frontend/Cargo.lock generated Normal file
View File

@ -0,0 +1,687 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
dependencies = [
"memchr",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bumpalo"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "bytes"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "css_typegen"
version = "0.2.0"
source = "git+https://github.com/hulthe/css_typegen.git?branch=master#ed1c4b1b7c8bf19e1ce045cafa12f3886041134c"
dependencies = [
"proc-macro2",
"quote",
"regex",
"syn 1.0.109",
]
[[package]]
name = "csv"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
dependencies = [
"memchr",
]
[[package]]
name = "enclose"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1056f553da426e9c025a662efa48b52e62e0a3a7648aa2d15aeaaf7f0d329357"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "futures"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]]
name = "futures-executor"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
[[package]]
name = "futures-macro"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "futures-sink"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
[[package]]
name = "futures-task"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
[[package]]
name = "futures-util"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "getrandom"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "gloo-console"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261"
dependencies = [
"gloo-utils 0.2.0",
"js-sys",
"serde",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "gloo-events"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc"
dependencies = [
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "gloo-file"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7"
dependencies = [
"futures-channel",
"gloo-events",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "gloo-net"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ac9e8288ae2c632fa9f8657ac70bfe38a1530f345282d7ba66a1f70b72b7dc4"
dependencies = [
"futures-channel",
"futures-core",
"futures-sink",
"gloo-utils 0.2.0",
"http",
"js-sys",
"pin-project",
"serde",
"serde_json",
"thiserror",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "gloo-timers"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
dependencies = [
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "gloo-utils"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e"
dependencies = [
"js-sys",
"serde",
"serde_json",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "gloo-utils"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
dependencies = [
"js-sys",
"serde",
"serde_json",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "http"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "js-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "pin-project"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "pin-project-lite"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "seed"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c0e296ea0569d20467e9a1df3cb6ed66ce3b791a7eaf1e1110ae231f75e2b46"
dependencies = [
"enclose",
"futures",
"getrandom",
"gloo-file",
"gloo-timers",
"gloo-utils 0.1.7",
"indexmap",
"js-sys",
"rand",
"uuid",
"version_check",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "serde"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "serde_json"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "singit2"
version = "0.2.2"
dependencies = [
"css_typegen",
"csv",
"gloo-console",
"gloo-net",
"rand",
"seed",
"serde",
"serde_json",
"thiserror",
"wasm-bindgen",
]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "uuid"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
dependencies = [
"getrandom",
]
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.37",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
]

20
frontend/Cargo.toml Normal file
View File

@ -0,0 +1,20 @@
[package]
name = "singit_web"
version = "0.2.2"
authors = ["Joakim Hulthe <joakim@hulthe.net"]
edition = "2021"
[dependencies]
seed = "0.10.0"
serde = { version = "1.0.0", features = ['derive'] }
serde_json = "1.0.0"
rand = "0.8.5"
gloo-console = "0.3.0"
gloo-net = "0.4.0"
csv = "1.2.2"
thiserror = "1.0.48"
wasm-bindgen = "0.2.87"
[dependencies.css_typegen]
git = "https://github.com/hulthe/css_typegen.git"
branch = "master"

37
frontend/index.html Executable file
View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Karaokelåtar på IT">
<!-- stylesheets -->
<link data-trunk data-inline rel="scss" href="/static/styles/common.scss">
<link data-trunk data-inline rel="scss" href="/static/styles/penguin.scss">
<link data-trunk rel="scss" href="/static/styles/marquee.scss">
<!-- fonts -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu|Ubuntu+Mono&display=swap">
<!-- pwa manifest -->
<link data-trunk rel="copy-file" href="/static/manifest.json">
<link rel="manifest" href="/static/manifest.json">
<!-- copy image directory -->
<link data-trunk rel="copy-dir" href="/static/images">
<!-- image preloading -->
<link rel="preload" href="/images/penguin1.svg" as="image">
<link rel="preload" href="/images/penguin2.svg" as="image">
<link rel="preload" href="/images/penguin3.svg" as="image">
<!-- icon -->
<link rel="icon" type="image/png" href="/images/icon.png">
<title>SingIT</title>
</head>
<body>
<div id="app", style="width: 100%;"></div>
</body>
</html>

383
frontend/src/app.rs Normal file
View File

@ -0,0 +1,383 @@
use crate::css::C;
use crate::custom_list::{fetch_custom_song_list, fetch_custom_song_list_index, CustomLists};
use crate::fetch::fetch_list_of;
use crate::fuzzy::FuzzyScore;
use crate::query::ParsedQuery;
use crate::song::Song;
use gloo_console::error;
use rand::seq::SliceRandom;
use rand::thread_rng;
use seed::app::cmds::timeout;
use seed::browser::util::document;
use seed::prelude::*;
use seed::{attrs, button, div, empty, img, input, p, span, C, IF};
use std::cmp::Reverse;
use std::collections::HashSet;
use web_sys::Element;
pub struct Model {
songs: Vec<(Reverse<FuzzyScore>, Song)>,
/// Custom song lists, lazily loaded.
custom_lists: CustomLists,
/// The search string.
query: String,
/// The number of songs currently in the dom. Goes up when the user scrolls down.
shown_songs: usize,
/// The number of songs that didn't match the search critera.
hidden_songs: usize,
/// Whether we're filtering by video.
filter_video: bool,
/// Whether we're filtering by duets.
filter_duets: bool,
query_placeholder: String,
query_placeholder_len: usize,
autotyper: Option<CmdHandle>,
}
#[derive(Default)]
pub enum Loading<T> {
/// The resource has not started loading.
#[default]
NotLoaded,
/// The resource is currently loading.
InProgress,
/// The resource has loaded.
Loaded(T),
}
const SCROLL_THRESHOLD: usize = 50;
const INITIAL_ELEM_COUNT: usize = 100;
pub enum Msg {
/// Loaded songs.
Songs(Vec<Song>),
/// Loaded custom song index.
CustomSongLists(Vec<String>),
/// Loaded custom song list.
CustomSongList {
list: String,
song_hashes: HashSet<String>,
},
/// The user entered something into the search field
Search(String),
/// The user pressed the Toggle Video button
ToggleVideo,
/// The user pressed the Toggle Duets button
ToggleDuets,
/// The user pressed the Shuffle button
Shuffle,
/// The user scrolled the song list
Scroll,
/// Type stuff in the search input placeholder
Autotyper,
}
pub fn init(_url: Url, orders: &mut impl Orders<Msg>) -> Model {
orders.perform_cmd(fetch_songs());
orders.perform_cmd(fetch_custom_song_list_index());
Model {
songs: vec![],
custom_lists: Default::default(),
query: String::new(),
hidden_songs: 0,
shown_songs: INITIAL_ELEM_COUNT,
filter_video: false,
filter_duets: false,
query_placeholder: String::from("Sök"),
query_placeholder_len: 0,
autotyper: Some(orders.perform_cmd_with_handle(timeout(500, || Msg::Autotyper))),
}
}
fn update_song_list(model: &mut Model, orders: &mut impl Orders<Msg>) {
model.hidden_songs = 0;
model.shown_songs = INITIAL_ELEM_COUNT;
scroll_to_top();
if model.query.is_empty() {
model.filter_duets = false;
model.filter_video = false;
update(Msg::Shuffle, model, orders);
} else {
let query = ParsedQuery::parse(&model.query);
model.filter_duets = query.duet == Some(true);
model.filter_video = query.video == Some(true);
if let Some(name) = query.list {
if let Some(l @ Loading::NotLoaded) = model.custom_lists.get_mut(name) {
orders.perform_cmd(fetch_custom_song_list(name.to_string()));
*l = Loading::InProgress;
}
}
// calculate search scores & sort list
for (score, song) in model.songs.iter_mut() {
let new_score = song.fuzzy_compare(&query, &model.custom_lists);
if new_score < Default::default() {
model.hidden_songs += 1;
}
*score = Reverse(new_score);
}
model.songs.sort_unstable();
}
}
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg {
Msg::Songs(songs) => {
model.songs = songs
.into_iter()
.map(|song| (Default::default(), song))
.collect();
}
Msg::CustomSongLists(lists) => {
model.custom_lists = lists
.into_iter()
.map(|list| (list, Loading::NotLoaded))
.collect();
}
Msg::CustomSongList { list, song_hashes } => {
let query = ParsedQuery::parse(&model.query);
let update_list = query.list == Some(&list);
*model.custom_lists.entry(list).or_default() = Loading::Loaded(song_hashes);
if update_list {
update_song_list(model, orders);
}
}
Msg::Search(query) => {
model.query = query;
update_song_list(model, orders);
}
Msg::ToggleVideo => {
let mut query = ParsedQuery::parse(&model.query);
query.video = match query.video {
Some(true) => None,
None | Some(false) => Some(true),
};
update(Msg::Search(query.to_string()), model, orders);
}
Msg::ToggleDuets => {
let mut query = ParsedQuery::parse(&model.query);
query.duet = match query.duet {
Some(true) => None,
None | Some(false) => Some(true),
};
update(Msg::Search(query.to_string()), model, orders);
}
Msg::Shuffle => {
model.hidden_songs = 0;
model.shown_songs = INITIAL_ELEM_COUNT;
scroll_to_top();
model.query.clear();
model.songs.shuffle(&mut thread_rng());
autotype_song(model, orders);
}
Msg::Scroll => {
let Some((scroll, max_scroll)) = get_scroll() else {
error!("Failed to get song list element by id:", SONG_LIST_ID);
return;
};
let scroll_left: i32 = max_scroll - scroll;
// when there are fewer elements than this below the scroll viewport, add more
const ELEMENT_HEIGHT: i32 = 48;
if scroll_left < ELEMENT_HEIGHT * SCROLL_THRESHOLD as i32 {
model.shown_songs += 1;
orders.perform_cmd(timeout(32 /* ms */, || Msg::Scroll));
}
}
Msg::Autotyper => {
model.query_placeholder_len += 1;
while !model
.query_placeholder
.is_char_boundary(model.query_placeholder_len)
{
model.query_placeholder_len += 1;
}
if model.query_placeholder_len < model.query_placeholder.len() {
model.autotyper =
Some(orders.perform_cmd_with_handle(timeout(80, || Msg::Autotyper)));
}
}
}
}
pub fn view(model: &Model) -> Vec<Node<Msg>> {
let song_card = |song: &Song| -> Node<Msg> {
div![
C![C.song_item],
img![
C![C.song_item_cover],
match song.cover {
Some(_) => attrs! {At::Src => format!("/images/songs/{}.png", song.song_hash)},
None => attrs! {At::Src => "/images/default_cover.png"},
},
],
div![
C![C.song_item_info],
div![C![C.song_item_title], &song.title],
div![
C![C.song_item_artist],
span![&song.artist],
if let Some(year) = song.year.as_ref() {
span![" (", year, ")"]
} else {
empty![]
}
],
],
div![
C![C.song_gizmos],
match &song.genre {
Some(genre) => div![
C![C.gizmo, C.note_icon, C.tooltip],
span![C![C.tooltiptext], genre],
],
None => empty![],
},
match &song.language {
Some(language) => div![
C![C.gizmo, C.flag_icon, C.tooltip],
span![C![C.tooltiptext], language],
],
None => empty![],
},
IF![song.video.is_some() => div![
C![C.gizmo, C.video_icon, C.tooltip],
span![
C![C.tooltiptext],
"Musikvideo",
],
]],
match (&song.duet_singer_1, &song.duet_singer_2) {
(Some(p1), Some(p2)) => div![
C![C.gizmo, C.duet_icon, C.tooltip],
span![
C![C.tooltiptext],
"Duet",
div![
C![C.marquee],
// add duplicates to get the repeating marquee effect
p![" 🗲 ", p1, " 🗲 ", p2, " 🗲 ", p1, " 🗲 ", p2]
],
],
],
_ => empty![],
},
],
]
};
vec![
div![
C![C.song_search_bar],
input![
C![C.song_search_field],
input_ev(Ev::Input, Msg::Search),
attrs! {
At::Placeholder => &model.query_placeholder[..model.query_placeholder_len],
At::Value => model.query,
},
],
button![
C![C.song_sort_button, C.tooltip],
IF![model.filter_duets => C![C.song_sort_button_selected]],
ev(Ev::Click, |_| Msg::ToggleDuets),
span![C![C.tooltiptext], "Endast Duetter"],
"D",
],
button![
C![C.song_sort_button, C.tooltip],
IF![model.filter_video => C![C.song_sort_button_selected]],
ev(Ev::Click, |_| Msg::ToggleVideo),
span![C![C.tooltiptext], "Endast med Video"],
"V",
],
button![
C![C.song_sort_button, C.song_sort_button_right, C.tooltip],
IF![model.filter_video => C![C.song_sort_button_selected]],
ev(Ev::Click, |_| Msg::Shuffle),
span![C![C.tooltiptext], "Blanda låtar"],
"🔀",
],
],
div![
C![C.song_list],
attrs! {At::Id => SONG_LIST_ID},
ev(Ev::Scroll, |_| Msg::Scroll),
model
.songs
.iter()
.map(|(_, song)| song)
.map(song_card)
.take(model.songs.len() - model.hidden_songs)
.take(model.shown_songs),
],
]
}
async fn fetch_songs() -> Option<Msg> {
let mut songs: Vec<Song> = match fetch_list_of("/songs").await {
Ok(response) => response,
Err(e) => {
error!("Error fetching songs:", e);
return None;
}
};
songs.shuffle(&mut thread_rng());
Some(Msg::Songs(songs))
}
pub fn autotype_song(model: &mut Model, orders: &mut impl Orders<Msg>) {
let (_, song) = &model.songs[0];
model.query_placeholder = ParsedQuery::random(song, &mut thread_rng()).to_string();
model.query_placeholder_len = 0;
model.autotyper = Some(orders.perform_cmd_with_handle(timeout(100, || Msg::Autotyper)));
}
const SONG_LIST_ID: &str = "song_list";
fn get_song_list_element() -> Option<Element> {
document().get_element_by_id(SONG_LIST_ID)
}
fn scroll_to_top() {
if let Some(elem) = get_song_list_element() {
elem.scroll_to_with_x_and_y(0.0, 0.0);
}
}
fn get_scroll() -> Option<(i32, i32)> {
let list = get_song_list_element()?;
let scroll = list.scroll_top();
let height = list.client_height();
let max = (list.scroll_height() - height).max(0);
Some((scroll, max))
}

7
frontend/src/css.rs Normal file
View File

@ -0,0 +1,7 @@
use css_typegen::css_typegen;
// NOTE: Remember to edit index.html when adding new css-files!
// Generate rust types for css-classes.
// Used for autocompletion and extra compile-time checks.
css_typegen!("frontend/static/styles");

View File

@ -0,0 +1,34 @@
use std::collections::{HashMap, HashSet};
use gloo_console::error;
use crate::{
app::{Loading, Msg},
fetch::fetch_list_of,
};
pub type CustomLists = HashMap<String, Loading<HashSet<String>>>;
pub async fn fetch_custom_song_list_index() -> Option<Msg> {
let custom_lists: Vec<String> = match fetch_list_of("/custom/lists").await {
Ok(response) => response,
Err(e) => {
error!("Failed fetching custom song list index:", e);
return None;
}
};
Some(Msg::CustomSongLists(custom_lists))
}
pub async fn fetch_custom_song_list(list: String) -> Option<Msg> {
let song_hashes: HashSet<String> = match fetch_list_of(format!("/custom/list/{list}")).await {
Ok(response) => response.into_iter().collect(),
Err(e) => {
error!("Failed fetching custom song list:", e);
return None;
}
};
Some(Msg::CustomSongList { list, song_hashes })
}

70
frontend/src/fetch.rs Normal file
View File

@ -0,0 +1,70 @@
use std::io::Cursor;
use gloo_net::http::{Request, Response};
use serde::de::DeserializeOwned;
use wasm_bindgen::{JsError, JsValue};
const HTTP_ACCEPT: &str = concat!("text/csv, ", "application/json;q=0.9");
#[derive(Debug, thiserror::Error)]
pub enum FetchError {
/// The request returned a non-2XX status code.
#[error("server responded with {code} {text}")]
Status { code: u16, text: String },
/// The response contained an unrecognized or missing content type.
#[error("unknown content type {0:?}")]
UnknownContentType(Option<String>),
/// Another error occured.
#[error("{0}")]
Other(#[from] gloo_net::Error),
#[error("error deserializing csv: {0}")]
Csv(#[from] csv::Error),
}
impl From<FetchError> for JsValue {
fn from(e: FetchError) -> Self {
JsError::new(&e.to_string()).into()
}
}
/// Perform a GET request.
pub async fn fetch(url: impl AsRef<str>) -> Result<Response, FetchError> {
let response = Request::get(url.as_ref())
.header("accept", HTTP_ACCEPT)
.send()
.await?;
if !response.ok() {
return Err(FetchError::Status {
code: response.status(),
text: response.status_text(),
});
}
Ok(response)
}
/// Perform a GET request and try to deserialize the response as a `Vec<T>`.
pub async fn fetch_list_of<T: DeserializeOwned>(
url: impl AsRef<str>,
) -> Result<Vec<T>, FetchError> {
let response = fetch(url.as_ref()).await?;
let headers = response.headers();
let content_type = headers.get("Content-Type").map(|s| s.to_lowercase());
match content_type.as_deref() {
Some("text/csv") => {
let text = response.text().await?;
let reader = csv::Reader::from_reader(Cursor::new(text)).into_deserialize();
let list = reader
.map(|r| r.map_err(FetchError::from))
.collect::<Result<_, _>>()?;
Ok(list)
}
Some("application/json") => Ok(response.json().await?),
_ => Err(FetchError::UnknownContentType(content_type)),
}
}

39
frontend/src/fuzzy.rs Normal file
View File

@ -0,0 +1,39 @@
pub type FuzzyScore = i32;
/// Compare a base string to a user-input search
///
/// Returns a tuple of the match score, as well as the indices of every char in `search` which maps
/// to an index in `base`
pub fn compare<B, S>(base: B, search: S) -> FuzzyScore
where
B: Iterator<Item = char> + Clone,
S: IntoIterator<Item = char>,
{
let mut base = base.into_iter().enumerate();
// How alike the search string is to self.name
//let mut score = -(search.len() as i32);
let mut score = 0;
for (_i, sc) in search.into_iter().enumerate() {
let sc = sc.to_ascii_lowercase();
let mut add = 3;
let mut base_tmp = base.clone();
while let Some((_j, bc)) = base_tmp.next() {
let bc = bc.to_ascii_lowercase();
if bc == sc {
score += add;
base = base_tmp;
break;
} else {
add = 2;
}
}
}
score
}
pub fn max_score(query: &str) -> FuzzyScore {
compare(query.chars(), query.chars())
}

13
frontend/src/main.rs Normal file
View File

@ -0,0 +1,13 @@
mod app;
mod css;
mod custom_list;
mod fetch;
mod fuzzy;
mod query;
mod song;
use seed::App;
fn main() {
App::start("app", app::init, app::update, app::view);
}

183
frontend/src/query.rs Normal file
View File

@ -0,0 +1,183 @@
use crate::song::Song;
use rand::seq::SliceRandom;
use rand::Rng;
use std::borrow::Cow;
use std::fmt::{self, Display, Formatter};
use std::ops::Not;
#[derive(Default)]
pub struct ParsedQuery<'a> {
/// Unspecified query.
pub plain: Option<Cow<'a, str>>,
/// Query a specific title
pub title: Option<Cow<'a, str>>,
/// Query a specific artist
pub artist: Option<Cow<'a, str>>,
/// Whether the song is a duet
pub duet: Option<bool>,
/// Whether the song has a video
pub video: Option<bool>,
/// Query a specific language
pub language: Option<&'a str>,
/// Query a specific genre
pub genre: Option<&'a str>,
/// Query from a specifc year
pub year: Option<&'a str>,
/// Query songs from the specified custom list.
pub list: Option<&'a str>,
}
impl<'a> ParsedQuery<'a> {
pub fn parse(s: &'a str) -> Self {
let mut parsed = ParsedQuery {
plain: extract_plain(s),
..Default::default()
};
let kvs = extract_key_values(s);
for (k, v) in kvs {
match k {
"title" => parsed.title = Some(Cow::Borrowed(v)),
"artist" => parsed.artist = Some(Cow::Borrowed(v)),
"duet" => parsed.duet = parse_bool(v),
"video" => parsed.video = parse_bool(v),
"lang" => parsed.language = Some(v),
"genre" => parsed.genre = Some(v),
"year" => parsed.year = Some(v),
"list" => parsed.list = Some(v),
_ => {}
}
}
parsed
}
/// Generate a parsed query with a few random fields matching a song
pub fn random<R: Rng>(song: &'a Song, rng: &mut R) -> Self {
let until_space = |s: &'a str| -> &'a str { s.split_whitespace().next().unwrap_or("") };
let join_spaces = |s: &'a str| -> Cow<'a, str> {
let s = s.trim();
if s.contains(char::is_whitespace) {
s.replace(char::is_whitespace, "").into()
} else {
Cow::Borrowed(s)
}
};
let mut primary_fields: [&dyn Fn(Self) -> Self; 4] = [
&|query| Self {
plain: Some(Cow::Borrowed(&song.title)),
..query
},
&|query| Self {
plain: Some(Cow::Borrowed(&song.artist)),
..query
},
&|query| Self {
title: Some(join_spaces(&song.title)),
..query
},
&|query| Self {
artist: Some(join_spaces(&song.artist)),
..query
},
];
let mut extra_fields: [&dyn Fn(Self) -> Self; 3] = [
&|query| Self {
language: song.language.as_deref().map(until_space),
..query
},
&|query| Self {
genre: song.genre.as_deref().map(until_space),
..query
},
&|query| Self {
year: song.year.as_deref().map(until_space),
..query
},
];
primary_fields.shuffle(rng);
extra_fields.shuffle(rng);
let primary_fields = primary_fields.into_iter().take(1);
let extra_fields = extra_fields.into_iter().take(rng.gen_range(0..2));
primary_fields
.chain(extra_fields)
.fold(Self::default(), |query, field| field(query))
}
}
fn parse_bool(s: &str) -> Option<bool> {
match s {
"true" | "yes" | "y" => Some(true),
"false" | "no" | "n" => Some(false),
_ => None,
}
}
fn extract_plain(s: &str) -> Option<Cow<str>> {
let plain: String =
s.split(' ')
.filter(|word| !word.contains(':'))
.fold(String::new(), |mut a, b| {
if !a.is_empty() {
a.push(' ');
}
a.push_str(b);
a
});
plain.is_empty().not().then_some(Cow::Owned(plain))
}
fn extract_key_values(s: &str) -> impl Iterator<Item = (&str, &str)> {
s.split_whitespace().filter_map(|s| s.split_once(':'))
}
impl Display for ParsedQuery<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut first = true;
let mut w = |prefix: &str, display: Option<&dyn Display>| -> fmt::Result {
match display {
Some(display) => {
if first {
first = false;
} else {
write!(f, " ")?;
}
write!(f, "{}{}", prefix, display)
}
None => Ok(()),
}
};
fn display<T: Display>(v: &Option<T>) -> Option<&dyn Display> {
v.as_ref().map(|s| s as &dyn Display)
}
w("", display(&self.plain))?;
w("title:", display(&self.title))?;
w("artist:", display(&self.artist))?;
w("duet:", display(&self.duet))?;
w("video:", display(&self.video))?;
w("lang:", display(&self.language))?;
w("genre:", display(&self.genre))?;
w("year:", display(&self.year))?;
w("list:", display(&self.list))?;
Ok(())
}
}

93
frontend/src/song.rs Normal file
View File

@ -0,0 +1,93 @@
use crate::app::Loading;
use crate::custom_list::CustomLists;
use crate::fuzzy::{self, FuzzyScore};
use crate::query::ParsedQuery;
use serde::Deserialize;
use std::cmp::max;
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct Song {
pub title: String,
pub artist: String,
pub song_hash: String,
pub cover: Option<String>,
pub language: Option<String>,
pub video: Option<String>,
pub year: Option<String>,
pub genre: Option<String>,
pub bpm: String,
#[serde(rename = "duetsingerp1")]
pub duet_singer_1: Option<String>,
#[serde(rename = "duetsingerp2")]
pub duet_singer_2: Option<String>,
}
impl Song {
pub fn duet(&self) -> Option<(&str, &str)> {
self.duet_singer_1
.as_deref()
.zip(self.duet_singer_2.as_deref())
}
pub fn fuzzy_compare(&self, query: &ParsedQuery, custom_lists: &CustomLists) -> FuzzyScore {
let bad: FuzzyScore = -1;
let filter_strs = |query: Option<&str>, item: Option<&str>| {
if let Some(query) = query {
match item {
Some(item) => {
let score = fuzzy::compare(item.chars(), query.chars());
score == fuzzy::max_score(query)
}
None => false,
}
} else {
true
}
};
let filter_bool =
|query: Option<bool>, item| !matches!(query, Some(query) if query != item);
let filters: &[&dyn Fn() -> bool] = &[
&|| filter_bool(query.duet, self.duet().is_some()),
&|| filter_bool(query.video, self.video.is_some()),
&|| filter_strs(query.language, self.language.as_deref()),
&|| filter_strs(query.genre, self.genre.as_deref()),
&|| filter_strs(query.year, self.year.as_deref()),
];
if !filters.iter().all(|f| f()) {
return bad;
}
if let Some(list) = query.list {
let Some(Loading::Loaded(list)) = custom_lists.get(list) else {
return bad;
};
if !list.contains(&self.song_hash) {
return bad;
}
}
let mut score = FuzzyScore::default();
if let Some(plain) = &query.plain {
let title_score = fuzzy::compare(self.title.chars(), plain.chars());
let artist_score = fuzzy::compare(self.artist.chars(), plain.chars());
score = max(title_score, artist_score);
}
if let Some(title) = &query.title {
let new_score = fuzzy::compare(self.title.chars(), title.chars());
score = max(score, new_score);
}
if let Some(artist) = &query.artist {
let new_score = fuzzy::compare(self.artist.chars(), artist.chars());
score = max(score, new_score);
}
score
}
}

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="151.118px" height="151.118px" viewBox="0 0 151.118 151.118" enable-background="new 0 0 151.118 151.118" xml:space="preserve">
<circle fill="#FFFFFF" stroke="#000000" stroke-width="3" cx="75.559" cy="75.56" r="71.208"/>
<g>
<g>
<path fill="#00B3E6" stroke="#000000" d="M79.393,18.702c-1.27-0.085-2.543-0.143-3.833-0.143c-6.136,0-12.04,0.98-17.578,2.774 c0.458,1.249,0.721,2.592,0.721,4c0,6.429-5.211,11.64-11.64,11.64c-3.645,0-6.895-1.678-9.029-4.3 c-3.313,2.902-6.285,6.18-8.853,9.771h50.212V18.702z M103.104,25.654v16.79h18.835C117,35.541,110.568,29.783,103.104,25.654z M125.401,47.905h-22.298v46.557c0,0-1.151,11.496,11.495,11.496h9.169c5.562-8.801,8.792-19.22,8.792-30.397 C132.56,65.522,129.956,56.097,125.401,47.905z M79.393,94.461c0,0,0-23.276,0-34.917s-11.639-11.64-11.639-11.64h-7.759v46.557 c0,11.641,11.639,11.641,11.639,11.641v7.688H33.283c10.43,11.526,25.507,18.771,42.276,18.771 c16.77,0,31.846-7.244,42.275-18.771h-3.236C114.599,113.788,79.393,115.814,79.393,94.461z M36.717,59.545 c0-10.017-8.614-11.412-11.018-11.606c-4.544,8.184-7.14,17.597-7.14,27.621c0,11.17,3.226,21.58,8.777,30.376 c9.374-1.402,9.38-11.475,9.38-11.475S36.717,71.185,36.717,59.545z"/>
</g>
<g>
<path fill="#00B3E6" stroke="#000000" stroke-width="3" d="M79.393,18.702c-1.27-0.085-2.543-0.143-3.833-0.143 c-6.136,0-12.04,0.98-17.578,2.774c0.458,1.249,0.721,2.592,0.721,4c0,6.429-5.211,11.64-11.64,11.64 c-3.645,0-6.895-1.678-9.029-4.3c-3.313,2.902-6.285,6.18-8.853,9.771h50.212V18.702z M103.104,25.654v16.79h18.835 C117,35.541,110.568,29.783,103.104,25.654z M125.401,47.905h-22.298v46.557c0,0-1.151,11.496,11.495,11.496h9.169 c5.562-8.801,8.792-19.22,8.792-30.397C132.56,65.522,129.956,56.097,125.401,47.905z M79.393,94.461c0,0,0-23.276,0-34.917 s-11.639-11.64-11.639-11.64h-7.759v46.557c0,11.641,11.639,11.641,11.639,11.641v7.688H33.283 c10.43,11.526,25.507,18.771,42.276,18.771c16.77,0,31.846-7.244,42.275-18.771h-3.236 C114.599,113.788,79.393,115.814,79.393,94.461z M36.717,59.545c0-10.017-8.614-11.412-11.018-11.606 c-4.544,8.184-7.14,17.597-7.14,27.621c0,11.17,3.226,21.58,8.777,30.376c9.374-1.402,9.38-11.475,9.38-11.475 S36.717,71.185,36.717,59.545z"/>
</g>
</g>
<g>
<path d="M8.724,80.924l1.055-0.127l0.217,1.832l5.027-0.598l0.151,1.272l-5.027,0.597l0.217,1.831L9.31,85.857L8.724,80.924z"/>
<path d="M9.61,74.781l0.074,3.155l1.296-0.029l-0.067-2.891l1.062-0.024l0.067,2.889l1.578-0.036l-0.077-3.312l1.093-0.025 l0.107,4.562l-6.124,0.144l-0.103-4.405L9.61,74.781z"/>
<path d="M8.573,72.581l0.099-1.246l2.519,0.201L8.86,68.973l0.131-1.645l2.312,2.705l3.804-2.348l-0.13,1.637l-2.817,1.67 l0.576,0.666l2.042,0.163l-0.099,1.246L8.573,72.581z"/>
<path d="M9.257,65.512l0.247-1.311l4.612-1.558l-4.17-0.786l0.22-1.167l6.019,1.134l-0.235,1.251l-4.699,1.603l4.245,0.8 l-0.22,1.167L9.257,65.512z"/>
<path d="M17.4,55.628c0.32,0.581,0.351,1.289,0.095,2.124c-0.256,0.835-0.679,1.404-1.269,1.706 c-0.739,0.421-1.633,0.471-2.683,0.149c-1.071-0.328-1.783-0.87-2.139-1.626c-0.319-0.581-0.351-1.289-0.095-2.124 s0.679-1.404,1.269-1.706c0.717-0.425,1.611-0.474,2.682-0.146C16.31,54.327,17.023,54.868,17.4,55.628z M16.27,56.118 c-0.268-0.392-0.729-0.688-1.384-0.888c-0.652-0.2-1.2-0.213-1.643-0.039c-0.443,0.173-0.738,0.501-0.885,0.982 s-0.087,0.92,0.179,1.315c0.267,0.395,0.728,0.693,1.383,0.894c0.654,0.2,1.203,0.212,1.646,0.034 c0.442-0.178,0.738-0.507,0.885-0.989C16.598,56.946,16.538,56.51,16.27,56.118z"/>
<path d="M13.063,51.3l0.5-1.18l4.633,1.962l1.182-2.791l1.007,0.426l-1.682,3.971L13.063,51.3z"/>
<path d="M22.694,44.202c0.194,0.634,0.081,1.333-0.341,2.099c-0.421,0.765-0.951,1.236-1.59,1.411 c-0.81,0.262-1.695,0.128-2.657-0.401c-0.981-0.54-1.568-1.216-1.761-2.029c-0.194-0.633-0.081-1.333,0.34-2.098 c0.421-0.766,0.951-1.236,1.59-1.412c0.789-0.27,1.673-0.134,2.654,0.405C21.893,42.706,22.48,43.381,22.694,44.202z M21.487,44.451c-0.183-0.438-0.574-0.822-1.174-1.152c-0.598-0.329-1.131-0.453-1.6-0.374c-0.469,0.08-0.825,0.34-1.067,0.781 c-0.243,0.441-0.273,0.882-0.093,1.324c0.181,0.442,0.571,0.828,1.171,1.158s1.135,0.453,1.604,0.369 c0.469-0.084,0.826-0.346,1.068-0.787C21.64,45.329,21.67,44.889,21.487,44.451z"/>
<path d="M23.325,36.713c-0.397-0.163-0.773-0.14-1.126,0.071c-0.196,0.119-0.368,0.282-0.517,0.492 c-0.284,0.401-0.366,0.838-0.247,1.31c0.119,0.472,0.482,0.922,1.089,1.352c0.611,0.433,1.142,0.599,1.594,0.5 c0.452-0.099,0.803-0.328,1.056-0.684c0.247-0.349,0.35-0.706,0.308-1.07c-0.042-0.364-0.206-0.687-0.493-0.968l-0.824,1.164 l-0.829-0.587l1.472-2.079l2.678,1.896l-0.488,0.688l-0.692-0.347c0.094,0.369,0.132,0.667,0.116,0.896 c-0.027,0.395-0.182,0.793-0.466,1.195c-0.469,0.662-1.081,1.042-1.837,1.141c-0.771,0.115-1.556-0.11-2.353-0.675 c-0.807-0.571-1.296-1.251-1.468-2.04c-0.172-0.789,0-1.548,0.518-2.279c0.448-0.633,0.969-1.028,1.562-1.186 c0.593-0.158,1.15-0.094,1.669,0.189L23.325,36.713z"/>
<path d="M27.742,34.873c0.234,0.155,0.441,0.236,0.62,0.241c0.326,0.01,0.656-0.175,0.992-0.554 c0.201-0.227,0.339-0.434,0.415-0.619c0.143-0.353,0.085-0.643-0.172-0.871c-0.151-0.133-0.326-0.17-0.525-0.111 c-0.197,0.061-0.453,0.208-0.768,0.439l-0.541,0.394c-0.532,0.386-0.943,0.616-1.233,0.69c-0.489,0.128-0.957-0.006-1.406-0.402 c-0.409-0.361-0.616-0.813-0.62-1.354s0.251-1.103,0.768-1.688c0.431-0.488,0.927-0.791,1.487-0.909 c0.561-0.118,1.092,0.029,1.594,0.443l-0.817,0.925c-0.291-0.227-0.594-0.277-0.911-0.152c-0.211,0.084-0.416,0.238-0.615,0.463 c-0.221,0.251-0.348,0.495-0.381,0.732c-0.033,0.237,0.04,0.435,0.218,0.591c0.164,0.145,0.351,0.179,0.562,0.103 c0.137-0.047,0.378-0.193,0.723-0.438l0.894-0.632c0.392-0.277,0.734-0.442,1.028-0.496c0.456-0.083,0.888,0.056,1.295,0.416 c0.418,0.369,0.623,0.837,0.614,1.403c-0.009,0.566-0.273,1.143-0.792,1.731c-0.531,0.601-1.085,0.953-1.662,1.056 c-0.577,0.103-1.104-0.056-1.581-0.478L27.742,34.873z"/>
<path d="M32.433,25.651l-2.314,2.146L31,28.748l2.12-1.965l0.722,0.779l-2.12,1.965l1.073,1.157l2.429-2.252l0.744,0.802 l-3.346,3.102l-4.164-4.492l3.231-2.996L32.433,25.651z"/>
<path d="M33.397,23.413l1-0.75l1.518,2.021l0.377-3.443l1.319-0.991l-0.497,3.523l4.278,1.297l-1.313,0.986l-3.117-1.006 l-0.118,0.873l1.23,1.638l-1,0.75L33.397,23.413z"/>
<path d="M42.951,16.963l0.55,0.909l-1.577,0.956l2.623,4.33l-1.096,0.664l-2.623-4.33l-1.577,0.956L38.7,19.539L42.951,16.963z"/>
<path d="M48.265,21.134l-1.14,0.585l-2.797-5.449l1.14-0.585L48.265,21.134z"/>
<path d="M53.806,18.069c-0.244,0.616-0.769,1.092-1.575,1.428c-0.807,0.335-1.515,0.373-2.123,0.111 c-0.796-0.3-1.405-0.958-1.826-1.971c-0.43-1.034-0.467-1.928-0.111-2.685c0.244-0.616,0.769-1.092,1.575-1.428 s1.514-0.373,2.123-0.111c0.785,0.282,1.392,0.939,1.822,1.973C54.113,16.399,54.151,17.294,53.806,18.069z M52.707,17.511 c0.13-0.456,0.064-1-0.199-1.633c-0.262-0.629-0.601-1.06-1.017-1.29c-0.417-0.23-0.857-0.249-1.322-0.055 c-0.465,0.194-0.764,0.519-0.898,0.977s-0.069,1.003,0.193,1.635c0.263,0.632,0.604,1.062,1.024,1.29 c0.42,0.228,0.861,0.245,1.326,0.051C52.279,18.292,52.577,17.967,52.707,17.511z"/>
<path d="M54.397,11.942l1.28-0.375l3.48,3.403l-1.191-4.073l1.14-0.333l1.72,5.878L59.604,16.8l-3.561-3.459l1.213,4.146 l-1.14,0.333L54.397,11.942z"/>
<path d="M65.833,10.335l-3.104,0.573l0.235,1.275l2.843-0.525L66,12.703l-2.843,0.524l0.287,1.552l3.257-0.602l0.199,1.076 l-4.487,0.828l-1.112-6.023l4.333-0.8L65.833,10.335z"/>
<path d="M67.808,8.965l1.33-0.107l2.718,4.039l-0.341-4.23l1.184-0.095l0.492,6.105l-1.269,0.102l-2.785-4.109l0.347,4.306 L68.3,15.07L67.808,8.965z"/>
<path d="M78.854,14.759l-1.279-0.055l0.262-6.119l1.279,0.055L78.854,14.759z"/>
<path d="M81.168,8.739l1.324,0.159l1.862,4.497l0.505-4.213l1.18,0.141l-0.729,6.082l-1.265-0.151l-1.914-4.581l-0.514,4.289 l-1.18-0.141L81.168,8.739z"/>
<path d="M88.194,9.732l4.24,0.942l-0.23,1.037l-2.988-0.665l-0.31,1.388l2.623,0.583l-0.229,1.037l-2.623-0.583l-0.557,2.501 l-1.252-0.278L88.194,9.732z"/>
<path d="M96.917,17.911c-0.588,0.305-1.297,0.318-2.125,0.042c-0.828-0.276-1.388-0.713-1.674-1.311 c-0.402-0.75-0.431-1.645-0.082-2.686c0.354-1.062,0.914-1.761,1.678-2.097c0.59-0.305,1.298-0.319,2.127-0.042 c0.828,0.276,1.387,0.713,1.674,1.311c0.406,0.728,0.434,1.623,0.079,2.685C98.245,16.854,97.687,17.553,96.917,17.911z M96.456,16.769c0.396-0.258,0.705-0.712,0.922-1.362c0.215-0.647,0.242-1.194,0.08-1.641c-0.162-0.447-0.482-0.75-0.961-0.91 c-0.478-0.159-0.916-0.11-1.318,0.147c-0.401,0.257-0.711,0.71-0.928,1.36c-0.217,0.65-0.242,1.198-0.076,1.645 c0.168,0.447,0.49,0.75,0.968,0.91S96.057,17.027,96.456,16.769z"/>
<path d="M104.888,15.472c0.164,0.182,0.276,0.392,0.341,0.628c0.053,0.195,0.074,0.394,0.064,0.596 c-0.012,0.202-0.066,0.413-0.168,0.631c-0.121,0.264-0.309,0.492-0.559,0.685c-0.251,0.193-0.554,0.272-0.908,0.236 c0.207,0.222,0.32,0.452,0.34,0.691c0.019,0.239-0.062,0.554-0.242,0.945l-0.174,0.374c-0.117,0.254-0.188,0.432-0.209,0.532 c-0.037,0.158-0.016,0.296,0.063,0.415l-0.063,0.14l-1.274-0.588c0.022-0.14,0.044-0.25,0.063-0.333 c0.043-0.17,0.101-0.337,0.174-0.502l0.23-0.521c0.159-0.357,0.208-0.623,0.145-0.796c-0.062-0.173-0.258-0.334-0.582-0.484 l-1.137-0.526l-1.01,2.185l-1.135-0.524l2.568-5.56l2.658,1.229C104.454,15.106,104.724,15.289,104.888,15.472z M102.106,15.184 l-0.688,1.489l1.252,0.578c0.248,0.115,0.449,0.171,0.602,0.168c0.27-0.003,0.475-0.161,0.618-0.472 c0.155-0.336,0.153-0.611-0.007-0.825c-0.09-0.121-0.254-0.236-0.492-0.346L102.106,15.184z"/>
<path d="M111.327,18.894l1.566,0.953l-3.18,5.235l-1.014-0.616l2.149-3.541c0.062-0.102,0.149-0.244,0.263-0.426 c0.114-0.182,0.201-0.323,0.262-0.422l-3.656,3.792l-1.062-0.644l1.687-4.99c-0.062,0.1-0.146,0.242-0.256,0.427 c-0.107,0.185-0.193,0.328-0.256,0.43l-2.149,3.541l-1.015-0.616l3.179-5.235l1.586,0.963l-1.55,4.693L111.327,18.894z"/>
<path d="M116.072,22.188l1.153,0.892l-2.041,6.165l-1.096-0.847l0.449-1.233l-1.783-1.379l-1.09,0.737l-1.065-0.825L116.072,22.188 z M113.683,25.16l1.237,0.957l0.865-2.379L113.683,25.16z"/>
<path d="M123.066,28.23l-0.724,0.778l-1.352-1.255l-3.445,3.708l-0.938-0.872l3.446-3.708l-1.352-1.255l0.725-0.778L123.066,28.23z "/>
<path d="M120.504,34.474l-0.875-0.936l4.475-4.182l0.875,0.936L120.504,34.474z"/>
<path d="M125.021,39.041c-0.66-0.067-1.261-0.443-1.804-1.128c-0.541-0.685-0.77-1.356-0.684-2.013 c0.073-0.848,0.541-1.612,1.401-2.293c0.878-0.695,1.729-0.973,2.553-0.836c0.659,0.067,1.261,0.443,1.804,1.128 c0.541,0.685,0.77,1.356,0.684,2.013c-0.059,0.832-0.525,1.595-1.403,2.29C126.709,38.882,125.86,39.162,125.021,39.041z M125.258,37.832c0.476,0.001,0.98-0.21,1.519-0.635c0.534-0.423,0.856-0.866,0.966-1.329c0.107-0.463,0.006-0.892-0.307-1.287 s-0.707-0.595-1.186-0.6c-0.477-0.005-0.982,0.206-1.521,0.63c-0.538,0.424-0.858,0.87-0.963,1.335 c-0.104,0.465-0.002,0.896,0.312,1.29C124.391,37.632,124.784,37.83,125.258,37.832z"/>
<path d="M131.081,37.952l0.705,1.131l-2.334,4.271l3.6-2.249l0.629,1.007l-5.194,3.246l-0.674-1.079l2.367-4.364l-3.664,2.29 l-0.629-1.007L131.081,37.952z"/>
<path d="M131.352,46.758c-0.232,0.158-0.387,0.318-0.46,0.481c-0.134,0.297-0.089,0.673,0.135,1.128 c0.134,0.272,0.271,0.479,0.414,0.62c0.271,0.266,0.562,0.324,0.87,0.172c0.182-0.088,0.281-0.236,0.303-0.443 c0.02-0.206-0.019-0.498-0.113-0.877l-0.156-0.65c-0.154-0.639-0.211-1.106-0.168-1.403c0.066-0.5,0.369-0.882,0.908-1.146 c0.49-0.24,0.985-0.259,1.486-0.057c0.502,0.202,0.924,0.653,1.268,1.354c0.287,0.584,0.377,1.158,0.272,1.722 c-0.104,0.563-0.442,0.998-1.019,1.304l-0.543-1.108c0.32-0.182,0.484-0.443,0.49-0.784c0.002-0.227-0.062-0.475-0.194-0.745 c-0.147-0.3-0.324-0.511-0.531-0.631c-0.207-0.121-0.417-0.129-0.63-0.025c-0.195,0.096-0.299,0.256-0.309,0.48 c-0.01,0.146,0.033,0.424,0.129,0.835l0.242,1.067c0.106,0.468,0.129,0.848,0.065,1.14c-0.099,0.453-0.39,0.8-0.878,1.039 c-0.501,0.245-1.012,0.256-1.531,0.032c-0.521-0.224-0.953-0.688-1.298-1.393c-0.353-0.72-0.467-1.366-0.342-1.938 c0.124-0.573,0.473-0.999,1.044-1.279L131.352,46.758z"/>
<path d="M139.122,54.22l-0.994,0.375l-0.651-1.725l-4.736,1.787l-0.452-1.199l4.736-1.787l-0.65-1.725l0.994-0.375L139.122,54.22z"/>
<path d="M139.737,60.395l-0.83-3.045l-1.251,0.341l0.761,2.789l-1.025,0.279l-0.76-2.789l-1.522,0.415l0.871,3.196l-1.056,0.288 l-1.199-4.402l5.908-1.611l1.158,4.251L139.737,60.395z"/>
<path d="M141.273,62.279l0.204,1.233l-2.493,0.413l2.881,1.925l0.271,1.627l-2.896-2.068l-3.126,3.195l-0.268-1.62l2.331-2.3 l-0.721-0.507l-2.021,0.334l-0.204-1.233L141.273,62.279z"/>
<path d="M142.313,69.3l0.077,1.331l-4.099,2.627l4.236-0.246l0.069,1.185l-6.114,0.356l-0.074-1.271l4.172-2.693l-4.313,0.251 l-0.067-1.186L142.313,69.3z"/>
<path d="M136.42,77.345l0.022-1.281l6.124,0.11l-0.023,1.281L136.42,77.345z"/>
<path d="M142.495,79.542l-0.119,1.244l-2.516-0.238l2.293,2.598l-0.156,1.643l-2.271-2.738l-3.839,2.289l0.154-1.635l2.842-1.627 l-0.565-0.675l-2.04-0.192l0.118-1.244L142.495,79.542z"/>
</g>
<rect x="13.962" y="14.947" fill="none" width="121.094" height="121.095"/>
<g>
<path d="M14.433,92.2c-0.122,0.209-0.31,0.348-0.566,0.416c-0.256,0.065-0.49,0.038-0.702-0.084 c-0.212-0.123-0.351-0.312-0.418-0.568s-0.039-0.488,0.085-0.699s0.315-0.35,0.571-0.417c0.256-0.067,0.488-0.039,0.697,0.084 c0.209,0.124,0.348,0.313,0.415,0.569C14.583,91.756,14.555,91.989,14.433,92.2z"/>
<path d="M17.734,96.76c0.649,0.271,1.115,0.759,1.398,1.464c0.377,0.942,0.34,1.76-0.112,2.446 c-0.256,0.383-0.558,0.654-0.905,0.812l-0.476-1.189c0.242-0.184,0.409-0.361,0.5-0.535c0.163-0.309,0.161-0.67-0.004-1.082 c-0.168-0.42-0.475-0.684-0.92-0.786c-0.445-0.103-0.985-0.027-1.621,0.228c-0.636,0.254-1.062,0.572-1.276,0.954 c-0.215,0.382-0.244,0.771-0.086,1.162c0.162,0.403,0.421,0.655,0.78,0.759c0.194,0.057,0.454,0.065,0.779,0.024l0.476,1.188 c-0.659,0.146-1.265,0.088-1.819-0.174c-0.554-0.263-0.962-0.72-1.223-1.371c-0.323-0.807-0.315-1.545,0.023-2.216 c0.341-0.672,0.969-1.19,1.884-1.558C16.121,96.493,16.988,96.45,17.734,96.76z"/>
<path d="M15.157,104.76l5.418-2.856l0.597,1.134l-2.059,1.086l1.093,2.073l2.06-1.086l0.598,1.134l-5.418,2.855l-0.598-1.133 l2.419-1.275l-1.093-2.072l-2.418,1.274L15.157,104.76z"/>
<path d="M24.609,108.986l0.812,1.211l-3.888,5.201l-0.771-1.149l0.816-1.027l-1.254-1.872l-1.268,0.354l-0.75-1.121L24.609,108.986 z M21.401,111.047l0.871,1.301l1.575-1.982L21.401,111.047z"/>
<path d="M27.297,112.821l0.813,0.989l-3.886,3.194l1.925,2.343l-0.845,0.694l-2.739-3.332L27.297,112.821z"/>
<path d="M33.701,119.881l1.308,1.287l-4.295,4.365l-0.847-0.832l2.905-2.953c0.083-0.086,0.201-0.203,0.354-0.354 c0.152-0.151,0.27-0.269,0.351-0.353l-4.43,2.854l-0.885-0.87l2.786-4.471c-0.082,0.083-0.197,0.202-0.346,0.356 c-0.149,0.155-0.265,0.274-0.348,0.359l-2.905,2.953l-0.846-0.832l4.295-4.366l1.323,1.302l-2.584,4.213L33.701,119.881z"/>
<path d="M38.937,125.708l-2.477-1.957l-0.804,1.019l2.269,1.792l-0.659,0.834l-2.268-1.792l-0.979,1.237l2.599,2.054l-0.678,0.858 l-3.58-2.828l3.797-4.807l3.457,2.731L38.937,125.708z"/>
<path d="M44.062,127.978c0.138,0.203,0.222,0.426,0.253,0.669c0.026,0.2,0.02,0.4-0.018,0.6c-0.038,0.198-0.121,0.399-0.251,0.604 c-0.156,0.245-0.372,0.445-0.646,0.604c-0.275,0.157-0.585,0.194-0.932,0.11c0.176,0.247,0.257,0.491,0.243,0.729 c-0.014,0.24-0.137,0.541-0.369,0.903l-0.222,0.349c-0.151,0.234-0.244,0.401-0.279,0.498c-0.057,0.15-0.055,0.291,0.007,0.42 l-0.083,0.129l-1.183-0.756c0.041-0.135,0.077-0.241,0.108-0.32c0.065-0.163,0.145-0.321,0.24-0.475l0.3-0.484 c0.206-0.333,0.29-0.59,0.25-0.77c-0.04-0.181-0.209-0.367-0.511-0.56l-1.056-0.675l-1.296,2.027l-1.053-0.674l3.298-5.16 l2.468,1.578C43.681,127.557,43.924,127.774,44.062,127.978z M41.345,127.314l-0.883,1.383l1.162,0.743 c0.23,0.146,0.421,0.23,0.573,0.248c0.267,0.032,0.492-0.096,0.677-0.384c0.199-0.312,0.234-0.584,0.105-0.817 c-0.073-0.132-0.22-0.27-0.441-0.41L41.345,127.314z"/>
<path d="M45.217,133.312c-0.091,0.267-0.117,0.485-0.078,0.66c0.073,0.317,0.334,0.591,0.786,0.819 c0.271,0.138,0.505,0.22,0.704,0.246c0.377,0.049,0.644-0.08,0.799-0.387c0.091-0.18,0.083-0.357-0.025-0.535 c-0.109-0.177-0.315-0.387-0.619-0.634l-0.517-0.424c-0.507-0.417-0.834-0.757-0.979-1.021c-0.247-0.439-0.235-0.928,0.035-1.461 c0.247-0.488,0.632-0.802,1.154-0.941c0.522-0.141,1.131-0.034,1.826,0.318c0.581,0.295,0.999,0.697,1.254,1.211 c0.255,0.513,0.246,1.063-0.028,1.652l-1.101-0.559c0.146-0.338,0.119-0.646-0.082-0.92c-0.134-0.184-0.335-0.342-0.604-0.479 c-0.298-0.15-0.566-0.213-0.804-0.186s-0.411,0.147-0.518,0.359c-0.099,0.194-0.084,0.385,0.042,0.568 c0.081,0.121,0.282,0.316,0.605,0.59l0.836,0.706c0.367,0.31,0.613,0.601,0.739,0.87c0.195,0.421,0.169,0.873-0.077,1.357 c-0.252,0.498-0.653,0.812-1.204,0.947c-0.55,0.135-1.175,0.023-1.875-0.332c-0.715-0.361-1.195-0.81-1.44-1.342 c-0.245-0.531-0.223-1.082,0.064-1.65L45.217,133.312z"/>
<path d="M58.45,134.226l-0.344,1.005l-1.744-0.598l-1.642,4.787l-1.212-0.414l1.642-4.789l-1.744-0.598l0.345-1.006L58.45,134.226z "/>
<path d="M63.51,136.602l-3.069-0.738l-0.303,1.262l2.811,0.676l-0.249,1.033l-2.811-0.676l-0.369,1.533l3.221,0.773l-0.256,1.063 l-4.436-1.067l1.433-5.953l4.284,1.029L63.51,136.602z"/>
<path d="M65.268,135.827l1.238,0.168l-0.338,2.504l2.687-2.188l1.635,0.223l-2.828,2.158l2.135,3.928l-1.627-0.221l-1.513-2.904 l-0.697,0.539l-0.274,2.029l-1.239-0.168L65.268,135.827z"/>
<path d="M71.6,136.6l1.333,0.039l2.259,4.312l0.125-4.242l1.188,0.035l-0.18,6.123l-1.272-0.037l-2.317-4.392l-0.127,4.317 l-1.187-0.034L71.6,136.6z"/>
<path d="M79.522,142.725l-1.279,0.059l-0.277-6.119l1.279-0.059L79.522,142.725z"/>
<path d="M82.211,140.633c0.069,0.271,0.17,0.47,0.3,0.593c0.235,0.226,0.604,0.31,1.108,0.249c0.301-0.035,0.541-0.096,0.723-0.184 c0.341-0.168,0.492-0.422,0.451-0.765c-0.022-0.2-0.129-0.344-0.315-0.433c-0.188-0.088-0.478-0.148-0.865-0.186l-0.666-0.068 c-0.653-0.066-1.112-0.17-1.379-0.31c-0.448-0.229-0.709-0.643-0.778-1.237c-0.062-0.543,0.084-1.017,0.441-1.422 c0.357-0.406,0.924-0.654,1.698-0.744c0.646-0.076,1.218,0.029,1.714,0.315s0.793,0.751,0.891,1.394l-1.226,0.145 c-0.065-0.363-0.257-0.604-0.576-0.723c-0.213-0.078-0.469-0.1-0.769-0.064c-0.332,0.039-0.59,0.137-0.771,0.29 c-0.184,0.155-0.261,0.351-0.232,0.586c0.024,0.218,0.143,0.367,0.351,0.451c0.134,0.058,0.41,0.108,0.83,0.155l1.087,0.127 c0.477,0.055,0.843,0.16,1.098,0.316c0.396,0.243,0.623,0.635,0.688,1.174c0.064,0.555-0.096,1.039-0.479,1.455 c-0.386,0.416-0.968,0.67-1.746,0.76c-0.797,0.094-1.443-0.014-1.941-0.322s-0.784-0.777-0.858-1.41L82.211,140.633z"/>
<path d="M86.725,135.772l1.221-0.27l0.543,2.469l1.771-2.979l1.611-0.354l-1.914,3l3.355,2.953l-1.604,0.354l-2.42-2.207 l-0.47,0.745l0.44,2.001l-1.221,0.27L86.725,135.772z"/>
<path d="M94.597,133.771l1.384-0.459l3.979,5.133l-1.313,0.437l-0.772-1.061l-2.14,0.71l0.004,1.316l-1.28,0.425L94.597,133.771z M95.729,137.413l1.484-0.494l-1.491-2.047L95.729,137.413z"/>
<path d="M104.025,136.72l-2.748-5.476l1.146-0.574l1.045,2.082l2.095-1.053l-1.044-2.08l1.145-0.574l2.748,5.474l-1.146,0.575 l-1.228-2.444l-2.095,1.052l1.228,2.443L104.025,136.72z"/>
<path d="M107.144,126.129l0.918-0.594l0.535,0.827l-0.919,0.595L107.144,126.129z M113.952,130.424 c-0.129,0.65-0.562,1.212-1.295,1.687c-0.732,0.474-1.423,0.638-2.068,0.488c-0.836-0.154-1.553-0.69-2.148-1.613 c-0.607-0.94-0.804-1.813-0.588-2.622c0.129-0.648,0.561-1.212,1.294-1.686c0.733-0.475,1.424-0.637,2.069-0.488 c0.822,0.137,1.537,0.676,2.146,1.615C113.956,128.727,114.153,129.6,113.952,130.424z M108.547,125.223l0.918-0.594l0.535,0.826 l-0.918,0.594L108.547,125.223z M112.771,130.071c0.047-0.473-0.115-0.996-0.487-1.57c-0.369-0.572-0.779-0.937-1.229-1.088 c-0.451-0.152-0.888-0.093-1.312,0.182c-0.423,0.273-0.658,0.646-0.709,1.121c-0.051,0.476,0.11,1,0.481,1.574 c0.372,0.576,0.784,0.938,1.237,1.086s0.892,0.088,1.313-0.187S112.725,130.543,112.771,130.071z"/>
<path d="M117.1,123.377c-0.342-0.262-0.709-0.338-1.104-0.229c-0.222,0.062-0.432,0.176-0.629,0.337 c-0.381,0.312-0.576,0.711-0.586,1.198c-0.01,0.486,0.221,1.018,0.692,1.592c0.476,0.579,0.942,0.881,1.403,0.903 c0.463,0.022,0.861-0.103,1.199-0.38c0.332-0.271,0.524-0.588,0.582-0.95c0.055-0.362-0.018-0.718-0.22-1.063l-1.103,0.903 l-0.646-0.785l1.97-1.614l2.08,2.537l-0.652,0.535l-0.575-0.518c-0.007,0.38-0.05,0.678-0.125,0.894 c-0.132,0.374-0.386,0.718-0.767,1.029c-0.627,0.515-1.318,0.719-2.074,0.612c-0.773-0.094-1.471-0.518-2.09-1.272 c-0.627-0.765-0.92-1.55-0.877-2.354c0.043-0.806,0.412-1.494,1.104-2.062c0.602-0.491,1.208-0.735,1.82-0.729 c0.615,0.006,1.135,0.215,1.561,0.625L117.1,123.377z"/>
<path d="M121.618,122.366c0.225,0.168,0.426,0.26,0.604,0.274c0.324,0.028,0.665-0.14,1.021-0.499 c0.213-0.217,0.361-0.414,0.447-0.596c0.162-0.344,0.12-0.637-0.124-0.879c-0.144-0.142-0.315-0.188-0.519-0.14 c-0.2,0.05-0.465,0.183-0.791,0.396l-0.562,0.363c-0.553,0.356-0.976,0.564-1.271,0.623c-0.494,0.102-0.954-0.06-1.381-0.479 c-0.39-0.384-0.57-0.847-0.545-1.386c0.024-0.541,0.312-1.088,0.858-1.644c0.457-0.464,0.97-0.739,1.534-0.825 c0.566-0.089,1.089,0.088,1.566,0.528l-0.867,0.879c-0.276-0.241-0.577-0.31-0.9-0.202c-0.215,0.072-0.428,0.215-0.641,0.43 c-0.233,0.238-0.375,0.476-0.42,0.709c-0.047,0.235,0.016,0.438,0.185,0.604c0.156,0.152,0.341,0.198,0.556,0.133 c0.141-0.039,0.389-0.172,0.746-0.396l0.928-0.582c0.406-0.254,0.758-0.4,1.054-0.438c0.46-0.058,0.884,0.104,1.271,0.486 c0.397,0.393,0.575,0.869,0.536,1.436c-0.04,0.563-0.336,1.125-0.887,1.685c-0.562,0.571-1.136,0.892-1.718,0.963 c-0.58,0.071-1.098-0.116-1.551-0.563L121.618,122.366z"/>
<path d="M122.098,115.749l0.783-0.975l1.97,1.584l-0.483-3.432l1.033-1.284l0.389,3.537l4.465,0.2l-1.027,1.279l-3.27-0.205 l0.102,0.875l1.597,1.283l-0.782,0.975L122.098,115.749z"/>
<path d="M133.273,109.766c0.151,0.646-0.009,1.336-0.479,2.07c-0.472,0.735-1.031,1.17-1.682,1.302 c-0.824,0.207-1.699,0.014-2.624-0.578c-0.942-0.604-1.483-1.317-1.62-2.144c-0.152-0.646,0.008-1.336,0.479-2.07 c0.471-0.735,1.03-1.17,1.681-1.301c0.807-0.217,1.68-0.022,2.622,0.582C132.575,108.219,133.116,108.932,133.273,109.766z M132.053,109.934c-0.152-0.449-0.518-0.857-1.094-1.229c-0.574-0.369-1.099-0.529-1.571-0.48 c-0.474,0.049-0.847,0.283-1.117,0.708c-0.271,0.424-0.332,0.862-0.183,1.313c0.15,0.453,0.516,0.864,1.092,1.233 c0.576,0.37,1.102,0.528,1.576,0.478c0.474-0.051,0.847-0.291,1.119-0.715C132.146,110.819,132.206,110.383,132.053,109.934z"/>
<path d="M129.695,104.815l0.579-1.143l4.486,2.277l1.371-2.703l0.977,0.494l-1.952,3.846L129.695,104.815z"/>
<path d="M132.765,98.278l0.53-1.357l6.49,0.221l-0.505,1.289l-1.31-0.083l-0.82,2.1l1.016,0.839l-0.492,1.256L132.765,98.278z M136.29,99.733l0.568-1.457l-2.527-0.16L136.29,99.733z"/>
<path d="M137.782,90.629c0.208-0.125,0.44-0.153,0.697-0.088c0.256,0.065,0.447,0.205,0.572,0.414 c0.126,0.211,0.154,0.443,0.089,0.699c-0.065,0.258-0.204,0.446-0.415,0.57c-0.212,0.124-0.445,0.152-0.702,0.087 c-0.256-0.065-0.444-0.204-0.567-0.413c-0.123-0.21-0.15-0.443-0.086-0.699C137.437,90.944,137.575,90.754,137.782,90.629z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
viewBox="0 0 16.933333 16.933334"
version="1.1"
id="svg5"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<g
id="layer1">
<path
style="fill:#ffffff;stroke-width:0.0172872"
d="M 2.0431764,16.908998 C 1.9602187,16.872757 1.876554,16.793057 1.8422936,16.717632 1.8116739,16.650224 1.8105455,16.401051 1.810179,9.6279558 L 1.8097869,2.6081437 1.6641359,2.5092064 C 1.2472056,2.2259971 1.0391181,1.8036281 1.0713576,1.3060066 1.0844166,1.1044411 1.1224816,0.96380799 1.2142435,0.77810771 1.3901797,0.42206407 1.7319615,0.15177983 2.1468873,0.0405643 2.3323772,-0.00915361 2.7302473,-0.01417349 2.8988814,0.03107665 3.3528542,0.15289318 3.7091938,0.44111518 3.8848869,0.82859726 4.0597307,1.2142068 4.0366627,1.7326461 3.8292893,2.0781429 3.7421304,2.2233555 3.57164,2.3977544 3.4085243,2.5085543 l -0.1466114,0.099589 -3.921e-4,7.0198121 c -3.92e-4,6.7912266 -0.00142,7.0221046 -0.032342,7.0901846 -0.038333,0.0844 -0.1349174,0.168073 -0.2252432,0.195135 -0.097123,0.0291 -0.8924887,0.02556 -0.960784,-0.0043 z M 4.4373436,12.716063 C 4.2495943,12.658952 4.0830255,12.448031 4.030713,12.201158 3.9938784,12.027325 3.9933603,3.8105555 4.0301903,3.6368753 4.0755058,3.4230858 4.1697878,3.2812388 4.3715252,3.1233409 5.3165223,2.3836996 6.3178698,1.8281179 7.1314687,1.5920287 7.5769935,1.4627473 7.8698032,1.4201238 8.3098088,1.4205014 c 0.489238,3.92e-4 0.8716048,0.059099 1.2965409,0.198971 0.4326523,0.1424116 1.0852773,0.4785873 1.8454873,0.9506357 0.373219,0.2317482 0.431206,0.2606372 0.620161,0.3089634 0.378486,0.096801 0.849505,0.00191 1.427559,-0.2876026 0.334418,-0.1674874 0.481383,-0.2591206 0.80027,-0.4989694 0.380455,-0.286156 0.773889,-0.5542429 0.917678,-0.6253073 0.105568,-0.052175 0.136868,-0.060373 0.191991,-0.050288 0.203687,0.037265 0.387579,0.2559054 0.435924,0.5183002 0.0255,0.1384181 0.02682,8.6933686 0.0014,8.8276256 -0.04196,0.221249 -0.146314,0.34086 -0.54429,0.62386 -1.367655,0.972536 -2.434688,1.331821 -3.326394,1.120042 -0.379668,-0.09017 -0.901986,-0.356434 -1.323138,-0.6745 C 10.371145,11.619406 10.208111,11.5187 9.9025808,11.368732 9.1628643,11.005644 8.5121596,10.936609 7.6874652,11.133724 7.3017711,11.225912 6.8336043,11.405483 6.3827127,11.63418 5.8966468,11.880716 5.6917131,12.0075 4.8136497,12.604888 4.6413416,12.722118 4.5479619,12.749707 4.4373579,12.716063 Z"
id="path836" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
viewBox="0 0 16.933333 16.933334"
version="1.1"
id="svg5"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<g
id="layer1">
<path
style="fill:#ffffff;stroke:#000000;stroke-width:0.027706"
d="M 4.5551369,13.73784 C 4.4712159,13.713848 4.2942016,13.631736 4.1617718,13.555369 3.9569689,13.437269 3.8864653,13.375379 3.6899365,13.141189 3.4947882,12.908643 3.4405963,12.821296 3.3412101,12.579103 3.1831538,12.193936 3.1341667,11.913692 3.1494268,11.481958 3.1792799,10.637362 3.5697022,9.9484817 4.2213186,9.5906614 4.5074657,9.4335284 4.6608076,9.3951632 5.0001725,9.3957953 c 0.3135708,5.704e-4 0.5150999,0.048388 0.7563296,0.1794085 0.3300738,0.1792741 0.6561763,0.5253422 0.8331234,0.8841312 l 0.1088097,0.220629 0.027707,-0.189904 C 6.9470115,8.9761896 6.6960377,6.9399561 6.0763141,5.2177993 5.9357403,4.8271574 5.6389438,4.1214756 5.5058847,3.8615112 5.4508509,3.7539882 5.4112872,3.6595299 5.4179658,3.6516022 5.4567654,3.6055488 6.6007883,3.373365 7.2253505,3.2847856 8.1011111,3.1605811 8.324241,3.1472014 9.5268205,3.1467839 c 1.3500215,-4.564e-4 1.7915365,0.034262 2.9118045,0.2290499 0.55905,0.097205 0.525804,0.083369 0.591628,0.2462207 0.101089,0.2501087 0.329321,1.1059901 0.448665,1.6825274 0.117824,0.5691893 0.214134,1.2008098 0.273853,1.795992 0.04477,0.4461473 0.04513,2.154298 5.77e-4,2.5807942 -0.109067,1.0434349 -0.269326,1.8555249 -0.512069,2.5948459 -0.234881,0.715378 -0.62845,1.181088 -1.191885,1.410356 -0.277845,0.113057 -0.722659,0.133043 -1.014105,0.04557 -1.3979076,-0.419587 -1.8940712,-2.441281 -0.900268,-3.668278 0.536302,-0.6621431 1.349345,-0.8627349 2.060124,-0.508268 0.350035,0.1745629 0.723984,0.571198 0.892645,0.946793 0.04324,0.09629 0.08236,0.175083 0.08692,0.175083 0.01834,0 0.06685,-0.49438 0.09118,-0.9293692 C 13.317443,8.8268273 13.202847,7.6012054 12.980897,6.7000545 12.921884,6.4604495 12.940482,6.4769175 12.667531,6.422634 11.506786,6.1917919 10.005801,6.0828451 8.8237205,6.1436358 8.1898052,6.1762364 7.3817978,6.2496667 7.2414036,6.2874331 c -0.055361,0.014892 -0.05885,0.026539 -0.04285,0.1430145 0.2622878,1.9092854 0.1127805,4.0985924 -0.3905402,5.7188654 -0.2725808,0.877484 -0.7067678,1.380715 -1.3604851,1.576831 -0.2413187,0.0724 -0.6608065,0.07789 -0.8923609,0.01169 z"
id="path836" />
<ellipse
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.00874;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.938225;stop-color:#000000"
id="path958"
cx="8.4408598"
cy="8.4666681"
rx="7.9622936"
ry="7.9622946" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="120"
height="120"
viewBox="0 0 31.75 31.75"
version="1.1"
id="svg8"
sodipodi:docname="penguin1.svg"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview14"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="6.9083333"
inkscape:cx="60"
inkscape:cy="68.54041"
inkscape:window-width="1702"
inkscape:window-height="930"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
style="display:none">
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 7.5967544,-6.2400058 c 0,0 -0.041418,0.1031026 -0.02862,0.2093299 0.012798,0.1062273 0.084435,0.1741091 0.084435,0.1741091 l -0.083147,0.088222 c 0,0 -0.1053512,-0.138166 -0.073877,-0.2774823 0.031474,-0.1393166 0.1012092,-0.1941783 0.101209,-0.1941787 z"
id="path1039" />
</g>
<g
id="layer2"
style="display:inline;fill:#ffffff">
<g
id="g1085"
transform="matrix(4.3607823,0,0,4.3607823,-25.60314,0)"
style="fill:#ffffff">
<path
style="fill:#ffffff;stroke-width:0.0678637"
d="m 8.9055733,7.2413582 c -0.565186,-0.09685 -1.176774,-0.415363 -1.632858,-0.850389 -1.503214,-1.43381 -1.115157,-3.86618 0.767032,-4.807792 0.257986,-0.129065 0.613842,-0.340937 0.790791,-0.470828 0.427006,-0.31344801 0.957267,-0.88614801 0.957267,-1.03388001 0,-0.09418 0.01716,-0.101117 0.08424,-0.03403 0.04633,0.04633 0.09978,0.25562 0.118763,0.465073 l 0.03452,0.380824 0.213389,-0.180047 c 0.117363,-0.09903 0.228326,-0.180047 0.246583,-0.180047 0.01825,0 0.05453,0.199156 0.08059,0.442568 0.04564,0.42610801 0.0569,0.44741901 0.303068,0.57300001 0.140621,0.07174 0.394132,0.23612 0.563357,0.365292 l 0.307682,0.234855 0.07434,-0.163155 c 0.159263,-0.34954 0.752058,-0.0992 0.869072,0.367026 0.06159,0.245394 -0.05541,0.517892 -0.23331,0.543385 -0.08323,0.01193 -0.150934,0.0272 -0.150453,0.03393 4.74e-4,0.0067 0.06156,0.205833 0.135728,0.442438 0.385927,1.231145 -0.08926,2.609103 -1.154563,3.348037 -0.643116,0.446087 -1.5987099,0.656795 -2.3752269,0.523734 z m 1.2351777,-0.136144 c 0.558283,-0.117422 1.025941,-0.369806 1.37326,-0.741116 0.473889,-0.506621 0.628567,-0.967713 0.420215,-1.252649 -0.07888,-0.107873 -0.07888,-0.161324 0,-0.350108 0.121083,-0.289793 0.117727,-0.594607 -0.01134,-1.029201 -0.101025,-0.340191 -0.181472,-0.425109 -0.268827,-0.28377 -0.08904,0.144072 -0.389985,0.0647 -0.617562,-0.162872 -0.17695,-0.176948 -0.230737,-0.287688 -0.230737,-0.475043 0,-0.241031 -0.0037,-0.244309 -0.280028,-0.244309 -0.176302,0 -0.427095,0.07473 -0.6770717,0.201763 l -0.397045,0.201762 -0.337336,-0.209698 c -0.815418,-0.506889 -1.602182,-0.242198 -2.027616,0.682148 -0.191776,0.416675 -0.236961,1.14766 -0.08788,1.421699 0.06294,0.115695 0.06651,0.180504 0.01288,0.234129 -0.116061,0.11606 -0.08718,0.501906 0.059,0.78846 0.482693,0.946148 1.827708,1.480112 3.0700767,1.218805 z M 8.8477543,5.2533082 c -0.424112,-0.10747 -0.654904,-0.301236 -0.592603,-0.497529 0.06213,-0.195726 0.665023,-0.497533 1.076087,-0.538679 0.611047,-0.06116 1.5000967,0.382898 1.3821197,0.69034 -0.119917,0.312492 -1.2041087,0.513493 -1.8656037,0.345868 z m 1.2589217,-0.1425 c 0.456161,-0.135464 0.539706,-0.23998 0.34103,-0.426626 -0.419028,-0.393651 -1.1014207,-0.461363 -1.6826577,-0.166964 -0.455585,0.230757 -0.494803,0.363836 -0.150648,0.511195 0.486065,0.208121 0.97753,0.235258 1.4922757,0.0824 z M 8.6341183,4.7696162 c 0,-0.08863 0.121319,-0.101086 0.82579,-0.08483 0.5862597,0.01353 0.8339577,0.04366 0.8539537,0.103883 0.02154,0.06486 -0.172846,0.08483 -0.8257887,0.08483 -0.72146,0 -0.853955,-0.01612 -0.853955,-0.103884 z m 2.9852977,-1.422177 c 0.116451,-0.140314 0.03796,-0.315999 -0.115476,-0.258467 -0.109958,0.04122 -0.111839,0.03384 -0.02006,-0.07879 0.09429,-0.115732 0.08966,-0.120606 -0.06733,-0.07078 -0.151,0.04792 -0.158931,0.04187 -0.07599,-0.05808 0.08138,-0.09805 0.07308,-0.112539 -0.0684,-0.119456 -0.115019,-0.0056 -0.127085,-0.01674 -0.04224,-0.03891 0.145624,-0.03806 0.154107,-0.128726 0.01697,-0.181351 -0.432561,-0.165989 -0.470623,0.571787 -0.04153,0.804994 0.228877,0.12439 0.311386,0.124558 0.414065,8.42e-4 z m 0.337056,-0.43736 0.16668,-0.128093 -0.131214,-0.243646 c -0.07217,-0.134006 -0.148013,-0.243647 -0.168546,-0.243647 -0.02982,0 -0.274289,0.150867 -0.397626,0.245381 -0.03646,0.02793 0.26552,0.501375 0.318664,0.499607 0.02495,-8.28e-4 0.120369,-0.05915 0.212042,-0.129602 z m 0.629143,-0.248805 c 0.176025,-0.386328 -0.430301,-0.9977 -0.667609,-0.673165 -0.104081,0.142338 -0.09554,0.249613 0.02302,0.289132 0.04119,0.01373 0.09163,-0.03017 0.112083,-0.09756 0.02046,-0.06738 0.02721,-0.03826 0.015,0.0647 -0.01797,0.151566 -0.0046,0.1726 0.0703,0.110451 0.111754,-0.09275 0.124608,0.01632 0.01486,0.126073 -0.05828,0.05827 -0.03712,0.06896 0.08483,0.04283 0.137963,-0.02955 0.144981,-0.02359 0.04653,0.03952 -0.06377,0.04088 -0.09868,0.119327 -0.07757,0.174329 0.06225,0.162216 0.290873,0.116122 0.378559,-0.07633 z"
id="path913-7" />
<path
style="fill:#ffffff;stroke-width:0.0691565"
d="M 7.8768005,4.236173 C 7.6543017,4.153323 7.6524223,3.710674 7.8742605,3.628625 8.0875869,3.549705 8.2761935,3.613255 8.3404236,3.785709 8.4567516,4.098027 8.1933217,4.354002 7.8768404,4.236173 Z M 8.1361383,3.927654 c 0,-0.117352 -0.1782109,-0.133788 -0.2468281,-0.02276 -0.052137,0.08436 0.1031823,0.211193 0.1916582,0.156514 0.030349,-0.01875 0.055173,-0.07894 0.055173,-0.13375 z m 2.6417907,0.232298 c -0.219104,-0.219102 0.03747,-0.636462 0.342282,-0.556756 0.196786,0.05146 0.30135,0.306717 0.201823,0.492685 -0.08796,0.164344 -0.406338,0.201838 -0.544105,0.06407 z m 0.370255,-0.130506 c 0.07127,-0.115313 -0.08903,-0.247547 -0.184421,-0.152145 -0.0798,0.0798 -0.02986,0.227327 0.07696,0.227327 0.03354,0 0.0819,-0.03383 0.107459,-0.07518 z"
id="path913-6-5" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 10.825894,3.3605122 c 0,0 -0.04142,0.1031026 -0.02862,0.2093299 0.0128,0.1062273 0.08444,0.1741091 0.08444,0.1741091 l -0.08315,0.088222 c 0,0 -0.105351,-0.138166 -0.07388,-0.2774823 0.03147,-0.1393166 0.101209,-0.1941783 0.10121,-0.1941787 z"
id="path1039-6" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 7.7793686,3.3458678 c 0,0 -0.04142,0.1031026 -0.02862,0.2093299 0.0128,0.1062273 0.08444,0.1741091 0.08444,0.1741091 l -0.08315,0.088222 c 0,0 -0.105351,-0.138166 -0.07388,-0.2774823 0.03147,-0.1393166 0.101209,-0.1941783 0.10121,-0.1941787 z"
id="path1039-6-2" />
</g>
</g>
<g
id="layer3"
style="display:inline" />
</svg>

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="120"
height="120"
viewBox="0 0 31.75 31.75"
version="1.1"
id="svg8"
sodipodi:docname="penguin2.svg"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview839"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="6.2083333"
inkscape:cx="6.8456376"
inkscape:cy="60"
inkscape:window-width="1702"
inkscape:window-height="930"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
style="display:inline;fill:#ffffff">
<path
style="fill:#ffffff;stroke-width:0.177246"
d="m 13.134179,31.651166 c -1.367874,-0.18043 -3.4872278,-0.85238 -4.780367,-1.51563 -1.871747,-0.96002 -4.179215,-3.22966 -5.0074297,-4.92534 -1.5914865,-3.25839 -1.6801158,-7.72336 -0.2278948,-11.48085 1.0247424,-2.65144 2.7098602,-4.5706201 5.4768881,-6.2376401 4.4640374,-2.6894 6.9208324,-4.59636 8.5218534,-6.61464 0.435944,-0.54955 0.851411,-0.9404 0.923263,-0.86855 0.34663,0.34663 0.709996,2.45556 0.596276,3.46071 l -0.118698,1.04918 0.543199,-0.3868 c 0.298763,-0.21273 0.754695,-0.66407 1.013185,-1.00297 0.258491,-0.3389 0.531184,-0.55268 0.605988,-0.47507 0.277608,0.28804 0.872923,2.3693 0.872923,3.05181 0,0.78189 -0.07309,0.70941 2.140938,2.12277 3.360595,2.14527 5.28622,5.2741001 5.845846,9.4985401 0.238089,1.79727 0.119928,4.12317 -0.289284,5.69424 -0.438918,1.68512 -1.295306,3.20011 -2.596637,4.59356 -2.715779,2.90803 -6.119638,4.1954 -10.928887,4.13338 -1.132683,-0.0146 -2.298705,-0.0581 -2.591161,-0.0967 z m 5.683631,-1.1265 c 5.074026,-0.89873 8.492767,-3.70496 9.49005,-7.7898 0.358508,-1.46844 0.317005,-5.28368 -0.07569,-6.95754 -0.594746,-2.53514 -2.005266,-4.78931 -3.64922,-5.8318801 -1.428352,-0.90583 -1.561881,-0.82384 -2.840659,1.7442101 -0.615739,1.23654 -1.777129,3.21756 -2.580868,4.40229 l -1.461342,2.15404 0.927607,0.3153 c 1.188141,0.40386 2.476979,1.20634 2.848748,1.77373 0.272049,0.4152 0.269021,0.4806 -0.04735,1.02231 -0.778356,1.33273 -2.272203,1.79512 -5.849412,1.81056 l -2.340153,0.0101 -2.489801,2.46697 c -2.6276133,2.60352 -2.8788341,3.03045 -2.0880964,3.54856 1.8126654,1.18771 7.0732674,1.8772 10.1561944,1.33115 z m 3.183004,-13.17071 c -0.205126,-0.14999 -0.329285,-0.4602 -0.329285,-0.8227 0,-0.96498 1.087198,-1.43355 1.715448,-0.73934 0.872429,0.96402 -0.338235,2.3283 -1.386163,1.56204 z m -3.186586,4.78402 c 1.133944,-0.30198 1.619925,-0.56299 1.85054,-0.9939 0.246861,-0.46126 -0.269147,-0.94676 -1.770094,-1.66543 -1.062457,-0.50872 -1.296906,-0.55176 -3.013183,-0.55311 -1.794444,-0.001 -1.910137,0.0225 -3.231141,0.66815 -1.860639,0.90936 -2.118197,1.48499 -0.948717,2.12031 1.182601,0.64245 5.357705,0.89133 7.112595,0.42398 z m -5.26747,-0.96936 c -1.113796,-0.13246 -1.303724,-0.23853 -1.149022,-0.64168 0.08921,-0.23246 0.582443,-0.27351 3.286452,-0.27351 1.749822,0 3.307658,0.0484 3.461858,0.10758 0.350902,0.13466 0.365077,0.53097 0.02367,0.66198 -0.432127,0.16582 -4.555272,0.2726 -5.622968,0.14563 z m -3.7845902,-3.81466 c 0.7343882,-0.537 0.2478022,-1.88618 -0.6802563,-1.88618 -0.5030742,0 -0.9992445,0.51278 -0.9992445,1.03268 0,0.90987 0.9453857,1.39029 1.6795008,0.8535 z"
id="path865" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 7.5967544,-6.2400058 c 0,0 -0.041418,0.1031026 -0.02862,0.2093299 0.012798,0.1062273 0.084435,0.1741091 0.084435,0.1741091 l -0.083147,0.088222 c 0,0 -0.1053512,-0.138166 -0.073877,-0.2774823 0.031474,-0.1393166 0.1012092,-0.1941783 0.101209,-0.1941787 z"
id="path1039" />
</g>
<g
id="layer2"
style="display:none" />
<g
id="layer3"
style="display:none" />
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="120"
height="120"
viewBox="0 0 31.75 31.75"
version="1.1"
id="svg8"
sodipodi:docname="penguin3.svg"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview906"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="6.2083333"
inkscape:cx="6.8456376"
inkscape:cy="60"
inkscape:window-width="1702"
inkscape:window-height="930"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
style="display:none">
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 7.5967544,-6.2400058 c 0,0 -0.041418,0.1031026 -0.02862,0.2093299 0.012798,0.1062273 0.084435,0.1741091 0.084435,0.1741091 l -0.083147,0.088222 c 0,0 -0.1053512,-0.138166 -0.073877,-0.2774823 0.031474,-0.1393166 0.1012092,-0.1941783 0.101209,-0.1941787 z"
id="path1039" />
</g>
<g
id="layer2"
style="display:none" />
<g
id="layer3"
style="display:inline;fill:#ffffff">
<path
style="display:inline;fill:#ffffff;stroke-width:0.294273"
d="M 13.219872,31.561152 C 7.7639295,30.619019 3.1854282,26.04262 2.2530273,20.599337 1.3266857,15.191452 4.3731265,9.445337 9.4587119,7.0081512 12.617064,5.4945709 15.836366,2.8084407 16.825842,0.86116517 L 17.263414,0 17.622933,0.67182296 c 0.19778,0.36951884 0.313308,1.25361504 0.256757,1.96469194 -0.05655,0.7110726 -0.05991,1.2928605 -0.0077,1.2928605 0.05242,0 0.52936,-0.3310521 1.059852,-0.7356803 0.530492,-0.4046239 1.05135,-0.7356802 1.157461,-0.7356802 0.106124,0 0.192929,0.845204 0.192929,1.8782354 v 1.8782312 l 1.580587,0.7733087 c 7.26375,3.5537888 9.530087,12.9645358 4.6616,19.3568408 -3.030552,3.979101 -8.363039,6.069856 -13.304766,5.216521 z m 5.356014,-0.592886 c 3.720242,-0.783427 7.101118,-3.48828 7.892345,-6.314256 0.336074,-1.200345 0.329308,-1.506279 -0.04795,-2.163583 -0.383774,-0.668636 -0.386199,-0.89544 -0.01957,-1.791532 0.938375,-2.291723 -0.417007,-6.522811 -2.67179,-8.34061 -0.91567,-0.738208 -1.4406,-0.918725 -2.942743,-1.011981 -1.593611,-0.09893 -2.045846,0.0015 -3.523445,0.781916 l -1.694978,0.895411 -1.487934,-0.924941 c -3.376446,-2.0989003 -6.6719039,-1.163244 -8.4524067,2.399829 -1.1527548,2.306846 -1.4375744,4.436294 -0.8292982,6.200159 0.2922024,0.847387 0.3536045,1.421626 0.1714833,1.603781 -0.4403631,0.440338 -0.3350945,2.176004 0.2005035,3.304594 0.7011922,1.477632 2.814632,3.472702 4.6084279,4.350322 2.6015972,1.272827 5.8052792,1.640958 8.7973002,1.010891 z m -5.355571,-7.922727 c -1.664073,-0.348285 -2.79605,-1.176171 -2.79605,-2.044978 0,-0.89302 2.504528,-2.316003 4.490206,-2.551169 1.788767,-0.211822 3.947996,0.437993 5.353112,1.610989 0.846392,0.706597 0.936274,0.903347 0.653807,1.431145 -0.704264,1.315915 -4.845636,2.151609 -7.701075,1.554013 z m 5.207815,-0.725102 c 2.110112,-0.626633 2.388166,-1.069391 1.265061,-2.014417 -1.037329,-0.87285 -2.579593,-1.366029 -4.266265,-1.364263 -1.351595,0.0015 -4.190311,1.218923 -4.45594,1.911124 -0.557627,1.453161 4.291873,2.407531 7.457144,1.467556 z m -6.385357,-1.479496 c 0,-0.384327 0.526071,-0.438355 3.580814,-0.367817 2.54216,0.05868 3.616241,0.189313 3.702949,0.450461 0.0934,0.281224 -0.749501,0.367859 -3.580813,0.367859 -3.128417,0 -3.70295,-0.06991 -3.70295,-0.450469 z M 8.5850578,18.025628 c -0.9467707,-0.352541 -0.9547704,-2.236086 -0.010638,-2.585219 0.907738,-0.335818 1.7102922,-0.0654 1.9836022,0.668419 0.494995,1.328966 -0.625944,2.418182 -1.9726282,1.9168 z m 1.1035225,-1.3128 c 0,-0.499353 -0.7583177,-0.569291 -1.0502946,-0.09685 -0.2218645,0.358966 0.439061,0.898662 0.815537,0.665994 0.1291443,-0.07979 0.2347576,-0.335903 0.2347576,-0.569129 z m 11.2412737,0.988467 c -0.932325,-0.932316 0.159441,-2.708253 1.456467,-2.36909 0.837358,0.218971 1.282295,1.305132 0.858791,2.096457 -0.374285,0.699311 -1.729037,0.858855 -2.315258,0.272633 z m 1.575497,-0.555325 c 0.303266,-0.490676 -0.378838,-1.053354 -0.784743,-0.647403 -0.339562,0.339563 -0.127059,0.967315 0.327478,0.967315 0.142719,0 0.348498,-0.143952 0.457256,-0.319903 z"
id="path913-6" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
viewBox="0 0 16.933333 16.933334"
version="1.1"
id="svg5"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<g
id="layer1">
<path
style="fill:#ffffff;stroke-width:0.0400104"
d="M 3.8618918,16.847379 C 3.5531533,16.691409 3.4069553,16.365377 3.501334,16.04331 3.542104,15.904183 3.7461635,15.680279 4.754658,14.668113 l 1.2046249,-1.209011 -1.6453677,-0.01131 c -1.5902084,-0.01093 -1.6490699,-0.01408 -1.7558086,-0.0938 -0.060743,-0.04537 -0.1475633,-0.132205 -0.1929343,-0.192962 -0.081388,-0.10899 -0.08264,-0.151159 -0.093468,-3.148353 -0.00768,-2.127506 0.00178,-3.0378868 0.031602,-3.0378868 0.023417,0 0.1093766,0.033727 0.1910216,0.074948 0.7345785,0.3708761 1.850302,0.3432692 2.6691067,-0.066045 C 5.7138612,6.7085388 6.2607299,6.1897789 6.519511,5.6973179 6.6012857,5.5417011 6.6740408,5.4143778 6.6811899,5.4143778 c 0.00715,0 0.1397658,0.158753 0.2947045,0.3527844 C 7.2814145,6.149769 7.7470505,6.5441028 8.1767625,6.7841447 9.2563186,7.387198 10.599477,7.45749 11.765755,6.9719669 12.07361,6.8438058 12.717706,6.4465246 12.820341,6.3214922 c 0.0302,-0.036792 0.07071,-0.066894 0.09002,-0.066894 0.01931,0 0.03511,0.4321134 0.03511,0.960252 0,0.5281385 0.01007,0.9602519 0.02238,0.9602519 0.01231,0 0.520942,-0.4463311 1.130297,-0.991848 0.609353,-0.5455169 1.13121,-1.0061868 1.15968,-1.0237117 0.02895,-0.01782 0.07745,-0.010555 0.11003,0.016489 0.05008,0.041566 0.05826,0.4790598 0.05826,3.116261 0,3.0603016 -0.0042,3.1639316 -0.127269,3.1639316 -0.01718,0 -0.544543,-0.459119 -1.171905,-1.020267 -0.627363,-0.561147 -1.149843,-1.020268 -1.161068,-1.020268 -0.01122,0 -0.02041,0.570467 -0.02041,1.267705 0,1.207082 -0.004,1.276024 -0.08424,1.441715 -0.05771,0.119213 -0.132808,0.198792 -0.238469,0.252696 -0.145606,0.07428 -0.242097,0.07868 -1.725333,0.07868 H 9.3263383 l 1.1670447,1.170307 c 0.641873,0.643668 1.186109,1.220992 1.209411,1.282941 0.187564,0.498638 -0.240394,1.01204 -0.772351,0.926552 -0.153075,-0.0246 -0.28226,-0.142979 -1.7157132,-1.572241 L 7.664555,13.718401 6.093911,15.284123 C 4.7678227,16.606056 4.4983476,16.856627 4.363225,16.8934 4.1350567,16.955495 4.0627726,16.94886 3.8618918,16.847377 Z M 3.1656223,6.3133233 C 2.3679602,6.0944358 1.7351637,5.415766 1.562666,4.5941638 1.4887316,4.242016 1.4887316,4.0660812 1.562666,3.7139334 1.7851483,2.6542553 2.689375,1.9162056 3.7630675,1.9179159 4.3889609,1.9189745 4.9013558,2.1315077 5.3434821,2.5736334 5.7815991,3.0117503 5.9823409,3.5117648 5.9831752,4.1669999 5.9844152,5.138787 5.370442,5.9838299 4.4511832,6.275568 4.0910672,6.3898546 3.5070228,6.4070076 3.1656223,6.3133233 Z M 9.3845417,6.2918711 C 8.4419841,6.0457608 7.7286787,5.4656719 7.2873968,4.586388 6.9681783,3.9503232 6.878522,3.0823809 7.0608854,2.3935869 7.3531567,1.2896647 8.178748,0.44194365 9.2845167,0.11035277 9.5893612,0.01893829 9.7213451,0.0020182 10.144742,8.106388e-5 10.745297,-0.00267115 11.046898,0.06391438 11.565113,0.31364492 c 0.839924,0.40476359 1.465284,1.16723538 1.705916,2.07994198 0.117201,0.4445347 0.116438,1.1533912 -0.0017,1.5980982 -0.166979,0.628469 -0.559697,1.2513414 -1.040633,1.6505053 -0.320956,0.2663784 -0.961885,0.5837273 -1.351649,0.6692517 -0.40784,0.089491 -1.110077,0.080283 -1.4924962,-0.019571 z"
id="path836" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,15 @@
{
"name": "SingIT",
"short_name": "SingIT",
"start_url": "/",
"display": "standalone",
"background_color": "#09babe",
"description": "Karaokelåtar på IT",
"icons": [
{
"src": "/static/icon.png",
"sizes": "192x192",
"type": "image/png"
}
]
}

View File

@ -0,0 +1,322 @@
body {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
background-color: #0c2738;
color: #ffffff;
height: 100%;
font-family: Ubuntu,serif;
}
body::after {
display: absolute;
top: 0;
bottom: 100vh;
left: 0;
right: 100vw;
background-image: url(/images/background.svg);
background-repeat: no-repeat;
}
.nobr {
white-space: nowrap;
}
.center {
margin: auto;
}
.song_list {
overflow: auto;
position: absolute;
top: 6em;
bottom: 0;
left: 1em;
right: 1em;
}
.song_search_bar {
position: relative;
max-width: 38em;
width: 95%;
margin: auto;
margin-top: 1em;
}
.song_search_field {
border: none;
border-radius: .3em;
padding: .7em 1em;
width: calc(100% - 11em);
color: #0c2738;
margin: 0;
float: left;
height: 2em;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.song_sort_button {
width: 3em;
height: 3.4em;
border-radius: 0;
border-style: none;
border-left-style: solid;
background-color: #427493;
transition: 0.4s;
color: #ffffff;
font-weight: 900;
}
.song_sort_button:hover {
background-color: #5598be;
transition: 0.4s;
}
.song_sort_button:active {
background-color: #30566c;
transition: 0.1s;
}
.song_sort_button_selected {
color: #00ff00;
transition: 0.1s;
}
.song_sort_button_right {
border-top-right-radius: 0.3em;
border-bottom-right-radius: 0.3em;
}
.song_search_counter {
font-size: smaller;
}
.song_item {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
border-radius: 1em;
background: black;
max-width: 40em;
margin: auto;
margin-bottom: 1em;
animation: song_item_enter 1s 1;
box-shadow: #09babe 1px 1px;
}
@keyframes song_item_enter {
from {
opacity: 0;
/*margin-left: -16em;
margin-right: 16em;*/
}
to {
opacity: 1;
/*margin-left: 0;
margin-right: 0;*/
}
}
.song_item_info {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
flex-basis: max-content;
margin: 1em;
}
.song_item_cover {
width: 5em;
height: auto;
object-fit: cover;
border-top-left-radius: 1em;
border-bottom-left-radius: 1em;
}
.song_item_date {
font-size: smaller;
color: #427493;
}
.song_item_title {
margin: 0;
}
.song_item_artist {
font-size: smaller;
color: #adddff;
}
.song_gizmos {
flex-grow: 0;
flex-shrink: 1;
display: flex;
flex-direction: row-reverse;
flex-wrap: wrap;
padding-top: 1em;
padding-bottom: 1em;
padding-right: 0.5em;
}
.song_gizmos div {
margin: 0.5em;
}
.gizmo {
background-size: contain;
background-repeat: no-repeat;
width: 2em;
height: 2em;
}
.duet_icon {
background-image: url("/images/duet.svg");
}
.video_icon {
background-image: url("/images/video.svg");
}
.flag_icon {
background-image: url("/images/flag.svg");
}
.note_icon {
background-image: url("/images/note.svg");
}
.hidden {
visibility: hidden;
}
.play_queue {
position: fixed;
width: 26em;
max-width: 100%;
bottom: 0;
right: 0;
background-color: #434343;
border-top-left-radius: 1em;
border-top-right-radius: 1em;
max-height: 100%;
transition: max-height 0.3s;
}
@media (orientation: portrait) {
.play_queue {
width: 100%;
}
}
.play_queue_hidden {
max-height: 6.3em;
transition: max-height 0.3s;
}
.play_queue_head {
padding: 1em;
padding-top:0.4em;
border-bottom: solid 0.2em;
border-color: #fff;
border-top-left-radius: 1em;
border-top-right-radius: 1em;
background: rgba(99, 99, 99, 0.0);
transition: background 0.1s;
}
.play_queue_head:hover {
background: rgba(99, 99, 99, 1.0);
transition: background 0.1s;
}
.play_queue_list {
padding: 1em;
}
.spinner {
border: 16px solid #f3f3f3;
border-top: 16px solid #0c2738;
border-radius: 50%;
width: 48px;
height: 48px;
animation: spin 1.3s cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
margin: auto;
border-bottom: 16px solid #0c2738;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Tooltip container */
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
}
/* Tooltip text */
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
padding: 5px 0;
border-radius: 6px;
/* Position the tooltip text */
position: absolute;
z-index: 1;
top: 125%;
left: 50%;
margin-left: -100px;
/* Fade in tooltip */
opacity: 0;
transition: opacity 0.3s;
}
/* Tooltip arrow */
.tooltip .tooltiptext::after {
content: "";
position: absolute;
bottom: 100%;
left: 100px;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent #555 transparent;
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}

View File

@ -0,0 +1,25 @@
.marquee {
height: 2em;
overflow: hidden;
position: relative;
border-left: 2px solid #4a4a4a;
border-right: 2px solid #4a4a4a;
}
.marquee p {
position: absolute;
margin: 0;
text-align: center;
white-space: nowrap;
transform: translateX(100%);
animation: scroll-left 6s linear infinite;
}
@keyframes scroll-left {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-50%);
}
}

View File

@ -0,0 +1,58 @@
@keyframes example {
0% {
transform: perspective(36em) rotateY(-90deg);
background-image: url(/images/penguin1.svg);
}
24.99% {
transform: perspective(36em) rotateY(90deg);
background-image: url(/images/penguin1.svg);
}
25% {
transform: perspective(36em) rotateY(90deg);
background-image: url(/images/penguin2.svg);
}
49.99% {
transform: perspective(36em) rotateY(270deg);
background-image: url(/images/penguin2.svg);
}
50% {
transform: perspective(36em) rotateY(270deg);
background-image: url(/images/penguin3.svg);
}
74.99% {
transform: perspective(36em) rotateY(450deg);
background-image: url(/images/penguin3.svg);
}
75% {
transform: perspective(36em) rotateY(450deg);
background-image: url(/images/penguin2.svg);
}
99.99% {
transform: perspective(36em) rotateY(630deg);
background-image: url(/images/penguin2.svg);
}
100% {
transform: perspective(36em) rotateY(630deg);
background-image: url(/images/penguin1.svg);
}
}
.penguin {
width: 12em;
height: 12em;
margin-top: 1em;
margin-bottom: 1em;
background-image: url(/images/penguin1.svg);
background-size: contain;
animation-name: example;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-timing-function: cubic-bezier(0.1, 0.5, 0.9, 0.5);
}
.penguin_small {
width: 1.5em;
height: 1.5em;
margin-top: 0em;
margin-bottom: 0em;
}