mirror of
https://github.com/glassflame/glassflame.github.io.git
synced 2024-11-22 16:14:26 +00:00
Create landing page + bugfixes
This commit is contained in:
parent
fef9dc6155
commit
f14315c39d
6 changed files with 238 additions and 39 deletions
90
index.html
90
index.html
|
@ -13,6 +13,96 @@
|
||||||
@import "style/dark.css";
|
@import "style/dark.css";
|
||||||
</style>
|
</style>
|
||||||
<!-- Templates -->
|
<!-- Templates -->
|
||||||
|
<template id="template-landing">
|
||||||
|
<style>
|
||||||
|
.landing {
|
||||||
|
margin-left: 64px;
|
||||||
|
margin-right: 64px;
|
||||||
|
|
||||||
|
max-width: calc(100vw - 128px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-form label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-form label span {
|
||||||
|
min-width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-form input {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-form input[type="submit"] {
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="landing">
|
||||||
|
<h2>
|
||||||
|
What is this?
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Obsiview is a web viewer for <a href="https://obsidian.md/">Obsidian</a> vaults!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
It's currently in the Alpha development stage, so some features are still missing, but it's already functional!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Please report bugs, suggest features, and leave feedback at <a href="https://github.com/Steffo99/obsidian-file-index/issues">the project's issue tracker</a>!
|
||||||
|
</p>
|
||||||
|
<h2>
|
||||||
|
How do I browse a Vault?
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
To browse a vault, enter its details here:
|
||||||
|
</p>
|
||||||
|
<form class="landing-form">
|
||||||
|
<label>
|
||||||
|
<span>Vault base URL</span>
|
||||||
|
<input type="url" name="vault" required placeholder="https://raw.githubusercontent.com/Steffo99/appunti-magistrali/main/">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Path of the initial file</span>
|
||||||
|
<input type="text" name="path" placeholder="8 - Crittografia applicata/2 - Comunicazione simmetrica/3 - Indistinguibilità/★ mappa concettuale.canvas">
|
||||||
|
</label>
|
||||||
|
<input type="submit" value="Open">
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
Alternatively, browse an example vault, such as:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="./?vault=https%3A%2F%2Fraw.githubusercontent.com%2FSteffo99%2Fappunti-magistrali%2Fmain%2F&path=9 - Algoritmi distribuiti/1 - Problemi/★ problemi.canvas">Steffo's University notes on Distributed Problems</a></li>
|
||||||
|
<li><a href="./?vault=https%3A%2F%2Fraw.githubusercontent.com%2Fobsidianmd%2Fobsidian-help%2Fmaster%2Fen%2F&path=Home.md>">Obsidian's own documentation</a> (no wikilinks)</li>
|
||||||
|
</ul>
|
||||||
|
<h2>
|
||||||
|
Wikilinks are not working!
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
To resolve Wikilinks, full knowledge of a Vault's contents is required.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Obsidian does not include a list of files in a Vault anywhere in it, because it operates under the assumption that this would be trivial to do via the file system.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Obsiview, running on the web, does not have this ability, and needs to somehow learn about it.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To solve this problem, the <a href="https://github.com/Steffo99/obsidian-file-index"><code>steffo-file-index</code></a> plugin was developed; once installed in a given Vault, and once the <code>steffo-file-index.json</code> file it generates is published, Obsiview will be able to resolve Wikilinks.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<template id="template-vault">
|
<template id="template-vault">
|
||||||
<style>
|
<style>
|
||||||
.vault {
|
.vault {
|
||||||
|
|
|
@ -5,84 +5,174 @@ import {fileDetails, filePath} from "../utils/file.mjs";
|
||||||
*/
|
*/
|
||||||
export class BrowseElement extends HTMLBodyElement {
|
export class BrowseElement extends HTMLBodyElement {
|
||||||
/**
|
/**
|
||||||
* Parameters to be used to display *things*.
|
* @returns {string|null} The base URL of the current vault.
|
||||||
* @type {{vault: string, path: string, highlight: string}}
|
|
||||||
*/
|
*/
|
||||||
parameters
|
get vault() {
|
||||||
|
return new URLSearchParams(window.location.search).get("vault")
|
||||||
/**
|
}
|
||||||
* Recalculate the value of {@link parameters} using the current {@link window.location}.
|
set vault(value) {
|
||||||
* @returns {void}
|
window.location.replace(this.urlFor({vault: value}))
|
||||||
*/
|
|
||||||
recalculateParameters() {
|
|
||||||
const location = window.location
|
|
||||||
const params = new URLSearchParams(location.search)
|
|
||||||
const vault = params.get("vault")
|
|
||||||
const path = params.get("path")
|
|
||||||
const highlight = location.hash.replace(/^#/, "")
|
|
||||||
this.parameters = {vault, path, highlight}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
urlFor({vault = this.parameters.vault, path = this.parameters.path, highlight = this.parameters.highlight}) {
|
/**
|
||||||
|
* @returns {string} The path of the current displayed file.
|
||||||
|
*/
|
||||||
|
get path() {
|
||||||
|
return new URLSearchParams(window.location.search).get("path") || "README.md"
|
||||||
|
}
|
||||||
|
set path(value) {
|
||||||
|
window.location.replace(this.urlFor({path: value}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the URL to reach a certain page, using the current {@link vault} and {@link path} as default, and overwriting them with the function's arguments.
|
||||||
|
* @param vault The base URL of the vault to use.
|
||||||
|
* @param path The file path of the file to display.
|
||||||
|
* @returns {URL} The resulting URL.
|
||||||
|
*/
|
||||||
|
urlFor({vault = this.vault, path = this.path}) {
|
||||||
const location = window.location
|
const location = window.location
|
||||||
const params = new URLSearchParams(location.search)
|
const params = new URLSearchParams(location.search)
|
||||||
params.set("vault", vault)
|
params.set("vault", vault)
|
||||||
params.set("path", path)
|
params.set("path", path)
|
||||||
const url = new URL(location)
|
const url = new URL(location)
|
||||||
url.search = params.toString()
|
url.search = params.toString()
|
||||||
url.hash = highlight
|
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add a landing page
|
/**
|
||||||
|
* The landing page element, telling the user how to view a vault.
|
||||||
|
* Can be recreated by {@link recreateLandingElement}.
|
||||||
|
* Mutually exclusive with {@link vaultElement}.
|
||||||
|
* @type {LandingElement|null}
|
||||||
|
*/
|
||||||
|
landingElement
|
||||||
|
|
||||||
|
recreateLandingElement() {
|
||||||
|
if(this.landingElement) {
|
||||||
|
this.landingElement.remove()
|
||||||
|
this.landingElement = null
|
||||||
|
}
|
||||||
|
if(this.vaultElement) {
|
||||||
|
this.vaultElement.remove()
|
||||||
|
this.vaultElement = null
|
||||||
|
}
|
||||||
|
if(this.rootDisplayElement) {
|
||||||
|
this.rootDisplayElement.remove()
|
||||||
|
this.rootDisplayElement = null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vaultElement = document.createElement("x-landing")
|
||||||
|
|
||||||
|
this.appendChild(this.vaultElement)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The vault element, describing to its descendants how to handle various situations.
|
* The vault element, describing to its descendants how to handle various situations.
|
||||||
* @type {VaultElement}
|
* Can be recreated by {@link recreateVaultElement}.
|
||||||
|
* Mutually exclusive with {@link landingElement}.
|
||||||
|
* @type {VaultElement|null}
|
||||||
*/
|
*/
|
||||||
vaultElement
|
vaultElement
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recreate {@link vaultElement} with the current value of {@link vault}.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
recreateVaultElement() {
|
||||||
|
if(this.landingElement) {
|
||||||
|
this.landingElement.remove()
|
||||||
|
this.landingElement = null
|
||||||
|
}
|
||||||
|
if(this.vaultElement) {
|
||||||
|
this.vaultElement.remove()
|
||||||
|
this.vaultElement = null
|
||||||
|
}
|
||||||
|
if(this.rootDisplayElement) {
|
||||||
|
this.rootDisplayElement.remove()
|
||||||
|
this.rootDisplayElement = null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vaultElement = document.createElement("x-vault")
|
||||||
|
this.vaultElement.base = this.vault
|
||||||
|
this.vaultElement.cooldownMs = 0
|
||||||
|
|
||||||
|
this.appendChild(this.vaultElement)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The title of the page.
|
* The title of the page.
|
||||||
|
* Can be recreated by {@link recreateTitleElement}.
|
||||||
* @type {HTMLHeadingElement}
|
* @type {HTMLHeadingElement}
|
||||||
*/
|
*/
|
||||||
titleElement
|
titleElement
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of this application, displayed if no page is being shown.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
static APP_NAME = "Obsiview"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recreate {@link titleElement} with the current value of {@link path}.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
recreateTitleElement() {
|
||||||
|
if(this.titleElement) {
|
||||||
|
this.titleElement.remove()
|
||||||
|
this.titleElement = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const vault = this.vault
|
||||||
|
|
||||||
|
let name
|
||||||
|
if(vault === null) {
|
||||||
|
name = this.constructor.APP_NAME
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
name = fileDetails(this.path).name
|
||||||
|
}
|
||||||
|
|
||||||
|
this.titleElement = document.createElement("h1")
|
||||||
|
this.titleElement.innerText = name
|
||||||
|
|
||||||
|
this.appendChild(this.titleElement)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The display element showing the contents of the specified file.
|
* The display element showing the contents of the specified file.
|
||||||
* @type {DisplayElement}
|
* Can be recreated by {@link recreateRootDisplayElement}.
|
||||||
|
* Mutually exclusive with {@link landingElement}.
|
||||||
|
* @type {DisplayElement|null}
|
||||||
*/
|
*/
|
||||||
rootDisplayElement
|
rootDisplayElement
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recreate all contents of this element to match the current value of {@link parameters}.
|
* Recreate {@link rootDisplayElement} with the current value of {@link path}.
|
||||||
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
recreateContents() {
|
recreateRootDisplayElement() {
|
||||||
if(this.vaultElement) {
|
if(this.rootDisplayElement) {
|
||||||
this.vaultElement.remove()
|
this.rootDisplayElement.remove()
|
||||||
this.vaultElement = null
|
|
||||||
this.rootDisplayElement = null
|
this.rootDisplayElement = null
|
||||||
}
|
}
|
||||||
|
|
||||||
const {name} = fileDetails(this.parameters.path)
|
|
||||||
this.titleElement = document.createElement("h1")
|
|
||||||
this.titleElement.innerText = name
|
|
||||||
this.appendChild(this.titleElement)
|
|
||||||
|
|
||||||
this.vaultElement = document.createElement("x-vault")
|
|
||||||
this.vaultElement.base = this.parameters.vault
|
|
||||||
this.vaultElement.cooldownMs = 0
|
|
||||||
|
|
||||||
this.rootDisplayElement = document.createElement("x-display")
|
this.rootDisplayElement = document.createElement("x-display")
|
||||||
this.rootDisplayElement.path = this.parameters.path
|
this.rootDisplayElement.path = this.path
|
||||||
this.rootDisplayElement.slot = "vault-child"
|
this.rootDisplayElement.slot = "vault-child"
|
||||||
|
|
||||||
this.vaultElement.appendChild(this.rootDisplayElement)
|
this.vaultElement.appendChild(this.rootDisplayElement)
|
||||||
this.appendChild(this.vaultElement)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.recalculateParameters()
|
this.recreateTitleElement()
|
||||||
this.recreateContents()
|
if(this.vault === null) {
|
||||||
|
this.recreateLandingElement()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.recreateVaultElement()
|
||||||
|
this.recreateRootDisplayElement()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,3 +3,4 @@ export {MarkdownElement, HashtagElement, WikilinkElement, FrontMatterElement} fr
|
||||||
export {DisplayElement} from "./display.mjs"
|
export {DisplayElement} from "./display.mjs"
|
||||||
export {VaultElement} from "./vault.mjs"
|
export {VaultElement} from "./vault.mjs"
|
||||||
export {BrowseElement} from "./browse.mjs"
|
export {BrowseElement} from "./browse.mjs"
|
||||||
|
export {LandingElement} from "./landing.mjs"
|
||||||
|
|
11
src/elements/landing.mjs
Normal file
11
src/elements/landing.mjs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import {CustomElement} from "./base.mjs";
|
||||||
|
|
||||||
|
export class LandingElement extends CustomElement {
|
||||||
|
static get template() {
|
||||||
|
return document.getElementById("template-landing")
|
||||||
|
}
|
||||||
|
|
||||||
|
onConnect() {
|
||||||
|
super.onConnect()
|
||||||
|
}
|
||||||
|
}
|
|
@ -137,6 +137,9 @@ export class VaultElement extends CustomElement {
|
||||||
*/
|
*/
|
||||||
async refetchAppearance() {
|
async refetchAppearance() {
|
||||||
const response = await this.fetchCooldown(".obsidian/appearance.json")
|
const response = await this.fetchCooldown(".obsidian/appearance.json")
|
||||||
|
if(response.status >= 400) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const appearance = await response.json()
|
const appearance = await response.json()
|
||||||
const accentColor = appearance.accentColor
|
const accentColor = appearance.accentColor
|
||||||
if(accentColor.match(/^#[0-9A-F]{3}$|^#[0-9A-F]{6}$/i)) {
|
if(accentColor.match(/^#[0-9A-F]{3}$|^#[0-9A-F]{6}$/i)) {
|
||||||
|
@ -159,6 +162,7 @@ export class VaultElement extends CustomElement {
|
||||||
const response = await this.fetchCooldown("steffo-file-index.json")
|
const response = await this.fetchCooldown("steffo-file-index.json")
|
||||||
if(response.status >= 400) {
|
if(response.status >= 400) {
|
||||||
this.fileIndex = null
|
this.fileIndex = null
|
||||||
|
return
|
||||||
}
|
}
|
||||||
this.fileIndex = await response.json()
|
this.fileIndex = await response.json()
|
||||||
this.#fileIndexQueue.forEach(resolve => resolve(undefined))
|
this.#fileIndexQueue.forEach(resolve => resolve(undefined))
|
||||||
|
|
|
@ -9,9 +9,12 @@ import {
|
||||||
NodeTextElement,
|
NodeTextElement,
|
||||||
FrontMatterElement,
|
FrontMatterElement,
|
||||||
MarkdownElement,
|
MarkdownElement,
|
||||||
VaultElement, BrowseElement
|
VaultElement,
|
||||||
|
BrowseElement,
|
||||||
|
LandingElement,
|
||||||
} from "./elements/index.mjs";
|
} from "./elements/index.mjs";
|
||||||
|
|
||||||
|
customElements.define("x-landing", LandingElement)
|
||||||
customElements.define("x-vault", VaultElement)
|
customElements.define("x-vault", VaultElement)
|
||||||
customElements.define("x-display", DisplayElement)
|
customElements.define("x-display", DisplayElement)
|
||||||
customElements.define("x-canvas", CanvasElement)
|
customElements.define("x-canvas", CanvasElement)
|
||||||
|
|
Loading…
Reference in a new issue