1
Fork 0
mirror of https://github.com/glassflame/glassflame.github.io.git synced 2024-11-22 08:04:27 +00:00

Create landing page + bugfixes

This commit is contained in:
Steffo 2023-10-30 04:49:36 +01:00
parent fef9dc6155
commit f14315c39d
Signed by: steffo
GPG key ID: 2A24051445686895
6 changed files with 238 additions and 39 deletions

View file

@ -13,6 +13,96 @@
@import "style/dark.css";
</style>
<!-- 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">
<style>
.vault {

View file

@ -5,84 +5,174 @@ import {fileDetails, filePath} from "../utils/file.mjs";
*/
export class BrowseElement extends HTMLBodyElement {
/**
* Parameters to be used to display *things*.
* @type {{vault: string, path: string, highlight: string}}
* @returns {string|null} The base URL of the current vault.
*/
parameters
/**
* Recalculate the value of {@link parameters} using the current {@link window.location}.
* @returns {void}
*/
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}
get vault() {
return new URLSearchParams(window.location.search).get("vault")
}
set vault(value) {
window.location.replace(this.urlFor({vault: value}))
}
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 params = new URLSearchParams(location.search)
params.set("vault", vault)
params.set("path", path)
const url = new URL(location)
url.search = params.toString()
url.hash = highlight
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.
* @type {VaultElement}
* Can be recreated by {@link recreateVaultElement}.
* Mutually exclusive with {@link landingElement}.
* @type {VaultElement|null}
*/
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.
* Can be recreated by {@link recreateTitleElement}.
* @type {HTMLHeadingElement}
*/
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.
* @type {DisplayElement}
* Can be recreated by {@link recreateRootDisplayElement}.
* Mutually exclusive with {@link landingElement}.
* @type {DisplayElement|null}
*/
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() {
if(this.vaultElement) {
this.vaultElement.remove()
this.vaultElement = null
recreateRootDisplayElement() {
if(this.rootDisplayElement) {
this.rootDisplayElement.remove()
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.path = this.parameters.path
this.rootDisplayElement.path = this.path
this.rootDisplayElement.slot = "vault-child"
this.vaultElement.appendChild(this.rootDisplayElement)
this.appendChild(this.vaultElement)
}
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
this.recalculateParameters()
this.recreateContents()
this.recreateTitleElement()
if(this.vault === null) {
this.recreateLandingElement()
}
else {
this.recreateVaultElement()
this.recreateRootDisplayElement()
}
}
}

View file

@ -3,3 +3,4 @@ export {MarkdownElement, HashtagElement, WikilinkElement, FrontMatterElement} fr
export {DisplayElement} from "./display.mjs"
export {VaultElement} from "./vault.mjs"
export {BrowseElement} from "./browse.mjs"
export {LandingElement} from "./landing.mjs"

11
src/elements/landing.mjs Normal file
View 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()
}
}

View file

@ -137,6 +137,9 @@ export class VaultElement extends CustomElement {
*/
async refetchAppearance() {
const response = await this.fetchCooldown(".obsidian/appearance.json")
if(response.status >= 400) {
return
}
const appearance = await response.json()
const accentColor = appearance.accentColor
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")
if(response.status >= 400) {
this.fileIndex = null
return
}
this.fileIndex = await response.json()
this.#fileIndexQueue.forEach(resolve => resolve(undefined))

View file

@ -9,9 +9,12 @@ import {
NodeTextElement,
FrontMatterElement,
MarkdownElement,
VaultElement, BrowseElement
VaultElement,
BrowseElement,
LandingElement,
} from "./elements/index.mjs";
customElements.define("x-landing", LandingElement)
customElements.define("x-vault", VaultElement)
customElements.define("x-display", DisplayElement)
customElements.define("x-canvas", CanvasElement)