203 lines
5.9 KiB
JavaScript
203 lines
5.9 KiB
JavaScript
|
/* gmi.js is licensed under CC0 */
|
||
|
class Gemini {
|
||
|
constructor({modes} = {modes: false}) {
|
||
|
this.modes = modes
|
||
|
this.allThemes = {
|
||
|
default: {
|
||
|
icon: "🎨",
|
||
|
colors: [
|
||
|
getComputedStyle(document.documentElement).getPropertyValue(`--foreground`),
|
||
|
getComputedStyle(document.documentElement).getPropertyValue(`--background`)
|
||
|
],
|
||
|
},
|
||
|
}
|
||
|
|
||
|
if (this.modes) {
|
||
|
css(`#toggleMode {
|
||
|
font-size: 1rem;
|
||
|
cursor: pointer;
|
||
|
position: fixed;
|
||
|
top: 0.5rem;
|
||
|
right: 0.5rem;
|
||
|
padding: 0.3rem;
|
||
|
margin-top: 0.1rem;
|
||
|
border: none;
|
||
|
color: var(--background);
|
||
|
background-color: var(--foreground);
|
||
|
}`)
|
||
|
this.toggleMode = document.createElement("button")
|
||
|
this.toggleMode.id = "toggleMode"
|
||
|
this.toggleMode.textContent = this.mode
|
||
|
this.toggleMode.onclick = () => {
|
||
|
this.mode = this.mode === "light" ? "dark" : "light"
|
||
|
this.toggleMode.textContent = this.mode
|
||
|
}
|
||
|
}
|
||
|
|
||
|
window.addEventListener("load", () => {
|
||
|
this.mode = this.mode
|
||
|
document.body.append(this.toggleMode)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
set foreground(value) { return this.set("foreground", value) }
|
||
|
get(property) { return document.documentElement.style.getPropertyValue(`--${property}`) }
|
||
|
set(property, value) { return document.documentElement.style.setProperty(`--${property}`, value) }
|
||
|
get foreground() { return this.get("foreground") }
|
||
|
get background() { return this.get("background") }
|
||
|
set background(value) { return this.set("background", value) }
|
||
|
get fontSize() { return this.get("font-size") }
|
||
|
set fontSize(value) { return this.set("font-size", value) }
|
||
|
get mono() { return this.get("mono") }
|
||
|
set mono(value) { return this.set("mono", value) }
|
||
|
get serif() { return this.get("serif") }
|
||
|
set serif(value) { return this.set("serif", value) }
|
||
|
get sansSerif() { return this.get("sans-serif") }
|
||
|
set sansSerif(value) { return this.set("sans-serif", value) }
|
||
|
|
||
|
get mode() { return localStorage.getItem("mode") || "light" }
|
||
|
set mode(value) {
|
||
|
if (!/^(light|dark)$/.test(value))
|
||
|
throw Error("Invalid mode: use either 'light' or 'dark'")
|
||
|
localStorage.setItem("mode", value)
|
||
|
this.colors()
|
||
|
}
|
||
|
|
||
|
get theme() {
|
||
|
const theme = localStorage.getItem("theme")
|
||
|
return !theme || !this.allThemes[theme] ? "default" : theme
|
||
|
}
|
||
|
set theme(theme) {
|
||
|
if (this.themeSwitcher) this.themeSwitcher.textContent = this.allThemes[theme].icon
|
||
|
localStorage.setItem("theme", theme)
|
||
|
this.colors()
|
||
|
}
|
||
|
|
||
|
colors() {
|
||
|
const theme = this.allThemes[this.theme]
|
||
|
const foreground = theme.colors[0]
|
||
|
const background = theme.colors[1]
|
||
|
if (this.mode == "dark") {
|
||
|
this.foreground = background
|
||
|
this.background = foreground
|
||
|
} else {
|
||
|
this.foreground = foreground
|
||
|
this.background = background
|
||
|
}
|
||
|
}
|
||
|
|
||
|
themes(themes, mode) {
|
||
|
this.mode = mode || this.mode
|
||
|
this.allThemes = Object.assign(themes, this.allThemes)
|
||
|
|
||
|
css(`#themeSwitcher {
|
||
|
font-size: 1.5rem;
|
||
|
position: fixed;
|
||
|
top: 0.5rem;
|
||
|
right: ${this.modes ? "3.3rem" : "1rem"};
|
||
|
cursor: pointer;
|
||
|
border: none;
|
||
|
background: none;"
|
||
|
}`)
|
||
|
this.themeSwitcher = document.createElement("button")
|
||
|
this.themeSwitcher.id = "themeSwitcher"
|
||
|
this.themeSwitcher.onclick = () => {
|
||
|
const names = Object.keys(this.allThemes)
|
||
|
let next = names.indexOf(this.theme) + 1
|
||
|
next = next <= names.length - 1 ? next : 0
|
||
|
this.theme = names[next]
|
||
|
}
|
||
|
document.body.append(this.themeSwitcher)
|
||
|
|
||
|
this.theme = this.theme
|
||
|
return this
|
||
|
}
|
||
|
|
||
|
clickToCopy() {
|
||
|
css(`pre:hover {
|
||
|
cursor: pointer;
|
||
|
}
|
||
|
pre:hover::before {
|
||
|
content: "click to copy";
|
||
|
color: var(--foreground);
|
||
|
background-color: var(--background);
|
||
|
float: right;
|
||
|
}`)
|
||
|
for (const pre of document.getElementsByTagName('pre')) {
|
||
|
pre.onclick = () => {
|
||
|
navigator.clipboard.writeText(pre.textContent)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return this
|
||
|
}
|
||
|
|
||
|
inline({images, audio, video} = {images: false, audio: false, video: false}) {
|
||
|
if(images) {
|
||
|
css(`img {
|
||
|
display: block;
|
||
|
max-width: 100%;
|
||
|
}`)
|
||
|
const IMAGE_EXTENSIONS = /\.(jpeg|jpg|png|gif|bmp|svg|ico|webp|tiff)$/
|
||
|
for (const link of document.getElementsByTagName('a')) {
|
||
|
if (IMAGE_EXTENSIONS.test(link.pathname)) {
|
||
|
const img = document.createElement("img")
|
||
|
img.src = link.href
|
||
|
img.title = link.textContent.replace(/\n$/, "")
|
||
|
link.append(img)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (audio) {
|
||
|
css(`audio {
|
||
|
width: 100%;
|
||
|
display: block;
|
||
|
}`)
|
||
|
const AUDIO_EXTENSIONS = /\.(mp3|ogg)$/
|
||
|
for (const link of document.getElementsByTagName('a')) {
|
||
|
if (AUDIO_EXTENSIONS.test(link.pathname)) {
|
||
|
const audio = document.createElement("audio")
|
||
|
audio.src = link.href
|
||
|
audio.title = link.textContent.replace(/\n$/, "")
|
||
|
audio.controls = true
|
||
|
audio.currentTime = true
|
||
|
audio.preload = "none"
|
||
|
link.append(audio)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (video) {
|
||
|
css(`video {
|
||
|
width: 100%;
|
||
|
display: block;
|
||
|
}`)
|
||
|
const VIDEO_EXTENSIONS = /\.(mp4|webm|ogv|mov)$/
|
||
|
for (const link of document.getElementsByTagName('a')) {
|
||
|
if (VIDEO_EXTENSIONS.test(link.pathname)) {
|
||
|
const video = document.createElement("video")
|
||
|
video.src = link.href
|
||
|
video.title = link.textContent.replace(/\n$/, "")
|
||
|
video.controls = true
|
||
|
video.currentTime = true
|
||
|
video.preload = "metadata"
|
||
|
link.append(video)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return this
|
||
|
}
|
||
|
}
|
||
|
function css(css) {
|
||
|
if (!this.style) {
|
||
|
this.style = document.createElement("style")
|
||
|
document.documentElement.append(this.style)
|
||
|
}
|
||
|
this.style.textContent = this.style.textContent + "\n" + css
|
||
|
|
||
|
return this
|
||
|
}
|