Website shell
+Load your website's main stylesheet, JavaScript, markdown, and other assets once and keep them around between page navigations. Saving bandwidth and increases page load times considerably.
+ +diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8d16b98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+vegvisir
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..3b5234f
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "vegvisir"]
+ path = vegvisir
+ url = https://codeberg.org/vegvisir/vegvisir
diff --git a/Consts.php b/Consts.php
new file mode 100644
index 0000000..c17bc35
--- /dev/null
+++ b/Consts.php
@@ -0,0 +1,8 @@
+= VV::css("modules/docs/contribute/style.css") ?>
- Have you found a problem om this page? Would you like to help make this little project a bit better?Contribute? 💕
-
!REF#
";
- }
-
- // Use enum name in lowercase as highlight.js lanuage definer
- $output = "";
- $output .= htmlspecialchars(file_get_contents($path));
- $output .= "
";
-
- return $output;
- }
- }
-
-?>
-
-
\ No newline at end of file
diff --git a/modules/snippet/snippet.js b/modules/snippet/snippet.js
deleted file mode 100644
index 0eefd2a..0000000
--- a/modules/snippet/snippet.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import hljs from "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/es/highlight.min.js";
-
-import php from "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/es/languages/php.min.js";
-import css from "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/es/languages/css.min.js";
-import plaintext from "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/es/languages/plaintext.min.js";
-import javascript from "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/es/languages/javascript.min.js";
-
-hljs.registerLanguage("php", php);
-hljs.registerLanguage("css", css);
-hljs.registerLanguage("plaintext", plaintext);
-hljs.registerLanguage("javascript", javascript);
-
-// Initialize syntax highlighting for all code snippets on this page
-const highlightElements = () => {
- [...document.querySelectorAll("pre code")].forEach(element => hljs.highlightElement(element));
-}
-
-document.querySelector("[vv-shell-id='6ccb0465']").addEventListener(vegvisir.Navigation.EVENTS.FINISHED, () => highlightElements);
-highlightElements();
diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/description-additional.js b/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/description-additional.js
deleted file mode 100644
index 106a2c7..0000000
--- a/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/description-additional.js
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- target: HTMLElement
-}
\ No newline at end of file
diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/description.js
deleted file mode 100644
index b3ebdcd..0000000
--- a/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/description.js
+++ /dev/null
@@ -1,4 +0,0 @@
-static Navigation.EVENTS = {
- STARTED: "navstarted",
- FINISHED: "navfinished"
-}
\ No newline at end of file
diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/example-0-0.js b/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/example-0-0.js
deleted file mode 100644
index e58f8c6..0000000
--- a/modules/snippet/snippets/docs/API/JS/Navigation/EVENTS/example-0-0.js
+++ /dev/null
@@ -1,3 +0,0 @@
-document.addEventListener(vegvisir.Navigation.EVENTS.STARTED, (event) => {
- console.log(event.detail.target);
-});
\ No newline at end of file
diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/MODE/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/MODE/description.js
deleted file mode 100644
index 06714d6..0000000
--- a/modules/snippet/snippets/docs/API/JS/Navigation/MODE/description.js
+++ /dev/null
@@ -1,4 +0,0 @@
-static Navigation.MODE = {
- REPLACE: "replace",
- INSERT: "insert"
-}
\ No newline at end of file
diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/POSITION/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/POSITION/description.js
deleted file mode 100644
index 45bba4a..0000000
--- a/modules/snippet/snippets/docs/API/JS/Navigation/POSITION/description.js
+++ /dev/null
@@ -1,6 +0,0 @@
-static Navigation.POSITION = {
- AFTEREND: "afterend",
- BEFOREEND: "beforeend",
- AFTERBEGIN: "afterbegin",
- BEFOREBEGIN: "beforebegin"
-}
\ No newline at end of file
diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/description.js
deleted file mode 100644
index 3cbd36c..0000000
--- a/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/description.js
+++ /dev/null
@@ -1,6 +0,0 @@
-static Navigation.TARGET = {
- TOP: "_top",
- SELF: "_self",
- BLANK: "_blank",
- PARENT: "_parent"
-};
\ No newline at end of file
diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/example-0-0.php b/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/example-0-0.php
deleted file mode 100644
index 3f1b1de..0000000
--- a/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/example-0-0.php
+++ /dev/null
@@ -1 +0,0 @@
-Click here to replace this button with the contents of /some-page
\ No newline at end of file
diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/example-0-1.php b/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/example-0-1.php
deleted file mode 100644
index 6d9658f..0000000
--- a/modules/snippet/snippets/docs/API/JS/Navigation/TARGET/example-0-1.php
+++ /dev/null
@@ -1,4 +0,0 @@
-...
- Click here to replace this button and its siblings with /some-page - \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/abort/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/abort/description.js deleted file mode 100644 index 08afca9..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/abort/description.js +++ /dev/null @@ -1 +0,0 @@ -Navigation.abort: AbortController \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/bindElements/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/bindElements/description.js deleted file mode 100644 index e02da3b..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/bindElements/description.js +++ /dev/null @@ -1 +0,0 @@ -static Navigation.bindElements(): void \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/bindElements/example-0-0.js b/modules/snippet/snippets/docs/API/JS/Navigation/bindElements/example-0-0.js deleted file mode 100644 index e31c81f..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/bindElements/example-0-0.js +++ /dev/null @@ -1,5 +0,0 @@ -// The programatically appended anchor tag will not have Vegvisir event listeners on it yet -document.body.appendChild(document.createElement("a")); - -// It will have Vegvisir event listeners after this method is called -vegvisir.Navigation.bindElements(); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/constructor/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/constructor/description.js deleted file mode 100644 index b42d7a7..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/constructor/description.js +++ /dev/null @@ -1,4 +0,0 @@ -new globalThis.vegvisir.Navigation( - URL|String url = window.location, - Object options = vegvisir.Navigation.options -): Navigation \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-0.js b/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-0.js deleted file mode 100644 index 6494008..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-0.js +++ /dev/null @@ -1,2 +0,0 @@ -// Pathname string with leading slash -const nav = new vegvisir.Navigation("/some-page"); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-1.js b/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-1.js deleted file mode 100644 index 7e8d07a..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-1.js +++ /dev/null @@ -1,2 +0,0 @@ -// Pathname string without leading slash and a search parameter -const nav = new vegvisir.Navigation("some-page?foo=bar"); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-2.js b/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-2.js deleted file mode 100644 index a45cada..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/constructor/example-0-2.js +++ /dev/null @@ -1,6 +0,0 @@ -// URL object with a pathname and search parameter -const url = new URL(window.location); -url.pathname = "/some-page"; -url.searchParams.set("foo", "bar"); - -const nav = new vegvisir.Navigation(url); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/0.js b/modules/snippet/snippets/docs/API/JS/Navigation/navigate/0.js deleted file mode 100644 index 02e89ef..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/0.js +++ /dev/null @@ -1,4 +0,0 @@ -const nav = new vegvisir.Navigation("/some-page"); - -// Will navigate the top shell to /some-page -nav.navigate(); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/1.js b/modules/snippet/snippets/docs/API/JS/Navigation/navigate/1.js deleted file mode 100644 index 970bf78..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/1.js +++ /dev/null @@ -1,5 +0,0 @@ -const target = document.querySelector("#target"); -const nav = new vegvisir.Navigation("/some-page"); - -// Will replace the contents of an element with id #target with the contents of /some-page -nav.navigate(target); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/2.js b/modules/snippet/snippets/docs/API/JS/Navigation/navigate/2.js deleted file mode 100644 index 1ce57bd..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/2.js +++ /dev/null @@ -1,8 +0,0 @@ -const target = document.querySelector("#target"); -const nav = new vegvisir.Navigation("/some-page"); - -// Will place the contents of /some-page after the target element as a sibling -nav.navigate(target, vegvisir.Navigation.POSITION.AFTEREND); - -// Tip: You can also pass an insertAdjacentElement position string directly -nav.navigate(target, "afterend"); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/navigate/description.js deleted file mode 100644 index 1714708..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/description.js +++ /dev/null @@ -1,5 +0,0 @@ -Navigation.navigate( - target: HTMLELement = Navigation.#rootShellElement - position: Navigation.POSITION = Navigation.POSITION.BEFOREEND, - mode: Navigation.MODE = Navigation.MODE.REPLACE -): void \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/example-0-0.js b/modules/snippet/snippets/docs/API/JS/Navigation/navigate/example-0-0.js deleted file mode 100644 index 54c9df6..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/navigate/example-0-0.js +++ /dev/null @@ -1,6 +0,0 @@ -const target = document.querySelector("#update-this-element"); -const button = document.querySelector("#click-me-to-refresh"); - -const nav = new vegvisir.Navigation("/page-with-new-content"); - -button.addEventListener("click", () => nav.navigate(target)); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/JS/Navigation/options/description.js b/modules/snippet/snippets/docs/API/JS/Navigation/options/description.js deleted file mode 100644 index c2bc5aa..0000000 --- a/modules/snippet/snippets/docs/API/JS/Navigation/options/description.js +++ /dev/null @@ -1,3 +0,0 @@ -{ - pushHistory: boolean -} \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/css/0.php b/modules/snippet/snippets/docs/API/PHP/VV/css/0.php deleted file mode 100644 index ebb4007..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/css/0.php +++ /dev/null @@ -1,4 +0,0 @@ - - -// Without file extension (appended automatically) - \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/css/1.php b/modules/snippet/snippets/docs/API/PHP/VV/css/1.php deleted file mode 100644 index 0c6476c..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/css/1.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/css/2.php b/modules/snippet/snippets/docs/API/PHP/VV/css/2.php deleted file mode 100644 index 77d81a2..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/css/2.php +++ /dev/null @@ -1 +0,0 @@ -"const hello = ()=>console.log('Hello world');hello()" \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/css/description.php b/modules/snippet/snippets/docs/API/PHP/VV/css/description.php deleted file mode 100644 index 3251b2c..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/css/description.php +++ /dev/null @@ -1,4 +0,0 @@ -VV::css( - string $pathname, - bool $relative = true -): string \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/css/example-1-0.css b/modules/snippet/snippets/docs/API/PHP/VV/css/example-1-0.css deleted file mode 100644 index 0d2c803..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/css/example-1-0.css +++ /dev/null @@ -1,6 +0,0 @@ -/* File: /var/www/my-website/public/assets/css/style.css */ - -p { - color: blue; - background-color: red; -} \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/css/example-1-1.php b/modules/snippet/snippets/docs/API/PHP/VV/css/example-1-1.php deleted file mode 100644 index dfb160d..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/css/example-1-1.php +++ /dev/null @@ -1,4 +0,0 @@ -// File: /var/www/my-website/public/index.php - - -Some content...
\ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/embed/0.php b/modules/snippet/snippets/docs/API/PHP/VV/embed/0.php deleted file mode 100644 index ebb4007..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/embed/0.php +++ /dev/null @@ -1,4 +0,0 @@ - - -// Without file extension (appended automatically) - \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/embed/1.php b/modules/snippet/snippets/docs/API/PHP/VV/embed/1.php deleted file mode 100644 index 0c6476c..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/embed/1.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/embed/2.php b/modules/snippet/snippets/docs/API/PHP/VV/embed/2.php deleted file mode 100644 index 77d81a2..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/embed/2.php +++ /dev/null @@ -1 +0,0 @@ -"const hello = ()=>console.log('Hello world');hello()" \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/embed/description.php b/modules/snippet/snippets/docs/API/PHP/VV/embed/description.php deleted file mode 100644 index 70b5401..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/embed/description.php +++ /dev/null @@ -1,4 +0,0 @@ -VV::embed( - string $pathname, - bool $relative = true -): string \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/embed/example-1-0.php b/modules/snippet/snippets/docs/API/PHP/VV/embed/example-1-0.php deleted file mode 100644 index c1826be..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/embed/example-1-0.php +++ /dev/null @@ -1,3 +0,0 @@ -/* File: /var/www/my-website/public/assets/media/logo.svg */ - - \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/embed/example-1-1.php b/modules/snippet/snippets/docs/API/PHP/VV/embed/example-1-1.php deleted file mode 100644 index 5c07fee..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/embed/example-1-1.php +++ /dev/null @@ -1,5 +0,0 @@ -// File: /var/www/my-website/shells/document.php - -Important text!
-Some header content
- = VV::include("modules/banner") ?> -Some content...
- \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/root/0.php b/modules/snippet/snippets/docs/API/PHP/VV/root/0.php deleted file mode 100644 index 34f4b5a..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/root/0.php +++ /dev/null @@ -1 +0,0 @@ -VV::root("/src/databases"); \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/root/1.txt b/modules/snippet/snippets/docs/API/PHP/VV/root/1.txt deleted file mode 100644 index 38f9b6d..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/root/1.txt +++ /dev/null @@ -1 +0,0 @@ -"/var/www/my-website/src/databases" \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/root/2.php b/modules/snippet/snippets/docs/API/PHP/VV/root/2.php deleted file mode 100644 index c5b8f90..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/root/2.php +++ /dev/null @@ -1,9 +0,0 @@ -// File: /var/www/my-website/src/MyClass.php - - -A normal Vegvisir page whch has access to MyClass
\ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/root/description.php b/modules/snippet/snippets/docs/API/PHP/VV/root/description.php deleted file mode 100644 index 6bf4ff6..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/root/description.php +++ /dev/null @@ -1,3 +0,0 @@ -VV::root( - string $pathname = "" -): string \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/shell/0.php b/modules/snippet/snippets/docs/API/PHP/VV/shell/0.php deleted file mode 100644 index 0df0de9..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/shell/0.php +++ /dev/null @@ -1 +0,0 @@ -= VV::shell("shells/docs") ?> \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/shell/description.php b/modules/snippet/snippets/docs/API/PHP/VV/shell/description.php deleted file mode 100644 index 9d82be9..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/shell/description.php +++ /dev/null @@ -1,3 +0,0 @@ -VV::shell( - string $pathname = "" -): never \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/shell/example-0-0.php b/modules/snippet/snippets/docs/API/PHP/VV/shell/example-0-0.php deleted file mode 100644 index 091a064..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/shell/example-0-0.php +++ /dev/null @@ -1,4 +0,0 @@ -// File: /var/www/my-website/public/some-page.php - -Inner content
-= VV::shell("shells/outer-content") ?> \ No newline at end of file diff --git a/modules/snippet/snippets/docs/API/PHP/VV/shell/example-0-1.php b/modules/snippet/snippets/docs/API/PHP/VV/shell/example-0-1.php deleted file mode 100644 index 9dad618..0000000 --- a/modules/snippet/snippets/docs/API/PHP/VV/shell/example-0-1.php +++ /dev/null @@ -1,5 +0,0 @@ -// File: /var/www/my-website/shells/some-shell.php - -This paragraph will be above the wrapped content
-This parahraph will be below the wrapped content
\ No newline at end of file diff --git a/modules/snippet/snippets/docs/installation/0.txt b/modules/snippet/snippets/docs/installation/0.txt deleted file mode 100644 index 6a68fe0..0000000 --- a/modules/snippet/snippets/docs/installation/0.txt +++ /dev/null @@ -1 +0,0 @@ -git clone https://codeberg.org/vegvisir/vegvisir.git --depth 1 \ No newline at end of file diff --git a/modules/snippet/snippets/docs/installation/1.txt b/modules/snippet/snippets/docs/installation/1.txt deleted file mode 100644 index 312037a..0000000 --- a/modules/snippet/snippets/docs/installation/1.txt +++ /dev/null @@ -1 +0,0 @@ -composer install --optimize-autoloader \ No newline at end of file diff --git a/modules/snippet/snippets/docs/installation/2.txt b/modules/snippet/snippets/docs/installation/2.txt deleted file mode 100644 index 92a4de8..0000000 --- a/modules/snippet/snippets/docs/installation/2.txt +++ /dev/null @@ -1,16 +0,0 @@ -# You might need to alter this block to suit your NGINX configuration -# The important thing is that all requests should be routed to /public/index.php - -server { - listen 80; - server_name _; - - root /var/www/vegvisir/public; - - location / { - try_files /index.php =503; - - include snippets/fastcgi-php.conf; - fastcgi_pass unix:/run/php/php8.3-fpm.sock; - } -} \ No newline at end of file diff --git a/modules/snippet/snippets/docs/installation/3.txt b/modules/snippet/snippets/docs/installation/3.txt deleted file mode 100644 index 8b30c60..0000000 --- a/modules/snippet/snippets/docs/installation/3.txt +++ /dev/null @@ -1 +0,0 @@ -mkdir /var/www/my-website \ No newline at end of file diff --git a/modules/snippet/snippets/docs/installation/4.txt b/modules/snippet/snippets/docs/installation/4.txt deleted file mode 100644 index 038eaa1..0000000 --- a/modules/snippet/snippets/docs/installation/4.txt +++ /dev/null @@ -1 +0,0 @@ -cp -p /var/www/vegvisir/.env.example.ini /var/www/vegvisir/.env.ini \ No newline at end of file diff --git a/modules/snippet/snippets/docs/installation/5.txt b/modules/snippet/snippets/docs/installation/5.txt deleted file mode 100644 index 7c45f5b..0000000 --- a/modules/snippet/snippets/docs/installation/5.txt +++ /dev/null @@ -1,10 +0,0 @@ -# /var/www/vegvisir/.env.ini - -; +--------------------+ -; | Base configuration | -; +--------------------+ - -; An absolute path to the root directory of your website -root_path = "/var/www/my-website" - -... \ No newline at end of file diff --git a/public/assets/css/document.css b/public/assets/css/document.css deleted file mode 100644 index 524af4b..0000000 --- a/public/assets/css/document.css +++ /dev/null @@ -1,267 +0,0 @@ -:root { - --primer-color-deep: 0, 128, 255; - --primer-color-light: 135, 255, 255; - --color-deep: rgba(var(--primer-color-deep)); - --color-light: rgba(var(--primer-color-light)); - - --border-style-width: 1px; - --border-style: solid var(--border-style-width) rgba(var(--primer-color-deep), .2); - - --padding: 10px; - --running-size: 70px; - --max-width: 1400px; -} - -/* # Cornerstones */ - -* { - margin: 0; - color: inherit; - font-size: inherit; - box-sizing: border-box; - font-family: monospace; -} - -body { - font-size: 15px; - overflow-x: hidden; - overscroll-behavior: none; -} - -body.menuOpen { - overflow: hidden; -} - -a { - color: inherit; - display: contents; - text-decoration: none; -} - -/* # Components */ - -:is(h1, h2, h3, p, li) > a { - --underline-tickness: 3px; - - display: initial; - text-decoration: underline; - text-decoration-color: var(--color-accent); - text-underline-offset: var(--underline-tickness); - text-decoration-thickness: var(--underline-tickness); -} - -@media (hover: hover) { - :is(h1, h2, h3, p, li) > a:hover { - text-decoration-color: var(--color-deep); - } -} - -h1 { - font-size: 30px; - color: var(--color-accent); -} - -h2 { - font-size: 25px; -} - -h3 { - font-size: 18px; -} - -/* ## Container */ - -container { - margin: auto; - height: 100%; - display: flex; - width: clamp(200px, 100%, 80vw); - max-width: var(--max-width); - align-items: center; - gap: var(--padding); - padding: var(--padding) 0; -} - -container.split { - display: grid; - grid-template-columns: repeat(2, 1fr); -} - -container.split.reverse div:last-child { - order: -1; -} - -container.split > div { - display: flex; - flex-direction: column; - align-items: baseline; - gap: var(--padding); -} - -/* ## Button */ - -button { - border: unset; - fill: black; - cursor: pointer; - padding: 10px 15px; - border-radius: 4px; - background-color: rgba(0, 0, 0, 0); - border: solid var(--border-style-width) transparent; -} - -button.solid { - fill: white; - color: white; - background-color: var(--color-deep); -} - -button.shade { - background-color: rgba(0, 0, 0, .05); -} - -@media (hover: hover) { - button:hover { - background-color: rgba(var(--primer-color-light), .3); - } - - button.solid:hover { - color: var(--color-light); - background-color: var(--color-deep); - } -} - -button svg { - fill: inherit; - width: 1em; -} - -/* # Content */ - -/* ## Runners */ - -:is(header, footer) ul { - display: flex; - padding-left: 0; - list-style: none; - gap: var(--padding); -} - -:is(header, footer) ul:last-of-type { - margin-left: auto; -} - -:is(header, footer) container > button { - display: none; - margin-left: auto; -} - -/* ### Header */ - -header { - --border-width: 2px; - - top: 0px; - position: sticky; - background-color: white; - height: calc(var(--running-size) + var(--border-style-width)); - border-bottom: var(--border-style); - z-index: 1000; -} - -header .logo { - height: 40px; - padding: 5px; - border-radius: 4px; - background-color: var(--color-deep); -} - -[vv-top-page="/"] header:not(.transparent) a[href="/"] button, -[vv-top-page="/help"] header a[href="/help"] button, -[vv-top-page^="/docs"] header a[href="/docs"] button, -[vv-top-page="/demos"] header a[href="/demos"] button, -[vv-top-page="/why"] header a[href="/why"] button { - font-weight: bold; - color: var(--color-deep); - border: var(--border-style); -} - -/* ### Footer */ - -footer { - padding: var(--padding); - color: var(--color-light); - background-color: var(--color-deep); -} - -/* ### Menu */ - -menu { - display: none; - position: fixed; - top: var(--running-size); - left: 0; - width: 100svw; - padding: calc(var(--padding) * 2); - height: calc(100svh - var(--running-size)); - background-color: var(--color-deep); -} - -body.menuOpen menu { - display: initial; -} - -menu ul { - list-style: none; - padding-left: unset; -} - -menu button { - color: white; - width: 100%; - margin-top: var(--padding); -} - -/* # Size queries */ - -@media (max-width: 950px) { - container { - min-width: unset; - width: 100%; - padding: calc(var(--padding) * 2); - } - - container.split { - display: flex; - flex-direction: column; - } - - container.split.reverse { - flex-direction: column-reverse; - } - - header ul button.solid, - :is(header, footer) ul:not(:last-of-type) { - display: none; - } - - :is(header, footer) container > button { - display: initial; - } - - footer :is(container, ul) { - flex-direction: column; - } - - footer button, - footer ul:last-of-type { - width: 100%; - margin-left: unset; - } -} - -@media (min-width: 950px) { - body.menuOpen menu { - display: none; - } -} \ No newline at end of file diff --git a/public/assets/css/fonts.css b/public/assets/css/fonts.css new file mode 100644 index 0000000..782405f --- /dev/null +++ b/public/assets/css/fonts.css @@ -0,0 +1,8 @@ +@font-face { + font-family: "Roboto Mono"; + src: + url("/assets/fonts/roboto-mono.woff2") format("woff2 supports variations"), + url("/assets/fonts/roboto-mono.woff2") format("woff2-variations") + ; + font-weight: 100 900; +} \ No newline at end of file diff --git a/public/assets/css/pages/demos.css b/public/assets/css/pages/demos.css deleted file mode 100644 index 036cef3..0000000 --- a/public/assets/css/pages/demos.css +++ /dev/null @@ -1,26 +0,0 @@ -/* # WIP */ - -section#wip { - background-color: rgba(var(--primer-color-light), .3); -} - -section#wip container { - flex-direction: column; - gap: var(--padding); -} - -/* # Websites */ - -section#websites container { - flex-direction: column; -} - -section#websites ul { - list-style: none; - padding-left: unset; -} - -section#websites button { - margin-top: var(--padding); - width: 100%; -} \ No newline at end of file diff --git a/public/assets/css/pages/docs/aside.css b/public/assets/css/pages/docs/aside.css new file mode 100644 index 0000000..e056190 --- /dev/null +++ b/public/assets/css/pages/docs/aside.css @@ -0,0 +1,22 @@ +aside { + grid-area: aside; + padding: var(--padding); +} + +aside > p { + text-align: center; + margin: var(--padding) 0; +} + +aside nav { + display: flex; + flex-direction: column; + gap: calc(var(--padding) / 2); +} + +aside .spacer { + width: 100%; + height: 1px; + background-color: rgba(var(--primer-color-accent), .1); + margin: var(--padding) 0; +} \ No newline at end of file diff --git a/public/assets/css/pages/docs/header.css b/public/assets/css/pages/docs/header.css new file mode 100644 index 0000000..f8c81e2 --- /dev/null +++ b/public/assets/css/pages/docs/header.css @@ -0,0 +1,86 @@ +/* # Overrides */ + +header { + position: relative; + border-bottom: none; +} + +/* # Sections */ + +/* ## Header */ + +section.header { + top: 0; + width: 100%; + z-index: 100; + display: flex; + color: white; + position: sticky; + overflow: hidden; + grid-area: header; + align-items: stretch; + height: calc(var(--running-size) - var(--padding)); + grid-template-rows: var(--running-size); + background-color: var(--color-accent); + box-shadow: + 0 2px 0 0 white, + 20svw 0 0 0 var(--color-accent), + -20svw 0 0 0 var(--color-accent) + ; +} + +/* ### Nav */ + +section.header nav { + display: flex; + align-items: center; + padding: var(--padding); + justify-content: baseline; +} + +section.header nav:last-of-type { + justify-content: end; + gap: calc(var(--padding) / 2); +} + +/* ### Spacer */ + +section.header nav > div { + width: 2px; + height: 80%; + margin: 0 var(--padding); + background-color: rgba(0, 0, 0, .07); +} + +/* ### Buttons */ + +section.header button.inline:not(.solid):hover, +section.header button.inline { + fill: white; + color: white; +} + +section.header button.inline.solid { + color: var(--color-accent); + background-color: white; +} + +/* ## Menu */ + +section.header button.menu { + display: none; +} + +/* # Size queries */ + +@media (max-width: 950px) { + section.header > *:not(button.menu) { + display: none; + } + + section.header button.menu { + width: 100%; + justify-content: center; + display: flex; + } +} \ No newline at end of file diff --git a/public/assets/css/pages/docs/layout.css b/public/assets/css/pages/docs/layout.css new file mode 100644 index 0000000..a3cd3cb --- /dev/null +++ b/public/assets/css/pages/docs/layout.css @@ -0,0 +1,89 @@ +vv-shell { + display: grid; + grid-template-rows: calc(var(--running-size) - var(--padding)) 1fr var(--running-size); + grid-template-areas: + "header header" + "aside main" + "footer footer" + ; + grid-template-columns: 300px 1fr; +} + +/* # Main */ + +main { + --primer-color-accent: 0, 0, 0; + --color-accent: black; + + gap: var(--padding); + display: flex; + padding: var(--padding); + grid-area: main; + font-family: sans-serif; + flex-direction: column; +} + +main code { + color: white; + padding: 0 5px; + font-weight: normal; + font-family: monospace; + border-radius: 6px; + background-color: #212121; +} + +main h2 { + font-size: 1.5em; +} + +main h3 { + font-size: 1em; + margin-bottom: 5px; +} + +/* # Sections */ + +section.md { + gap: 5px; + display: flex; + align-items: baseline; + flex-direction: column; +} + +section.md :is(ol, ul) li { + margin: calc(var(--padding) / 2) 0; +} + +/* # Size queries */ + +@media (max-width: 950px) { + vv-shell { + grid-template-rows: calc(var(--running-size) - var(--padding)) 1fr var(--running-size); + grid-template-areas: + "header" + "main" + "footer" + ; + grid-template-columns: 100svw; + } + + aside { + display: none; + } + + vv-shell.menu-open { + grid-template-areas: + "header" + "aside" + "footer" + ; + } + + vv-shell.menu-open aside { + display: initial; + } + + vv-shell.menu-open main { + display: none; + } +} \ No newline at end of file diff --git a/public/assets/css/pages/error.css b/public/assets/css/pages/error.css new file mode 100644 index 0000000..0497f60 --- /dev/null +++ b/public/assets/css/pages/error.css @@ -0,0 +1,4 @@ +vv-shell { + margin: auto; + text-align: center; +} \ No newline at end of file diff --git a/public/assets/css/pages/examples.css b/public/assets/css/pages/examples.css new file mode 100644 index 0000000..01e6438 --- /dev/null +++ b/public/assets/css/pages/examples.css @@ -0,0 +1,56 @@ +vv-shell { + gap: var(--padding); + padding: var(--padding); +} + +/* # Sections */ + +/* ## Heading */ + +section.heading { + text-align: center; +} + +/* ## Grid */ + +section.grid { + gap: var(--padding); + display: grid; + grid-template-columns: repeat(3, 1fr); +} + +section.grid button { + width: 100%; + flex-direction: column; + justify-content: space-between; +} + +section.grid button img { + width: 100%; + border-radius: 6px; +} + +section.grid button > div { + display: flex; + text-align: right; + gap: var(--padding); + align-items: center; +} + +section.grid button p { + color: black; +} + +/* # Size queries */ + +@media (max-width: 1000px) { + section.grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 550px) { + section.grid { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/public/assets/css/pages/features.css b/public/assets/css/pages/features.css new file mode 100644 index 0000000..ae1da35 --- /dev/null +++ b/public/assets/css/pages/features.css @@ -0,0 +1,32 @@ +vv-shell { + padding: 0 var(--padding); +} + +/* # Section */ + +/* ## This stays */ + +section#this-stays { + display: flex; + align-items: center; + text-align: center; + fill: var(--color-accent); + justify-content: space-evenly; + height: var(--running-size); +} + +section#this-stays svg { + height: 70%; +} + +section#this-stays svg:last-child { + transform: rotateY(180deg); +} + +/* # Size queries */ + +@media (max-width: 950px) { + section#this-stays { + height: calc(var(--running-size) * 2); + } +} \ No newline at end of file diff --git a/public/assets/css/pages/index.css b/public/assets/css/pages/index.css index 2a189f5..ae129ec 100644 --- a/public/assets/css/pages/index.css +++ b/public/assets/css/pages/index.css @@ -1,188 +1,76 @@ -:root { - --wavelength: 20vw; +vv-shell { + overflow-x: hidden; + padding: 0 var(--padding); } -body { - background-color: var(--color-deep); -} +/* # Components */ -section h2 { - color: white; - background-color: black; -} - -header.transparent { - color: white; - background-color: transparent; - border-color: rgba(255, 255, 255, .1); -} - -header.transparent .logo { - fill: var(--color-deep); -} - -header.transparent button { - fill: white; -} - -header.transparent button.solid { - fill: var(--color-deep); - color: var(--color-deep); - background-color: white; +code-demo { + width: 100%; + max-width: 700px; } /* # Sections */ -/* ## Divider */ - -section.divider { - width: 100%; - overflow: hidden; - line-height: 0; - background-color: white; -} - -section.divider svg { - position: relative; - display: block; - width: calc(148% + 1.3px); - height: 79px; -} - -section.divider .shape-fill { - fill: var(--color-deep); -} - /* ## Intro */ section#intro { - display: grid; - color: white; - min-height: 300px; + min-height: min(50svh, 1000px); } -section#intro h1 { +section#intro .text h1 { font-size: 50px; + line-height: 50px; } -section#intro div { - display: flex; - flex-direction: column; - justify-content: center; - align-items: baseline; +/* ### Compass */ + +section#intro div.compass { + align-self: center; } -/* ### Waves */ +section#intro div.compass svg { + --size: 50svh; -section.waves { - --easing: .2; - - position: relative; - height: 300px; - user-select: none; - pointer-events: none; + width: var(--size); + height: var(--size); + position: absolute; z-index: -1; } -section.waves img { - margin: auto; - margin-top: -14%; - width: 50%; - transform-origin: 50% 100%; - animation: ship 6s alternate infinite ease; +section#intro div.compass svg.points { + opacity: .2; + animation: spin 10s alternate infinite linear; } -@keyframes ship { - 0% { - transform: translate(0, -7px) rotate(-7deg); - } - - 100% { - transform: translate(5px, 10px) rotate(4deg); - } +@keyframes spin { + to { transform: rotate(30deg); } } -section.waves .wave { - position: absolute; - width: 100%; - height: 100%; - transform: scale(1.5); - bottom: 70px; - animation: wave 7s alternate infinite cubic-bezier(var(--easing), 0, calc(1 - var(--easing)), 1); +section#intro div.compass svg:nth-child(2) { + --size: 60svh; + + animation-duration: 15s; + animation-direction: alternate-reverse; } -@keyframes wave { - to { transform: scale(1.5) translateX(100px); } -} +/* ## Assets */ -section.waves + section { - background-color: #4ca6ff; -} +/* ## Freedom */ -section.waves .wave:first-child { - background-image: url("/assets/media/waves/0.svg"); -} - -section.waves .wave:last-child { - animation-duration: 5s; - background-image: url("/assets/media/waves/1.svg"); -} - -/* ## Softnav */ - -section#softnav { - color: white; - background: linear-gradient(0deg, rgba(0,128,255,1) 0%, rgba(76,166,255,1) 100%); -} - -/* ## BYOE */ - -section.info { - background-color: white; -} - -section.info container { - min-height: 400px; -} - -section.info svg { - justify-self: center; - width: 400px; -} - -/* ## Lead */ - -section#lead h1 { - color: white; - text-align: center; - font-weight: normal; -} - -/* ## Free */ - -section#free { - box-shadow: inset 0 0 20px 20px white, inset 0 0 140px 20px white; - background-color: rgba(255, 255, 255, .9); - background-blend-mode: screen; - background-image: url("/assets/media/gnu.png"); +section#freedom > div > svg { + height: 300px; } /* # Size queries */ @media (max-width: 950px) { - section.waves { - display: none; + section#intro { + min-height: min(40svh, 1000px); } - section.info container { - min-height: unset; - } - - section.info svg { - width: 300px; - } - - section#lead h1 { - font-size: 20px; + section#intro div.compass { + opacity: .3; + z-index: -1; } } \ No newline at end of file diff --git a/public/assets/css/pages/why.css b/public/assets/css/pages/why.css deleted file mode 100644 index d2fded6..0000000 --- a/public/assets/css/pages/why.css +++ /dev/null @@ -1,15 +0,0 @@ -/* # Sections */ - -/* ## Free */ - -section#freedom { - background-position: 50% 50%; - background-size: 400px; - background-color: var(--color-deep); - background-blend-mode: lighten; - background-image: url("/assets/media/gnu.png"); -} - -section#freedom svg { - filter: drop-shadow(0 0 40px rgba(255, 255, 255, .3)); -} \ No newline at end of file diff --git a/public/assets/css/shell.css b/public/assets/css/shell.css new file mode 100644 index 0000000..2993f92 --- /dev/null +++ b/public/assets/css/shell.css @@ -0,0 +1,384 @@ +:root { + --primer-color-accent: 0, 128, 255; + --color-accent: rgb(var(--primer-color-accent)); + + --padding: 20px; + --running-size: 80px; +} + +/* # Cornerstones */ + +* { + margin: 0; + fill: inherit; + box-sizing: border-box; + font-family: inherit; + color: inherit; + font-size: inherit; +} + +::-webkit-scrollbar { + display: none; +} + +body { + display: grid; + justify-items: center; + grid-template-rows: var(--running-size) 1fr var(--running-size); + overscroll-behavior: none; + background-color: white; + color: black; + overflow-x: hidden; + min-height: 100svh; + font-size: 15px; + font-family: "Roboto Mono", sans-serif; +} + +body::before { + transition: 1s opacity; + content: ""; + position: absolute; + top: -5%; + left: 0; + width: 20%; + height: 5%; + border-radius: 100%; + z-index: 1000; + box-shadow: + 0 0 30svh 10svh rgba(var(--primer-color-accent), .1), + 0 0 30svh 60svh rgba(var(--primer-color-accent), .05), + 0 0 30svh 150svh rgba(var(--primer-color-accent), .02) + ; + opacity: 0; +} + +/* "enable" the corner glow effect on initial load when a page has been fully loaded */ +body[vv-top-page]::before { + opacity: 1; +} + +a { + display: contents; + color: inherit; + text-decoration: none; +} + +/* ## vv-shell */ + +vv-shell { + width: 100svw; + display: flex; + max-width: 1500px; + position: relative; + flex-direction: column; +} + +/* # Components */ + +:is(h1, h2, h3, p, li) > a { + --underline-tickness: 3px; + + display: initial; + text-decoration: underline; + text-decoration-thickness: var(--underline-tickness); + text-underline-offset: var(--underline-tickness); + text-decoration-color: var(--color-accent); +} + +h1 { + font-size: 30px; + color: var(--color-accent); +} + +h2 { + font-size: 30px; +} + +h3 { + font-size: 25px; +} + +/* ## Page transition */ + +[vv-loading] * { + transition: 200ms opacity; +} + +[vv-loading="true"] * { + opacity: 0; + pointer-events: none; +} + +[vv-loading="true"]::after { + content: ""; + position: fixed; + top: 50%; + left: 50%; + width: 45px; + height: 49px; + background-size: contain; + image-rendering: pixelated; + transform: translate(-50%, -50%); + background-image: url("/assets/media/spinner.gif"); + -webkit-filter: hue-rotate(var(--hue-accent)); + filter: hue-rotate(var(--hue-accent)); +} + +/* ## Buttons */ + +button { + border: none; + background-color: transparent; + color: inherit; + fill: inherit; + cursor: pointer; +} + +button * { + pointer-events: none; +} + +/* ### Inline */ + +button.inline { + gap: 10px; + display: flex; + border-radius: 7px; + align-items: center; + fill: var(--color-accent); + color: var(--color-accent); + padding: calc(var(--padding) / 1.5); + background: linear-gradient(139deg, rgba(0, 0, 0, 0) 0%, rgba(var(--primer-color-accent), .1) 100%); +} + +button.inline:not(.solid, .sly) { + box-shadow: + 0 0 0 2px rgba(var(--primer-color-accent), .1), + 10px 7px 40px 3px rgba(var(--primer-color-accent), .06) + ; +} + +button.inline svg { + flex: none; + height: 1em; +} + +button.inline svg:last-child { + width: 1.5em; + margin-left: auto; +} + +button.inline svg.chevron:last-child { + transform: rotate(-90deg); +} + +/* #### Solid */ + +button.inline.solid { + fill: white; + color: white; + border-color: var(--color-accent); + background-color: var(--color-accent); + border: solid 2px rgba(var(--primer-color-accent), 1); +} + +/* #### Sly */ + +button.sly { + border-color: transparent; + background: transparent; + box-shadow: none; +} + +button.sly > svg.chevron { + transition: 200ms width; + width: 0; +} + +button.sly:hover > svg.chevron { + width: 1.5em; +} + +/* ## Header */ + +header { + --border-style: solid 1px rgba(0, 0, 0, .07); + + top: 0; + width: 100%; + z-index: 100; + display: grid; + position: sticky; + overflow: hidden; + align-items: stretch; + backdrop-filter: blur(20px); + height: var(--running-size); + border-bottom: var(--border-style); + -webkit-backdrop-filter: blur(20px); + grid-template-rows: var(--running-size); + background-color: rgba(255, 255, 255, .8); + grid-template-columns: var(--running-size) repeat(2, 1fr); +} + +/* ### Nav */ + +header nav { + display: flex; + align-items: center; + padding: var(--padding); + justify-content: baseline; +} + +header nav:last-of-type { + justify-content: end; + gap: calc(var(--padding) / 2); +} + +:is(header, footer) nav.m { + display: none; +} + +/* ### Spacer */ + +header nav > div { + width: 2px; + height: 80%; + margin: 0 var(--padding); + background-color: rgba(0, 0, 0, .07); +} + +/* ### Buttons */ + +header button { + --icon-size: 25px; + + display: grid; + border-left: var(--border-style); + grid-template-columns: 1fr; + align-items: center; + justify-items: center; + padding: var(--padding); + gap: var(--padding); + fill: var(--color-accent); + font-size: 13px; + color: rgba(255, 255, 255, .5); + cursor: pointer; +} + +header button:not(.logo) svg { + width: var(--icon-size); +} + +header button.search p { + display: none; +} + +/* ## Footer */ + +footer { + width: 100%; + display: grid; + color: white; + position: sticky; + overflow: hidden; + align-items: stretch; + height: var(--running-size); + grid-template-rows: var(--running-size); + background-color: var(--color-accent); + grid-template-columns: repeat(2, 1fr); +} + +/* ### Nav */ + +footer nav { + display: flex; + align-items: center; + padding: var(--padding); + justify-content: baseline; +} + +footer nav:last-of-type { + justify-content: end; + gap: calc(var(--padding) / 2); +} + +/* ### Spacer */ + +footer nav > div { + width: 2px; + height: 80%; + margin: 0 var(--padding); + background-color: rgba(0, 0, 0, .07); +} + +/* ### Buttons */ + +footer button.inline:not(.solid):hover, +footer button.inline { + fill: white; + color: white; +} + +footer button.inline.solid { + color: var(--color-accent); + background-color: white; +} + +/* # Feature queries */ + +@media (hover: hover) { + :is(h1, h2, h3, p, li) > a:hover { + text-underline-offset: 1px; + text-decoration-thickness: calc(var(--underline-tickness) * 2); + color: var(--color-accent); + } + + /* # Components */ + + button.inline { + transition-duration: 300ms; + transition-property: background-color, border-color, box-shadow, color, fill; + } + + button:hover { + border-color: rgba(255, 255, 255, .2); + background-color: rgba(255, 255, 255, .1); + } + + button.inline:hover { + fill: var(--color-accent); + color: var(--color-accent); + } + + button.inline:not(.solid):hover { + box-shadow: + 0 0 0 2px rgba(var(--primer-color-accent), 1), + 10px 7px 30px 3px rgba(var(--primer-color-accent), .07) + ; + } + + button.solid:hover { + border-color: rgba(var(--primer-color-accent), .2); + background-color: rgba(var(--primer-color-accent), .2); + box-shadow: 0 -10px 20px 10px rgba(var(--primer-color-accent), .05); + } +} + +/* # Size queries */ + +@media (max-width: 950px) { + footer, + header { + grid-template-columns: var(--running-size) 1fr; + } + + :is(header, footer) nav.m { + display: flex; + padding-left: calc(var(--padding) / 2); + justify-content: space-between; + } + + :is(header, footer) nav:not(.m) { + display: none; + } +} \ No newline at end of file diff --git a/public/assets/css/shells/docs.css b/public/assets/css/shells/docs.css deleted file mode 100644 index 7573160..0000000 --- a/public/assets/css/shells/docs.css +++ /dev/null @@ -1,274 +0,0 @@ -body { - background-color: rgba(var(--primer-color-deep), .01); -} - -[vv-shell-id="/"] { - display: grid; - min-height: calc(100svh - var(--running-size) - var(--border-style-width)); - grid-template-areas: - "aside main" - "contribute contribute" - ; - grid-template-columns: 400px 1fr; - grid-template-rows: 1fr 200px; - gap: calc(var(--padding) * 2); - margin: auto; -} - -[vv-shell-id="6ccb0465"] { - grid-area: main; - display: flex; - flex-direction: column; - gap: calc(var(--padding) * 2); - margin-top: calc(var(--padding) * 2); - padding-right: calc(var(--padding) * 2); -} - -hr { - border: unset; - border-top: var(--border-style); -} - -/* # Aside */ - -aside { - grid-area: aside; - height: 100%; - display: flex; - flex-direction: column; - padding: var(--padding) 0; - padding-left: calc(var(--padding) * 2); - border-right: var(--border-style); -} - -aside button { - width: calc(100% - (var(--padding) * 2)); - text-align: left; -} - -aside hr { - margin: calc(var(--padding) * 2) 0; -} - -aside ul { - list-style: none; - padding-left: 0; -} - -aside ul ul { - padding-left: var(--padding); -} - -aside ul > p { - margin: var(--padding) 0; -} - -/* ---- */ - -aside .cc + ul { - display: none; -} - -aside .cc.php button { - background-color: rgba(122, 134, 184, .2); -} - -aside .cc.js button { - background-color: rgba(240, 219, 79, .3); -} - -[vv-page^="/docs/API/PHP"] aside .cc.php + ul, -[vv-page^="/docs/API/JS"] aside .cc.js + ul { - display: initial; -} - -/* # Collapsible */ - -details { - border: 1px solid #aaa; - border-radius: 4px; - padding: 0.5em 0.5em 0; -} - -summary { - margin: -0.5em -0.5em 0; - padding: 0.5em; - cursor: pointer; -} - -details[open] { - width: 100%; - padding: 0.5em; -} - -details[open] summary { - border-bottom: 1px solid #aaa; - margin-bottom: 0.5em; -} - -/* # Sections */ - -/* ## Inset */ - -section.inset { - padding-left: var(--padding); -} - -/* ## Markdown */ - -section.md container { - padding-top: 0; - flex-direction: column; - align-items: baseline; -} - -section.md :is(h1, h2, h3) { - cursor: pointer; -} - -section.md h1::before { - content: "#"; - opacity: 1; - padding: 0 10px; - margin-right: .5em; - color: var(--color-light); - background-color: var(--color-deep); -} - -section.md h2::before { - content: "#"; - opacity: 1; - margin-right: .5em; - color: var(--color-deep); -} - -/* ## Code inline */ - -:is(h1, h2, h3, a, p, quote) > code { - padding: 5px; - border-radius: 6px; - white-space: nowrap; - font-family: 'Courier New', monospace; - background-color: rgba(0, 0, 0, .05); -} - -code.tag::before { - content: "<"; -} - -code.tag::after { - content: ">"; -} - -/* ## Code block */ - -section.md pre { - width: 100%; - max-width: calc(100svw - (var(--padding) * 4)); - tab-size: 3; - overflow: scroll; -} - -section.md pre code { - --copy-size: 37px; - --copy-inset: 5px; - --copy-border-size: 1px; - - overflow: scroll; - position: relative; - padding-right: calc(var(--copy-size) + (var(--copy-inset) * 2) + var(--padding)); - border-radius: 6px; -} - -section.md pre code::after { - content: "📋"; - display: grid; - font-size: 20px; - cursor: pointer; - position: absolute; - border-radius: 4px; - align-items: center; - justify-items: center; - top: var(--copy-inset); - width: var(--copy-size); - right: var(--copy-inset); - height: var(--copy-size); - border: solid 1px rgba(255, 255, 255, .1); - background-color: rgba(255, 255, 255, .1); -} - -@media (hover: hover) { - section.md h1:hover::before { - background-color: black; - } - - section.md :is(h1, h2, h3):hover::after { - content: " <- click to copy link"; - font-size: .5em; - opacity: .5; - } - - section.md pre code:hover::after { - border: solid 1px rgba(255, 255, 255, .3); - background-color: rgba(255, 255, 255, .2); - } -} - -/* ## Menu */ - -section.menu { - display: none; - fill: white; - color: white; - grid-area: menu; - cursor: pointer; - background-color: rgba(var(--primer-color-deep), .8); -} - -section.menu container svg { - width: 1em; -} - -section.menu p::before { - content: "Open "; -} - -/* # Size queries */ - -@media (max-width: 950px) { - [vv-shell-id="/"] { - grid-template-areas: - "menu" - "main" - "contribute" - ; - grid-template-columns: 1fr; - grid-template-rows: var(--running-size) 1fr 300px; - } - - body.docsMenuOpen [vv-shell-id="/"] { - grid-template-areas: - "menu" - "aside" - ; - grid-template-rows: var(--running-size) 1fr; - } - - body.docsMenuOpen [vv-shell-id="6ccb0465"], - body.docsMenuOpen section.contribute, - body:not(.docsMenuOpen) aside { - display: none; - } - - /* ---- */ - - [vv-shell-id="6ccb0465"] { - margin-top: unset; - } - - /* ---- */ - - section.menu { - display: initial; - } -} \ No newline at end of file diff --git a/public/assets/css/snippets/HTMLCodeDemoElement.css b/public/assets/css/snippets/HTMLCodeDemoElement.css new file mode 100644 index 0000000..225e269 --- /dev/null +++ b/public/assets/css/snippets/HTMLCodeDemoElement.css @@ -0,0 +1,113 @@ +code-demo { + --primer-color-base: 31, 31, 31; + --color-base: rgb(var(--primer-color-base)); + --height: calc(var(--padding) * 2.5); + + display: block; + min-width: 700px; + border-radius: 12px; + font-family: monospace; + background-color: var(--color-base); +} + +/* # Header */ + +code-demo .header { + display: flex; + overflow-x: scroll; + height: var(--height); + border-bottom: solid 1px rgba(255, 255, 255, .1); +} + +code-demo .header button.inline { + border: solid 1px rgba(255, 255, 255, .1); + border-bottom: unset; + border-radius: unset; + box-shadow: unset; +} + +code-demo .header button.inline:hover { + box-shadow: unset; +} + +code-demo .header button:first-child { + margin-left: var(--height); +} + +code-demo .header button.inline + button.inline { + border-left: unset; +} + +/* ## Active */ + +code-demo .header button { + --primer-color-accent: 255, 255, 255; + --color-accent: rgb(var(--primer-color-accent)); +} + +code-demo .header button.active { + border-top: solid 4px var(--color-accent); + pointer-events: none; +} + +/* ## Languages */ + +code-demo .header button[data-lang="js"] { + --primer-color-accent: 241, 224, 90; + --color-accent: rgb(var(--primer-color-accent)); +} + +code-demo .header button[data-lang="css"] { + --primer-color-accent: 81, 154, 186; + --color-accent: rgb(var(--primer-color-accent)); +} + +code-demo .header button[data-lang="php"] { + --primer-color-accent: 160, 116, 196; + --color-accent: rgb(var(--primer-color-accent)); +} + +code-demo .header button[data-lang="html"] { + --primer-color-accent: 221, 120, 49; + --color-accent: rgb(var(--primer-color-accent)); +} + +/* # Body */ + +code-demo .body { + overflow: scroll; + padding: var(--padding); +} + +code-demo .body .view-line { + white-space: pre; +} + +/* ## Tabs */ + +code-demo .body [data-file] { + display: none; +} + +code-demo .body [data-file].active { + display: initial; +} + +code-demo .body a { + display: inline; + text-decoration: underline; + text-decoration-color: white; +} + +code-demo .body a:hover { + text-decoration-thickness: 2px; +} + +/* # Size queries */ + +@media (max-width: 950px) { + code-demo { + width: 100%; + min-width: unset; + } +} \ No newline at end of file diff --git a/public/assets/css/snippets/HTMLNavMenuElement.css b/public/assets/css/snippets/HTMLNavMenuElement.css new file mode 100644 index 0000000..428a8b2 --- /dev/null +++ b/public/assets/css/snippets/HTMLNavMenuElement.css @@ -0,0 +1,61 @@ +nav-menu { + display: none; +} + +@media (max-width: 950px) { + /* # Overrides */ + + body.menu-open { + overflow: hidden; + } + + /* ## Header */ + + body.menu-open header { + background-color: var(--color-accent); + } + + body.menu-open header nav p { + color: white; + } + + /* # Nav menu */ + + nav-menu { + top: var(--running-size); + left: 0; + width: 100%; + overflow-y: scroll; + height: calc(100svh - var(--running-size)); + display: none; + position: fixed; + align-items: center; + flex-direction: column; + background-color: white; + } + + nav-menu.active { + display: flex; + } + + /* ## Sections */ + + nav-menu nav { + gap: calc(var(--padding) / 2); + width: 100%; + max-width: 600px; + display: flex; + padding: var(--padding); + flex-direction: column; + } + + nav-menu nav:last-child { + margin-top: auto; + } + + nav-menu nav.horizontal { + gap: var(--padding); + flex-direction: row; + justify-content: center; + } +} \ No newline at end of file diff --git a/public/assets/css/snippets/split.css b/public/assets/css/snippets/split.css new file mode 100644 index 0000000..d69d691 --- /dev/null +++ b/public/assets/css/snippets/split.css @@ -0,0 +1,71 @@ +/* # Split */ + +section.split { + display: grid; + grid-template-columns: repeat(2, 1fr); + margin: 10svh 0; +} + +section.split.center { + justify-items: center; +} + +section.split > div { + grid-row: 1; + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; +} + +section.split.reverse > div:last-child { + grid-column: 1; +} + +section.split.reverse > div:first-child { + grid-column: 2; +} + +/* ## Text */ + +section.split .text { + width: 70%; + display: flex; + align-items: baseline; + flex-direction: column; +} + +section.split.reverse .text { + align-items: end; + justify-self: end; + text-align: right; +} + +/* ## Buttons */ + +section.split .buttons { + display: flex; + gap: var(--padding); + margin-top: var(--padding); +} + +/* # Size queries */ + +@media (max-width: 950px) { + section.split { + display: flex; + margin: 5svh 0; + gap: var(--padding); + flex-direction: column; + } + + section.split .text { + width: 100%; + } + + section.split .buttons { + width: 100%; + flex-direction: column; + gap: calc(var(--padding) / 2); + } +} \ No newline at end of file diff --git a/public/assets/css/syntax.css b/public/assets/css/syntax.css new file mode 100644 index 0000000..90e8d50 --- /dev/null +++ b/public/assets/css/syntax.css @@ -0,0 +1,27 @@ +/* # Syntax highliting */ + +.mtk1 { color: #cccccc; } +.mtk2 { color: #1f1f1f; } +.mtk3 { color: #d4d4d4; } +.mtk4 { color: #000080; } +.mtk5 { color: #6a9955; } +.mtk6 { color: #569cd6; } +.mtk7 { color: #b5cea8; } +.mtk8 { color: #646695; } +.mtk9 { color: #d7ba7d; } +.mtk10 { color: #9cdcfe; } +.mtk11 { color: #f44747; } +.mtk12 { color: #ce9178; } +.mtk13 { color: #6796e6; } +.mtk14 { color: #808080; } +.mtk15 { color: #d16969; } +.mtk16 { color: #dcdcaa; } +.mtk17 { color: #4ec9b0; } +.mtk18 { color: #c586c0; } +.mtk19 { color: #4fc1ff; } +.mtk20 { color: #c8c8c8; } +.mtk21 { color: #cd9731; } +.mtk22 { color: #b267e6; } +.mtki { font-style: italic; } +.mtkb { font-weight: bold; } +.mtks { text-decoration: line-through; } \ No newline at end of file diff --git a/public/assets/fonts/roboto-mono.woff2 b/public/assets/fonts/roboto-mono.woff2 new file mode 100644 index 0000000..26e996b Binary files /dev/null and b/public/assets/fonts/roboto-mono.woff2 differ diff --git a/public/assets/js/CustomElement.mjs b/public/assets/js/CustomElement.mjs new file mode 100644 index 0000000..456774b --- /dev/null +++ b/public/assets/js/CustomElement.mjs @@ -0,0 +1,45 @@ +const PUBLIC_ELEMENT_STYLESHEET_DIR = "/assets/css/snippets/"; + +export class CustomElement extends HTMLElement { + constructor() { + super(); + } + + /** + * Return a pathname to a custom element CSS stylesheet + * @param {String} stylesheet + * @returns {String} + */ + static #getElementStylesheetHref(stylesheet) { + return `${PUBLIC_ELEMENT_STYLESHEET_DIR}${stylesheet}.css`; + } + + /** + * Include a stylesheet for a custom element + * @param {String} stylesheet + */ + importElementStylesheet(stylesheet) { + if (document.head.querySelector(`link[href="${CustomElement.#getElementStylesheetHref(stylesheet)}"]`)) { + return; + } + + const element = document.createElement("link"); + element.href = CustomElement.#getElementStylesheetHref(stylesheet); + element.rel = "stylesheet"; + + document.head.appendChild(element); + } + + connectedCallback() { + if ("connected" in this) { + this.connected(); + } + } + + disconnectedCallback() { + if ("disconnected" in this) { + this.disconnected(); + } + } + +} \ No newline at end of file diff --git a/public/assets/js/pages/docs/layout.js b/public/assets/js/pages/docs/layout.js new file mode 100644 index 0000000..6a1960d --- /dev/null +++ b/public/assets/js/pages/docs/layout.js @@ -0,0 +1,9 @@ +// Toggle documentation menu with CSS when button in sub-header is clicked +document.querySelector("section.header button.menu").addEventListener("click", () => { + vegvisir.Navigation.shellElement.classList.toggle("menu-open"); +}); + +// Close documentation menu when shell is being navigated +vegvisir.Navigation.shellElement.addEventListener(vegvisir.Navigation.EVENTS.STARTED, () => { + vegvisir.Navigation.shellElement.classList.remove("menu-open"); +}); \ No newline at end of file diff --git a/public/assets/js/shell.js b/public/assets/js/shell.js new file mode 100644 index 0000000..f84c4a7 --- /dev/null +++ b/public/assets/js/shell.js @@ -0,0 +1,9 @@ +import { TAG_NAME } from "/assets/js/snippets/HTMLNavMenuElement.mjs"; + +// Bind toggles for the nav menu +[...document.querySelectorAll("[data-menu]")].forEach(element => { + element.addEventListener("click", () => document.querySelector(TAG_NAME).toggle()); +}); + +// Scroll page to the top on navigations +document.addEventListener(vegvisir.Navigation.EVENTS.FINISHED, () => window.scrollTo({ top: 0 })); \ No newline at end of file diff --git a/public/assets/js/shells/docs.js b/public/assets/js/shells/docs.js deleted file mode 100644 index c5dd70b..0000000 --- a/public/assets/js/shells/docs.js +++ /dev/null @@ -1,9 +0,0 @@ -// Handle docs menu open/close -{ - const CLASSNAME_DOCS_MENU_OPEN = "docsMenuOpen"; - - // Toggle docs menu on button click - document.querySelector("section.menu").addEventListener("click", () => document.body.classList.toggle(CLASSNAME_DOCS_MENU_OPEN)); - // Hide docs menu on navigation - document.addEventListener(vegvisir.Navigation.EVENTS.STARTED, () => document.body.classList.remove(CLASSNAME_DOCS_MENU_OPEN)); -} \ No newline at end of file diff --git a/public/assets/js/shells/document.js b/public/assets/js/shells/document.js deleted file mode 100644 index 27bdc5f..0000000 --- a/public/assets/js/shells/document.js +++ /dev/null @@ -1,9 +0,0 @@ -// Handle global menu open/close events -{ - const CLASSNAME_MENU_OPEN = "menuOpen"; - - // Toggle menu on menu button click - document.querySelector("header .menuToggle").addEventListener("click", () => document.body.classList.toggle(CLASSNAME_MENU_OPEN)); - // Close menu on navigation - document.addEventListener(vegvisir.Navigation.EVENTS.STARTED, () => document.body.classList.remove(CLASSNAME_MENU_OPEN)); -} \ No newline at end of file diff --git a/public/assets/js/snippets/HTMLCodeDemoElement.mjs b/public/assets/js/snippets/HTMLCodeDemoElement.mjs new file mode 100644 index 0000000..d8305ec --- /dev/null +++ b/public/assets/js/snippets/HTMLCodeDemoElement.mjs @@ -0,0 +1,40 @@ +import { CustomElement } from "../CustomElement.mjs"; + +export const TAG_NAME = "code-demo"; + +const SELECTOR_HEADER_BUTTON = ".header button"; + +class HTMLCodeDemoElement extends CustomElement { + constructor() { + super(); + + this.importElementStylesheet(this.constructor.name); + } + + /** + * Set a tab as active by passing an HTMLElement with a data-lang attribute + * @param {HTMLElement} target + */ + #setActiveTab(target) { + [...this.querySelectorAll("[data-file]")].forEach(element => { + element.classList.remove("active"); + + // Set active if current element lang is target lang + if (element.dataset.file === target.dataset.file) { + element.classList.add("active"); + } + }); + } + + connected() { + // Bind event listeners for language tabs + [...this.querySelectorAll(SELECTOR_HEADER_BUTTON)].forEach(element => { + element.addEventListener("click", (event) => this.#setActiveTab(event.target.closest(SELECTOR_HEADER_BUTTON))) + }); + + // Make the first tab active on load + this.#setActiveTab(this.querySelector(SELECTOR_HEADER_BUTTON)); + } +} + +globalThis.customElements.define(TAG_NAME, HTMLCodeDemoElement); \ No newline at end of file diff --git a/public/assets/js/snippets/HTMLNavMenuElement.mjs b/public/assets/js/snippets/HTMLNavMenuElement.mjs new file mode 100644 index 0000000..61b6eb2 --- /dev/null +++ b/public/assets/js/snippets/HTMLNavMenuElement.mjs @@ -0,0 +1,36 @@ +import { CustomElement } from "../CustomElement.mjs"; + +export const TAG_NAME = "nav-menu"; + +class HTMLNavMenuElement extends CustomElement { + constructor() { + super(); + + this.importElementStylesheet(this.constructor.name); + } + + open() { + document.body.classList.add("menu-open"); + this.classList.add("active"); + } + + close() { + this.classList.remove("active"); + + // Remove classname from body tag if this was the last menu that was open + if (!document.querySelector(TAG_NAME + ".active")) { + document.body.classList.remove("menu-open"); + } + } + + toggle() { + this.classList.contains("active") ? this.close() : this.open(); + } + + connected() { + // Close menu when a link is clicked + [...document.querySelectorAll("a")].forEach(element => element.addEventListener("click", () => this.close())); + } +} + +globalThis.customElements.define(TAG_NAME, HTMLNavMenuElement); \ No newline at end of file diff --git a/public/assets/media/arrow.svg b/public/assets/media/arrow.svg new file mode 100644 index 0000000..3fd37f2 --- /dev/null +++ b/public/assets/media/arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/compass-points.svg b/public/assets/media/compass-points.svg new file mode 100644 index 0000000..e97dcf2 --- /dev/null +++ b/public/assets/media/compass-points.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/compass.svg b/public/assets/media/compass.svg new file mode 100644 index 0000000..4a7390f --- /dev/null +++ b/public/assets/media/compass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/icons/chevron.svg b/public/assets/media/icons/chevron.svg new file mode 100644 index 0000000..5f067d3 --- /dev/null +++ b/public/assets/media/icons/chevron.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/icons/hamburger.svg b/public/assets/media/icons/hamburger.svg new file mode 100644 index 0000000..bfa139a --- /dev/null +++ b/public/assets/media/icons/hamburger.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/icons/languages/css.svg b/public/assets/media/icons/languages/css.svg new file mode 100644 index 0000000..b19f6e1 --- /dev/null +++ b/public/assets/media/icons/languages/css.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/icons/languages/html.svg b/public/assets/media/icons/languages/html.svg new file mode 100644 index 0000000..b1b23b5 --- /dev/null +++ b/public/assets/media/icons/languages/html.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/icons/languages/js.svg b/public/assets/media/icons/languages/js.svg new file mode 100644 index 0000000..70a97c9 --- /dev/null +++ b/public/assets/media/icons/languages/js.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/icons/languages/php.svg b/public/assets/media/icons/languages/php.svg new file mode 100644 index 0000000..32c9700 --- /dev/null +++ b/public/assets/media/icons/languages/php.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/icons/languages/txt.svg b/public/assets/media/icons/languages/txt.svg new file mode 100644 index 0000000..082cfe9 --- /dev/null +++ b/public/assets/media/icons/languages/txt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/media/img/genemate-se.avif b/public/assets/media/img/genemate-se.avif new file mode 100644 index 0000000..ad2eb34 Binary files /dev/null and b/public/assets/media/img/genemate-se.avif differ diff --git a/public/assets/media/img/icellate-com.avif b/public/assets/media/img/icellate-com.avif new file mode 100644 index 0000000..67b403f Binary files /dev/null and b/public/assets/media/img/icellate-com.avif differ diff --git a/public/assets/media/img/vegvisir-website.avif b/public/assets/media/img/vegvisir-website.avif new file mode 100644 index 0000000..f6452e0 Binary files /dev/null and b/public/assets/media/img/vegvisir-website.avif differ diff --git a/public/assets/media/img/vlw-se.avif b/public/assets/media/img/vlw-se.avif new file mode 100644 index 0000000..e73bc05 Binary files /dev/null and b/public/assets/media/img/vlw-se.avif differ diff --git a/public/assets/media/logo.svg b/public/assets/media/logo.svg index 510be1a..5c52250 100644 --- a/public/assets/media/logo.svg +++ b/public/assets/media/logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/media/spinner.gif b/public/assets/media/spinner.gif new file mode 100644 index 0000000..b5975c0 Binary files /dev/null and b/public/assets/media/spinner.gif differ diff --git a/public/demos.php b/public/demos.php deleted file mode 100644 index da2e789..0000000 --- a/public/demos.php +++ /dev/null @@ -1,18 +0,0 @@ - -Sorry, this whole website is a work in progress.. this page especially so.
-(Vegvisir 3)
-vegvisir.Navigation.EVENTS
Various navigation CustomEvent
s that can be listened for.
All events will also fire on document
as a catch-all interface.
navstarted
This CustomEvent
will be fired on the navigation target
and document
when a navigation is started with .navigate()
.
navfinished
This CustomEvent
will be fired on the navigation target
and document
when a navigation with .navigate()
has finished completely.
A navigation is considered finished when the page has been fully loaded and all element attributes have been updated.
-CustomEvent.detail
propertyAccessing the .detail
property on a captured Vegvisir event will contain the following object.
target
The target
element that is used/was used for the navigation.
This example logs the target
element of all navigations on this page.
(Vegvisir 3)
-vegvisir.Navigation.MODE
Change if content should be replaced or inserted when used in .navigate()
.
REPLACE
Content of the destination URL will replace the content at vegvisir.Navigation.POSITION
.
INSERT
Content of the destination URL will append/prepend to the existing content at vegvisir.Navigation.POSITION
.
Setting the mode to INSERT
will make .navigate()
behave exactly like HTMLElement.insertAdjacentElement()
.
Position: beforebegin
= Prepend before the target
element itself.
Position: afterbegin
= Prepend just inside the target
element, before its first child.
Position: beforeend
= Append just inside the target
element, after its last child.
Position: afterend
= Append after the target
element itself.
(Vegvisir 3)
-vegvisir.Navigation.POSITION
Change where content should be placed when .navigate()
is used.
The effect of Navigation.POSITION
depend on the Navigation.MODE
used for the current navigation.
The default Navigation.POSITION
for .navigate()
is beforeend
and the default mode is replace
.
afterend
beforeend
This is the default position for .navigate()
.
afterbegin
beforebegin
(Vegvisir 3)
-vegvisir.Navigation.TARGET
Defines the target
element of a navigation triggered from a bound element.
This object follows the same syntax as the target
attribute of HTMLAnchorElement
.
If a string is provided to a target
attribute of the bound element that isn't in this enumerable, the string will be treated as a CSS selector.
These values correspond to the value of a target
attribute on a bound element.
_top
Target vegvisir.Navigation.rootShellElement
. This is the same as performing a normal soft-navigation.
This is the default behavior if a target
attribute is omitted or equals an empty string.
_self
Target the bound element itself with the defaults vegvisir.Navigation.POSITION.BEFOREEND
and vegvisir.Navigation.MODE.REPLACE
, which will replace the bound element itself with the contents of the destination URL.
The default position and mode behavior can be overridden with by setting a vv-position
and vv-mode
attribute on the bound element respectivly.
_blank
Default browser behavior. The destination URL will open in a new tab or window.
-_parent
Target the closest parent HTMLElement that has a vv-page
attribute.
vegvisir.Navigation.rootShellElement
will become the target if no parent is found.
The value of the bound element's target
attribute will be treated as a CSS selector if the string value does not equal an entry in this enumerable.
Here's an example that uses a native anchor tag to do various navigations.
- = Snippet::put("docs/API/JS/Navigation/TARGET/example-0-0", Snippet::PHP) ?> - = Snippet::put("docs/API/JS/Navigation/TARGET/example-0-1", Snippet::PHP) ?> -(Vegvisir 2, Vegvisir 3)
-Navigation.abort
Interrupt a navigation started with .navigate()
.
Navigation.abort
is an instance of AbortController which gets contructed automatically with new vegvisir.Navigation
instances.
.abort()
Call Navigation.abort.abort()
to interrupt a Vegvisir navigation in progress.
(Vegvisir 2, Vegvisir 3)
-vegvisir.Navigation.bindElements()
Trigger automatic binding of unbound tags.
-Bind event listeners for HTMLAnchorElement
tags and other tags with a vv
attribute that haven't already been bound.
This method is runned automatically after a finished Vegvisir navigation.
-In this example we will programatically create and append an anchor tag to the DOM and use this method to bind it.
- = Snippet::put("docs/API/JS/Navigation/bindElements/example-0-0", Snippet::JAVASCRIPT) ?> -(Vegvisir 2, Vegvisir 3)
-vegvisir.Navigation()
constructorThe Vegvisir navigation constructor is used to create a new instance of Navigation
. This is the first step to creating a custom navigation.
url
A URL
object or string with to a location on the same origin as the initiator.
options
An optional object containing vegvisir.Navigation.options
overrides.
Navigation
instanceA Navigation
object instance. Use the instance method .navigate()
to navigate an, or many element(s) in the DOM.
Different ways to initialize vegvisir.Navigation
with a location that will open /public/some-page.php
relative from project root.
With strings:
- = Snippet::put("docs/API/JS/Navigation/constructor/example-0-0", Snippet::JAVASCRIPT) ?> - = Snippet::put("docs/API/JS/Navigation/constructor/example-0-1", Snippet::JAVASCRIPT) ?> -With URL objects:
- = Snippet::put("docs/API/JS/Navigation/constructor/example-0-2", Snippet::JAVASCRIPT) ?> -vegvisir.Navigation
The Vegvisir Navigation
class contains APIs for triggering navigations of any element programmatically.
A new navigation can be initialized by constructing the vegvisir.Navigation
class.
(Vegvisir 2, Vegvisir 3)
-Navigation.navigate()
Perform a soft-navigation on an element.
-target
An optional instance of an HTMLElement
which will be the target of this navigation.
Vegivisr.rootShellElement
will be used if no argument is passed to this parameter.
Passing nothing to this parameter will target the top shell. This would be equivalent to clicking a link.
- = Snippet::put("docs/API/JS/Navigation/navigate/0", Snippet::JAVASCRIPT) ?> -Passing an HTMLElement
to this parameter would in this example with no other arguments changed, replace the innerHTML of the target element with the response from /some-page
.
position
This parameter takes an optional Navigation.POSITION
string which can be used to change where content from the destination URL should be placed relative to the target
element.
Passing nothing to this parameter will replace the innerHTML of target
.
Passing an position string will in this example place the contents afterEnd from target.
- = Snippet::put("docs/API/JS/Navigation/navigate/2", Snippet::JAVASCRIPT) ?> -mode
This parameter takes an optional Navigation.MODE
string which can be used to change how the contents of the destination URL should be placed relative to existing content around the target
element.
This method will not return anything, but a navigation in progress can be aborted with Navigation.abort
.
Programmatically invoke a top navigation - as if a user clicked a link.
- = Snippet::put("docs/API/JS/Navigation/navigate/0", Snippet::JAVASCRIPT) ?> -An example how a simple "click to refresh" button can be implemented.
- = Snippet::put("docs/API/JS/Navigation/navigate/example-0-0", Snippet::JAVASCRIPT) ?> -(Vegvisir 2, Vegvisir 3)
-Navigation.options
Override default Vegvisir navigation behavior.
-This object should be passed as the second argument when constructing a vegvisir.Navigation
instance.
pushHistory
This option has no default value:
-The default behavior of any Vegvisir top navigation is to push the new URL to the history stack. Ie. History API entry and browser pathname changes.
-Any navigation that is not a top navigation will not push to the history stack.
-By setting the pushHistory
option to:
true
Force all navigations with .navigate()
on this instance will push to the history stack. Including non-top navigations.
false
Force no navigations with .navigate()
on this instance will push to the history stack. Including top navigations.
Here is an example the embeds an SVG file directly on a page.
-This can come in handy for inlining small vector icons.
- = Snippet::put("docs/API/PHP/VV/embed/example-1-0", Snippet::PHP) ?> - = Snippet::put("docs/API/PHP/VV/embed/example-1-1", Snippet::PHP) ?> -By using VV::css()
inside a style
, we've enabled this stylesheet for that specific page.
Vegvisir will automatically bind HTMLAnchorElement
tags and perform soft-navigation between pages on the same origin.
The Navigation
lets you interact with, and expand Vegvisirs front-end behavior.
(Vegvisir 2, Vegvisir 3)
-VV::css()
Import and minify a CSS file.
-The syntax is identical to VV::js()
, and VV::embed()
.
VV::css()
imports and minifies a CSS styleheet file and returns it as a string.
pathname
Path to a CSS stylesheet file to import relative from project root.
-relative
Path provided to pathname
will be a relative when this parameter is true
(default). Set to false
to make path absolute.
string
A string containing minified CSS. Please note that linebreaks are preserved.
-Will return an empty string if the path provided to pathname
is not a valid CSS stylesheet file, or if it failed to import.
Let's take the following CSS stylesheet file and put it into a page.
- = Snippet::put("docs/API/PHP/VV/css/example-1-0", Snippet::CSS) ?> - = Snippet::put("docs/API/PHP/VV/css/example-1-1", Snippet::PHP) ?> -By using VV::css()
inside a style
, we've enabled this stylesheet for that specific page.
(Vegvisir 2, Vegvisir 3)
-VV::embed()
Import and inline the contents of any file without executing code.
- -VV::embed()
returns the contents of any file as a string.
pathname
Path to a file to embed relative from project root.
-relative
Path provided to pathname
will be a relative when this parameter is true
(default). Set to false
to make path absolute.
string
A string containing the raw contents of the file. File encoding is preserved.
-Will return an empty string if the path provided to pathname
is not a valid file, or if it failed to import.
Here is an example the embeds an SVG file directly on a page.
-This can come in handy for inlining small vector icons.
- = Snippet::put("docs/API/PHP/VV/embed/example-1-0", Snippet::PHP) ?> - = Snippet::put("docs/API/PHP/VV/embed/example-1-1", Snippet::PHP) ?> -By using VV::css()
inside a style
, we've enabled this stylesheet for that specific page.
(Vegvisir 2, Vegvisir 3)
-VV::include()
Inline contents of one page inside another page.
-The syntax and functionality is similar to VV::embed()
, except it executes included code.
VV::include()
lets you put the contents of one page into another page.
pathname
Path to a PHP file to import and evaluate relative from project root.
-relative
Path provided to pathname
will be a relative when this parameter is true
(default). Set to false
to make path absolute.
This method will return whatever the compiled output of the included PHP file will be.
-Consider the following page snippet
- = Snippet::put("docs/API/PHP/VV/include/example-1-0", Snippet::PHP) ?> -Let's put this snippet into another page
- = Snippet::put("docs/API/PHP/VV/include/example-1-1", Snippet::PHP) ?> -By importing the snippet with VV::include()
we have placed the banner
tag and its contents into another page.
VV
The VV
(two "V"'s, not a W) contains everything needed to interact with Vegvisir's PHP features.
The class can not be instanced since it only contains static methods.
-The VV
class is accessible without a namespace from any PHP file within your project.
The class intentionally lacks a namespace to reduce the (all be it short) boilerplate code that would be required to import and use
it on every page of your project.
(Vegvisir 2, Vegvisir 3)
-VV::js()
Import and minify a JavaScript file.
-The syntax is identical to VV::css()
, and VV::embed()
.
VV::js()
imports and minifies a JavaScript file and returns it as a string.
pathname
Path to a JavaScript file to import relative from project root.
-relative
Path provided to pathname
will be a relative when this parameter is true
(default). Set to false
to make path absolute.
string
A string containing minified JavaScript. Please note that linebreaks are preserved.
-Will return an empty string if the path provided to pathname
is not a valid JavaScript file, or if it failed to import.
Let's take the following JavaScript file and put it into a page.
- = Snippet::put("docs/API/PHP/VV/js/example-1-0", Snippet::JAVASCRIPT) ?> - = Snippet::put("docs/API/PHP/VV/js/example-1-1", Snippet::PHP) ?> -By using VV::js()
inside a script
, we've enabled the code for that specific page.
(Vegvisir 3)
-VV::root()
Return an absolute path to a file or folder relative from project root.
-Return an absolute path to a file or folder relative from project root. This method does not process the entity at the provided location in any way. It simply returns an absolute path to it, which can be used with other functions.
-pathname
Path to a location relative from project root. This parameter is an empty string by default, which will return an absolute path to project root itself.
-string
An absolute path to the relative location provided by pathname
.
VV::root()
doesn't do anything on its own other than "convert" a relative path into an absolute one.
This can come in really handy when importing other PHP classes within your project. Let's import a PHP class from one location in the project into a public page.
-Let's import and use this class on our page with VV::root()
.
(Vegvisir 3)
-VV::shell()
Wrap contents of a page within another page.
-This method is similar to VV::include()
except it lets you place persistent content around the included page.
VV::shell()
is a powerful method which lets you put the contents of one page into a vv-shell
tag on another page.
Subsequent navigations to pages using the same shell will preserve the outer shell's state. The shell will not be fetched again.
-pathname
Path to a PHP shell page relative from project root which the contents of the initiator page will be wrapped inside.
-This method is buffered and will flush the buffer contents to stdout
when the last shell has been imported.
If we want the contents of page /public/some-page.php
wrapped inside the contents of /shells/some-shell.php
, we can do the following:
Place a VV::shell()
snippet at the end of the page you wish to wrap.
Now let's add a vv-shell
tag somewhere in our /shells/some-shell.php
file.
The contents of /public/some-page.php
will replace the inner contents of the vv-shell
tag.
The shell file acts like any other Vegvisir page, which means you have access to all VV
methods.
Vegvisir only has one class you need to worry about. The VV
class contains everything needed to interact with Vegvisir functions from project pages.
Here are some one-liners to help remember what things do.
-VV::include()
and VV::shell()
VV::include()
puts content inside another page.
VV::shell()
puts a page inside other content.
Vegvisir is a PHP and JavaScript web framework developed by Victor Westerlund as a hobby project.
-This framework is not intended to replace the true-and-tested like Laravel, it would be interesting of course if it gained some users but my goal is to keep this project small and flexible.
-This documentation only covers the new experimental version of Vegvisir, which is version 3.
-The older versions of Vegvisir can be found here. They lack proper documentation and function a bit differently than Vegvisir 3 which has been largely rewritten from scratch. The main addition to version 3 are what I call "shells".
-In this guide we will be installing Vegvisir on a Debian-based system with NGINX as the web server. The process should be similar for other configurations as well.
- -Let's start by cloning Vegvisir to a folder. The code for Vegvisir will be separate from the code for your project.
- = Snippet::put("docs/installation/0", Snippet::PLAINTEXT) ?> -I have cloned this into the folder /var/www/vegvisir
but you can put it wherever you want.
Vegvisir only has one dependency, let's cd
into our folder and install it with Composer.
We will be pointing a virtual host to the /public/index.php
file from the Vegvisir root directory.
Since your project files will live in a different directory, this can be set-and-forget.
- = Snippet::put("docs/installation/2", Snippet::PLAINTEXT) ?> -We're almost done here. We want to create a separate folder which will hold our project files.
-Let's create a folder /var/www/my-website
as an example - you can put this wherever you want!
Now let's finish up by pointing Vegvisir to the folder we just created.
-Make a copy of the .env.example.ini
file from Vegvisir's root directory and place it in the same spot as .env.ini
There is only one line we need to change inside the .env.ini
file we just created. It should be the top most variable called root_path
.
Change the value of this variable to an absolute path to your project root folder. In our case it will be /var/www/my-website
.
That's all there is to it. Restart your webserver if you haven't and navigate to your published website.
-If everything worked correctly, you should see a default landing page with a summary.
-Vegvisir will automatically serve anything that isn't a .php
file under /public
in your project directory as a static asset. You can for example put your robots.txt
file under /public/robots.txt
and it will be returned as a text/plain
document.
While this works fine for smaller assets, they still have to be passed through the PHP CGI. This process is a bit slower than serving assets with your web server directly - and might be a lot slower for larger files.
-To fix this, let's add an optional location
block to our NGINX configuration which will handle assets. The process should be similar for other web servers - contact me if you need help.
Let's add the following location
block to our NGINX virtual host that we set up in Step X.
Vegvisir has a few environment variables that can be modified to change its behavior.
+Copy .env.example.ini
to .env.ini
and edit the copied file to get started.
string
root_path
An absolute path to the folder where your project is located.
+string
shell_page
A path relative from your root_path
to a PHP file that contains a vv-shell
element, and will be loaded as the shell of your page.
string
public_path
A path relative from your root_path
to a folder containing public PHP pages and other public static assets.
The default for this variable is "public/".
+string
| null
error_page_path
An optional path relative from your root_path
to a PHP file that will be loaded when a page can not be found.
Commenting-out this variable or setting it to null will disable error pages. An empty respone body will be returned.
+string
worker_magic_pathname
Vegvisir navigation worker code will be returned when request pathname matches this string
+This variable can be left as-is for most applications.
+string
| null
rfc_4288_url
URL to an RFC 4288 compatible MIME-type file which will be cached (until server reboot) and referenced for serving static assets.
+The default for this variable is Apache's httpd MIME-reference.
+Commenting-out this variable or setting it to null will disable custom MIME-lists and default to PHP's mime_content_type
parser.
A set of CustomEvent
instances dispatched when various Vegvisir navigations are performed.
STARTED
An event dispatched with the type
of "navstarted"
on the target
element when a navigation has started. This event is also dispatched on document.body
.
The detail
property of this event returns the Navigation
instance that initiated the navigation.
FINISHED
An event dispatched with the type
of "navfinished"
on the target
element when a navigation has finished loading completely (content has been injected). This event is also dispatched on document.body
.
The detail
property of this event returns the Navigation
instance that initiated the navigation.
No examples available.
+A static object of Navigation
that alters the injection method of the target
element of .navigate()
REPLACE
The inner DOM of the target
element of .navigate()
will be replaced with the contents of href
from a Navigation
instance.
This is the default behavior.
+REPLACE
The contents of href
from a Navigation
instance will be inserted(appended) to the end of the existing DOM of the target
element of .navigate()
No examples available.
+A static object of Navigation
that adheres to the same concept as position
of .insertAdjacentElement()
AFTEREND
Inserts/replaces the DOM after the target
element with the contents of href
from a Navigation
instance.
BEFOREEND
This is the default behavior.
+Inserts/replaces the DOM right before closing the target
element with the contents of href
from a Navigation
instance.
Navigation.MODE.REPLACE
makes this perform the same operation as AFTERBEGIN
.
AFTERBEGIN
Inserts/replaces the DOM right after opening the target
element with the contents of href
from a Navigation
instance.
Navigation.MODE.REPLACE
makes this perform the same operation as BEFOREEND
.
BEFOREBEGIN
Inserts/replaces the DOM before the target
element with the contents of href
from a Navigation
instance.
No examples available.
+A static object of Navigation
that alters where the contents of a navigation should be placed relative to the target
element element for .navigate()
.
TOP
The inner DOM of the target
element will be replaced with the contents of href
from a Navigation
instance.
This is the default behavior when the vv-shell
element (top navigation) is navigated.
Setting this parameter on a target
element that isn't the vv-shell
element has the same effect as a normal top navigation. The target is "ignored".
SELF
The contents of the target
element will be navigated.
This is the default behavior when an element that isn't the vv-shell
is navigated.
Setting this parameter on a target
element that is the vv-shell
(top navigation) has the same effect as TOP
.
BLANK
Performs the browser-default behavior for opening links in a new window. The target
element is ignored.
PARENT
The closest HTMLElement
to the target
element with a vv-page
property present will be navigated. If no parent element with that attribute is found, the vv-shell
element (top navigation) will be navigated.
Setting this parameter on a target
element that is the vv-shell
(top navigation) has the same effect as TOP
.
No examples available.
+Abort a Vegvisir navigation in action.
+This is an instance property of vegvisir.Navigation
.
AbortController
Returns an instance of AbortController
.
In this example we will perform a simple programmatic Vegvsir navigation and abort it immediately.
+Static method on the Navigation
class.
Calling this method will trigger an automatic binding of anchor tags that haven't been bound yet.
+SSR anchor tags are automatically bound. This method should be called after you've added anchor tags dynamically with JavaScript.
+Initialize a new Vegvisir soft-navigation programmatically.
+Navigation
Returns an instance of Navigation
which can then be excuted by chaining .navigate()
.
No examples available.
+Vegvisir will automatically find and bind HTMLAnchorElement
tags and perform soft-navigation between pages on the same origin.
The Navigation
lets you interact with, and expand Vegvisirs front-end behavior.
HTMLElement
| String
| null
target
An element passed either by reference or a CSS selector passed as a string (if multiple elements match the selector; the first match will be navigated).
+If null or no value is passed to this argument, the vv-shell
element will be navigated (top navigation).
String
position
A Navigation.POSITION string which will determine where content from the navigated page should be injected relative to target
.
String
mode
A Navigation.MODE string which will determine how content from the navigated page should be injected relative to target
.
Promise
Returns a Promise that will resolve when the navigated page has been injected sucessfully, or rejects if the navigation failed or if the navigation was aborted with Navigation.abort
Navigate the vv-shell
element to another page (top navigation).
Remember that anchor tags with href's on the same origin are automatically navigated this way.
+Simple programmatic navigation of an element.
+An object containing parameters that can be changed to alter the behavior of a Vegvisir Navigation
.
bool
pushHistory
Flag which when set to:
+true
+ Will cause navigations performed on an instance of Navigation
to push to the History stack and update the browser pathname.
false
+ Will cause a "silent" navigation on an instance of Navigation
that won't update the broweser History stack and won't change the browser pathname.
The default setting for this property is:
+ +bool
carryRequestOptions
Flag which when set to:
+true
+ Will cause navigations performed on an instance of Navigation
to carry the request method and response body that the initiator page received on load.
false
+ Navigations performed on an instance of Navigation
will be sent as GET
requests (without a request body).
No examples available.
+Include a CSS file into a page which will be automatically minified and inlined.
+string
$pathname
Path to a CSS stylehseet file.
+Appending ".css" to the filename is optional. If omitted, the extension is infered.
+bool
$relative
Flag which when set to:
+true
+ Will make $pathname
look for a CSS file relative to root_path
.
false
+ Will make $pathname
look for a CSS file relative to the root of the whole filesystem.
string
Returns a minified version of the included stylesheet as a string. If a stylesheet can not be found at $pathname
, an empty string is returned.
In this example we're importing a stylesheet from /public/assets/css/style.css
relative from root_path
.
Inline the contents of any file.
+This can be very useful for bundling SVGs, plaintext files, HTML, and more for faster page loading.
+string
$pathname
Path to an asset to inline.
+bool
$relative
Flag which when set to:
+true
+ Will make $pathname
look for a file relative to root_path
.
false
+ Will make $pathname
look for a file relative to the root of the whole filesystem.
string
Returns the contents of a file passed to $pathname
as a string. If a file can not be found at $pathname
, an empty string is returned.
In this example we will be inlining an SVG icon from /public/assets/icon.svg
directly into our page as if it were hardcoded.
Inject the compiled output of another Vegvisir page (or other PHP script).
+string
$pathname
Path to another Vegvisir page or other PHP file.
+bool
$relative
Flag which when set to:
+true
+ Will make $pathname
look for a source file relative to root_path
.
false
+ Will make $pathname
look for a source file relative to the root of the whole filesystem.
string
Returns a minified version of the included source file as a string. If a file can not be found at $pathname
, an empty string is returned.
In this example we will be including a PHP file that contains reusable code (a banner) from /snippets/banner.php
into a Vegvisir page /public/index.php
.
Initialize the Vegvisir front-end.
+Place this as close to the bottom of your body
tag in your shell_page
as possible.
This method takes no parameters.
+string
Returns a script tag with the compiled and minified JavaScript required to run the Vegvisir front-end.
+In this example we will initialize a single-page website with the two required files to run a bare-bones Vegvisir website: /public/index.php
and /public/shell.php
.
Include a JavaScript source file into a page which will be automatically minified and inlined.
+string
$pathname
Path to a JavaScript source file.
+Appending ".js" to the filename is optional. If omitted, the extension is infered.
+bool
$relative
Flag which when set to:
+true
+ Will make $pathname
look for a JavaScript source file relative to root_path
.
false
+ Will make $pathname
look for a JavaScript source file relative to the root of the whole filesystem.
string
Returns a minified version of the included JavaScript source file as a string. If a file can not be found at $pathname
, an empty string is returned.
In this example we're importing a JavaScript source file from /public/assets/js/script.js
relative from root_path
.
Return an absolute path to any resource relative to root_path
.
string
$pathname
Path to any resource relative from root_path
.
Passing an empty string or nothing to this method will return an absolute path to the root folder itself.
+string
Returns a string with an absolute pathname from a relative pathname passed to $pathname
.
Vegvisir exposes a single global static class VV
that can be used in any script/page loaded with Vegvisir.
This class contains various methods for importing, inlining assets, and returning pathnames.
+Here you'll find cheat sheets for Vegvisir's VV
PHP static class, and the vegvisir.Navigation
JavaScript class.
Vegvisir has a few attributes that can be added to elements that can be used to bind navigations and change navigation behavior without JavaScript.
+string
vv
This attribute can be added to any clickable HTML element to bind it like an anchor tag.
+The value of this attribute should be a string with a pathname to the page that should be loaded.
+An element with this attribute will be treated just like an anchor tag, which means (by default) the vv-shell
will be navigated.
Note: If added to an anchor tag, the anchor href
will be prefered - and the vv
will be ignored.
string
vv-position
A Navigation.POSITION
string that determines where the contents of vv
(or href
on an anchor tag) should be injected relative to the element with this attribute.
string
vv-mode
A Navigation.MODE
string that determines how the contents of vv
(or href
on an anchor tag) should be injected relative to the element with this attribute.
Vegvisir sets a few attributes on elements that wrap soft-navigated content. These attributes are created automatically when it's the first time an element is used as a wrapper.
+string
vv-page
This attribute's value will be updated with the pathname of the page that was soft-navigated to.
+The attribute is set when a navigation is initiated.
+bool
vv-loading
The value of this attribute will be a string-boolean with a value of "true" or "false".
+this attribute will be "true" when a navigation is initiated, and set to "false" when the contents of the target page has been fully loaded (DOM ready).
+In this guide we will install Vegvisir from a template repository. I will be using a Debian Linux environment for this demonstration.
+There is a template repository on Codeberg which you can clone or generate from which has a bare-bones website ready for us.
+ +The template repository has an install.sh
file in its root directory which will install and set up our Vegvisir configuration for us.
In this demo we will be using NGINX as our web server, and PHP-FPM (packaged by Ondřej Surý) as our FastCGI processor.
+As long as you point all traffic to /vegvisir/public/index.php
with PHP pass you should be fine with other web server programs too.
Navigate to your configured web server host and if you're greeted with a welcome to Vegvisir page, then everything is working as it should!
+Feel free to experiment or follow the reference guide for more information about each Vegvisir feature.
+ +Vegvisir is a work in progress, based on a framework I developed for a company a few years ago, which in turn was based on a content injector I built for another company. You can read more about the history of this framework on my personal website.
+Adding a Vegvisir version number after "/docs" in the pathname /docs/vX.X.X/example-docs-page
lets you read the docs for a specific release.
This website (and the framework itself) is a work in progress. I apologize for the rushed, incomplete, confusing documentation on this site. I will make an effort to update these pages as best as I can.
+The simple answer to what Vegvisir does is that it will automatically find and bind navigation handlers for all HTMLAnchorElement
s on a website. If the anchor href
points to a page on the same origin; a PHP file (containing HTML and native PHP templating) from the website's public_path
will be automatically soft-navigated to.
Another thing that Vegvisir lets you do with those soft-navigated pages is to inject and minify assets such as CSS stylesheets, JavaScript source files, and other assets that output text.
+And the last thing that Vegvisir will offer for you is embeding snippets of PHP code (or another page) into a page.
+In this guide we will be installing Vegvisir on a Debian-based system with NGINX as the web server. The process should be similar for other configurations as well.
+ +Let's start by cloning Vegvisir to a folder. The code for Vegvisir will be separate from the code for your project.
+ = Snippet::put("docs/installation/0", Snippet::PLAINTEXT) ?> +I have cloned this into the folder /var/www/vegvisir
but you can put it wherever you want.
Vegvisir only has one dependency, let's cd
into our folder and install it with Composer.
We will be pointing a virtual host to the /public/index.php
file from the Vegvisir root directory.
Since your project files will live in a different directory, this can be set-and-forget.
+ = Snippet::put("docs/installation/2", Snippet::PLAINTEXT) ?> +We're almost done here. We want to create a separate folder which will hold our project files.
+Let's create a folder /var/www/my-website
as an example - you can put this wherever you want!
Now let's finish up by pointing Vegvisir to the folder we just created.
+Make a copy of the .env.example.ini
file from Vegvisir's root directory and place it in the same spot as .env.ini
There is only one line we need to change inside the .env.ini
file we just created. It should be the top most variable called root_path
.
Change the value of this variable to an absolute path to your project root folder. In our case it will be /var/www/my-website
.
That's all there is to it. Restart your webserver if you haven't and navigate to your published website.
+If everything worked correctly, you should see a default landing page with a summary.
+Vegvisir will automatically serve anything that isn't a .php
file under /public
in your project directory as a static asset. You can for example put your robots.txt
file under /public/robots.txt
and it will be returned as a text/plain
document.
While this works fine for smaller assets, they still have to be passed through the PHP CGI. This process is a bit slower than serving assets with your web server directly - and might be a lot slower for larger files.
+To fix this, let's add an optional location
block to our NGINX configuration which will handle assets. The process should be similar for other web servers - contact me if you need help.
Let's add the following location
block to our NGINX virtual host that we set up in Step X.
there's nothing to show here :(
\ No newline at end of file diff --git a/public/examples.php b/public/examples.php new file mode 100644 index 0000000..3b2d1f2 --- /dev/null +++ b/public/examples.php @@ -0,0 +1,47 @@ + +Here are some examples of Vegvisir being used on real websites!
+That header is present on every page, so it's loaded once and never again.
+Vevisir pages, snippets, and other PHP files can be inlined with the response using VV::include
.
that handles navigation and routing, and nothing else
+ + +developed as a hobby project by Victor Westerlund
+