mirror of
https://codeberg.org/vlw/vlw.se.git
synced 2025-09-13 21:13:40 +02:00
chore: add support for Vegvisir 3 (#1)
This PR adds support for the latest major release of the [Vegvisir framework](https://vegvisir.vlw.se) Reviewed-on: https://codeberg.org/vlw/vlw.se/pulls/1 Co-authored-by: vlw <victor@vlw.se> Co-committed-by: vlw <victor@vlw.se>
This commit is contained in:
parent
43ddf1fdf6
commit
ae1e992c5f
34 changed files with 276 additions and 256 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,8 +1,9 @@
|
|||
assets/media/content
|
||||
assets/js/modules/npm
|
||||
|
||||
# Bootstrapping #
|
||||
#################
|
||||
vendor
|
||||
node_modules
|
||||
.env.ini
|
||||
|
||||
# OS generated files #
|
||||
|
|
31
README.md
31
README.md
|
@ -1,32 +1,38 @@
|
|||
# vlw.se
|
||||
This is the source code behind [vlw.se](https://vlw.se) which has been written from the ground up by me. This website is built on top of my [Vegvisir web framework](https://github.com/victorwesterlund/vegvisir) and my [Reflect API framework](https://github.com/victorwesterlund/reflect).
|
||||
This is the source code behind [vlw.se](https://vlw.se) which has been written from the ground up by me. This website is built on top of my [Vegvisir web framework](https://vegvisir.vlw.se) and my [Reflect API framework](https://reflect.vlw.se).
|
||||
|
||||
# Installation
|
||||
If you for whatever reason want to get this website up and running for yourself this is how that is done.
|
||||
|
||||
This website is built for PHP 8.0+ and MariaDB 14+ (for the API database).
|
||||
## This website requires the following prerequisites
|
||||
- [PHP 8.0+](https://www.php.net/)
|
||||
- [MariaDB 14+](https://mariadb.org/)
|
||||
- [The NPM package manager](https://www.npmjs.com/)
|
||||
- [The Reflect API framework](https://reflect.vlw.se)
|
||||
- [The Vegvisir web framework](https://vegvisir.vlw.se)
|
||||
- [The composer package manager](https://getcomposer.org/)
|
||||
|
||||
**Confimed supported framework versions:**
|
||||
Vegvisir|Reflect
|
||||
--|--
|
||||
✅ [`2.5.0`](https://github.com/VictorWesterlund/vegvisir/releases/tag/2.5.0)|✅ [`2.7.2`](https://github.com/VictorWesterlund/reflect/releases/tag/2.7.2)
|
||||
✅ [`3.0.1`](https://codeberg.org/vegvisir/vegvisir/releases/tag/3.0.1)|✅ [`2.7.2`](https://codeberg.org/reflect/reflect/releases/tag/2.7.2)
|
||||
|
||||
## Website (Vegvisir)
|
||||
1. **Download this repo**
|
||||
|
||||
Git clone or download this repo to any local folder
|
||||
```
|
||||
git clone https://github.com/VictorWesterlund/vlw.se
|
||||
git clone https://codeberg.org/vlw/vlw.se
|
||||
```
|
||||
2. **Download and install Vegvisir**
|
||||
|
||||
Follow the installation instructions for [Vegvisir](https://github.com/victorwesterlund/vegvisir) and point the `site_path` variable to the local vlw.se folder.
|
||||
Follow the installation instructions for [Vegvisir](https://vegvisir.vlw.se/docs/installation) and point the `root_path` variable to your local vlw.se folder.
|
||||
|
||||
3. **Install dependencies**
|
||||
3. **Run the install script**
|
||||
|
||||
Install dependencies with composer.
|
||||
This bash script will install dependencies and make npm modules public.
|
||||
```
|
||||
composer install --optimize-autoloader
|
||||
./install.sh
|
||||
```
|
||||
|
||||
Et voila! You probably want to install the API-side too but the website itself should now be accessible from your configured Vegvisir host.
|
||||
|
@ -40,16 +46,16 @@ The API (and database) is where most content is stored and served from on this w
|
|||
|
||||
Otherwise... Git clone or download this repo to any local folder
|
||||
```
|
||||
git clone https://github.com/VictorWesterlund/vlw.se
|
||||
git clone https://codeberg.org/vlw/vlw.se
|
||||
```
|
||||
|
||||
2. **Download and install Reflect**
|
||||
|
||||
Follow the installation instructions for [Reflect](https://github.com/victorwesterlund/vegvisir) and point the `endpoints` variable to the `/api` subdirectory in the local vlw.se folder.
|
||||
Follow the installation instructions for [Reflect](https://reflect.vlw.se/docs/installation) and point the `endpoints` variable to the `/api` subdirectory in the local vlw.se folder.
|
||||
|
||||
3. **Install dependencies**
|
||||
|
||||
Install dependencies with composer.
|
||||
`cd` into the api folder and install dependencies with composer.
|
||||
```
|
||||
composer install --optimize-autoloader
|
||||
```
|
||||
|
@ -62,9 +68,6 @@ The API (and database) is where most content is stored and served from on this w
|
|||
|
||||
Make a copy of `/api/.env.example.ini` and change the `[vlwdb]` variables with your MariaDB credentials.
|
||||
|
||||
You also have to generate a [GitHub access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) if you wish to use the `releases` endpoint.
|
||||
[Read more about this endpoint here](#)
|
||||
|
||||
6. **Set environment variables for website**
|
||||
|
||||
It's reasonable to assume if you've installed the website from this repo that you'd also want to use the API with it. Start my making a copy of `/.env.example.ini` (root directory) and change the `[api]` variables to point to your API hostname.
|
||||
|
|
2
api/install.sh
Normal file
2
api/install.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Install dependencies
|
||||
composer install --optimize-autoloader
|
|
@ -5,7 +5,7 @@
|
|||
--color-accent: rgb(var(--primer-color-accent));
|
||||
}
|
||||
|
||||
main {
|
||||
vv-shell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--padding);
|
||||
|
@ -15,7 +15,7 @@ main {
|
|||
|
||||
/* ## Divider */
|
||||
|
||||
main > hr {
|
||||
vv-shell > hr {
|
||||
border-color: rgba(255, 255, 255, .1);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
--color-accent: rgb(var(--primer-color-accent));
|
||||
}
|
||||
|
||||
main {
|
||||
vv-shell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--padding);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
--color-accent: rgb(var(--primer-color-accent));
|
||||
}
|
||||
|
||||
main {
|
||||
vv-shell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--padding);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
--color-accent: rgb(var(--primer-color-accent));
|
||||
}
|
||||
|
||||
main {
|
||||
vv-shell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
@ -14,7 +14,7 @@ main {
|
|||
|
||||
/* # Sections */
|
||||
|
||||
main > svg {
|
||||
vv-shell > svg {
|
||||
margin: var(--padding) 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ header {
|
|||
backdrop-filter: unset;
|
||||
}
|
||||
|
||||
main {
|
||||
vv-shell {
|
||||
max-width: unset;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
|
|
|
@ -4,18 +4,18 @@ body[vv-top-page="/"]::before {
|
|||
opacity: 0;
|
||||
}
|
||||
|
||||
/* # Main styles */
|
||||
/* # vv-shell styles */
|
||||
|
||||
/* ## Picture */
|
||||
|
||||
main {
|
||||
vv-shell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
main img {
|
||||
vv-shell img {
|
||||
margin: auto;
|
||||
width: 25vh;
|
||||
pointer-events: none;
|
||||
|
@ -171,14 +171,14 @@ splash::after {
|
|||
/* # Size quries */
|
||||
|
||||
@media (min-width: 900px) {
|
||||
main {
|
||||
vv-shell {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
main img {
|
||||
vv-shell img {
|
||||
width: 35vh;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ section.search {
|
|||
margin-bottom: calc(var(--padding) * 2);
|
||||
}
|
||||
|
||||
main[vv-page="/search"] > section.search {
|
||||
vv-shell[vv-page="/search"] > section.search {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
--color-accent: rgb(var(--primer-color-accent));
|
||||
}
|
||||
|
||||
main {
|
||||
vv-shell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--padding);
|
||||
|
|
13
assets/css/document.css → assets/css/shells/document.css
Executable file → Normal file
13
assets/css/document.css → assets/css/shells/document.css
Executable file → Normal file
|
@ -260,24 +260,15 @@ header.searchboxActive searchbox {
|
|||
transform: rotateX(0);
|
||||
}
|
||||
|
||||
/* ## Main */
|
||||
/* ## vv-shell */
|
||||
|
||||
main {
|
||||
vv-shell {
|
||||
position: relative;
|
||||
padding: calc(var(--padding) * 1.5);
|
||||
width: 100%;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
main > * {
|
||||
transition: 100ms opacity;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
main.loading > * {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* ## Search results */
|
||||
|
||||
search-results {
|
|
@ -1,5 +1,3 @@
|
|||
new vv.Interactions("about");
|
||||
|
||||
const randomIntFromInterval = (min, max) => {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
new vv.Interactions("battlestation-retired");
|
|
@ -1,19 +1,19 @@
|
|||
new vv.Interactions("battlestation", {
|
||||
toggleGroup: (event) => {
|
||||
// Collapse self if already active and current target
|
||||
if (event.target.classList.contains("active")) {
|
||||
return event.target.classList.remove("active");
|
||||
}
|
||||
import { Elevent } from "/assets/js/modules/npm/Elevent.mjs";
|
||||
|
||||
// Collapse all and open current target
|
||||
[...event.target.closest(".specs").querySelectorAll(".group")].forEach(element => element.classList.remove("active"));
|
||||
event.target.classList.add("active");
|
||||
},
|
||||
setSpecActive: (event) => {
|
||||
event.target.classList.add("active");
|
||||
|
||||
event.target.addEventListener("mouseleave", () => event.target.classList.remove("active"));
|
||||
new Elevent("click", document.querySelectorAll(".group"), (event) => {
|
||||
// Collapse self if already active and current target
|
||||
if (event.target.classList.contains("active")) {
|
||||
return event.target.classList.remove("active");
|
||||
}
|
||||
|
||||
// Collapse all and open current target
|
||||
[...event.target.closest(".specs").querySelectorAll(".group")].forEach(element => element.classList.remove("active"));
|
||||
event.target.classList.add("active");
|
||||
});
|
||||
|
||||
new Elevent("click", document.querySelectorAll(".spec"), (event) => {
|
||||
event.target.classList.add("active");
|
||||
event.target.addEventListener("mouseleave", () => event.target.classList.remove("active"));
|
||||
});
|
||||
|
||||
// Bind hover listeners for components in the SVGs
|
||||
|
|
|
@ -10,8 +10,6 @@ class ContactForm {
|
|||
[...document.querySelectorAll("form :is(input, textarea)")].forEach(element => {
|
||||
element.addEventListener("keyup", () => this.saveMessage());
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Get saved message as JSON from SessionStorage
|
||||
|
@ -36,6 +34,7 @@ class ContactForm {
|
|||
return ContactForm.removeSavedMessage();
|
||||
}
|
||||
|
||||
// Set value of each input field in DOM by name attribute
|
||||
for (const [name, value] of Object.entries(message)) {
|
||||
this.form.querySelector(`[name="${name}"]`).value = value;
|
||||
}
|
||||
|
|
|
@ -1,59 +1,61 @@
|
|||
const EMAIL_CPY_ANIM_DUR_MSECONDS = 1000;
|
||||
import { Elevent } from "/assets/js/modules/npm/Elevent.mjs";
|
||||
|
||||
// Run email copied splash animation
|
||||
const emailCopiedAnimation = () => {
|
||||
const CONFETTI_COUNT = 40;
|
||||
const CONFETTI_SCALE_PIXELS = 300;
|
||||
// Click to copy email button
|
||||
{
|
||||
const EMAIL_CPY_ANIM_DUR_MSECONDS = 1000;
|
||||
|
||||
const randomIntFromInterval = (min, max) => {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min)
|
||||
// Run email copied splash animation
|
||||
const emailCopiedAnimation = () => {
|
||||
const CONFETTI_COUNT = 40;
|
||||
const CONFETTI_SCALE_PIXELS = 300;
|
||||
|
||||
const randomIntFromInterval = (min, max) => {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min)
|
||||
}
|
||||
|
||||
// Create new splash element
|
||||
const splashElement = document.createElement("splash");
|
||||
splashElement.innerText = "copied!";
|
||||
|
||||
// Set inline display to none to hide this element on pages where the splash element has no override styles defined.
|
||||
splashElement.style.display = "none";
|
||||
|
||||
// Array of box-shadow strings as "confetti"
|
||||
const confetti = [];
|
||||
|
||||
// Generate random confetti
|
||||
for (let i = 0; i < CONFETTI_COUNT; i++) {
|
||||
// Random confetti position
|
||||
const x = randomIntFromInterval(CONFETTI_SCALE_PIXELS * -1, CONFETTI_SCALE_PIXELS);
|
||||
const y = randomIntFromInterval(CONFETTI_SCALE_PIXELS * -1, CONFETTI_SCALE_PIXELS);
|
||||
|
||||
// Random confetti RGB color
|
||||
const rgb = [
|
||||
randomIntFromInterval(0, 255),
|
||||
randomIntFromInterval(0, 255),
|
||||
randomIntFromInterval(0, 255)
|
||||
];
|
||||
|
||||
// Interpolate random values and append to outer confetti array
|
||||
confetti.push(`${x}px ${y}px 0 rgb(${rgb.join(",")})`);
|
||||
}
|
||||
|
||||
// Set CSS variable on splash element that in turn will be used by pseudo-element
|
||||
splashElement.style.setProperty("--confetti", confetti.join(","));
|
||||
|
||||
// Start animation by appending the created element to the document body
|
||||
document.body.appendChild(splashElement);
|
||||
|
||||
// Run hide animation
|
||||
setTimeout(() => {
|
||||
splashElement.classList.add("hide");
|
||||
|
||||
// Selfdestruct element when hide animation finishes
|
||||
setTimeout(() => splashElement.remove(), 400);
|
||||
}, EMAIL_CPY_ANIM_DUR_MSECONDS + 100);
|
||||
}
|
||||
|
||||
// Create new splash element
|
||||
const splashElement = document.createElement("splash");
|
||||
splashElement.innerText = "copied!";
|
||||
|
||||
// Set inline display to none to hide this element on pages where the splash element has no override styles defined.
|
||||
splashElement.style.display = "none";
|
||||
|
||||
// Array of box-shadow strings as "confetti"
|
||||
const confetti = [];
|
||||
|
||||
// Generate random confetti
|
||||
for (let i = 0; i < CONFETTI_COUNT; i++) {
|
||||
// Random confetti position
|
||||
const x = randomIntFromInterval(CONFETTI_SCALE_PIXELS * -1, CONFETTI_SCALE_PIXELS);
|
||||
const y = randomIntFromInterval(CONFETTI_SCALE_PIXELS * -1, CONFETTI_SCALE_PIXELS);
|
||||
|
||||
// Random confetti RGB color
|
||||
const rgb = [
|
||||
randomIntFromInterval(0, 255),
|
||||
randomIntFromInterval(0, 255),
|
||||
randomIntFromInterval(0, 255)
|
||||
];
|
||||
|
||||
// Interpolate random values and append to outer confetti array
|
||||
confetti.push(`${x}px ${y}px 0 rgb(${rgb.join(",")})`);
|
||||
}
|
||||
|
||||
// Set CSS variable on splash element that in turn will be used by pseudo-element
|
||||
splashElement.style.setProperty("--confetti", confetti.join(","));
|
||||
|
||||
// Start animation by appending the created element to the document body
|
||||
document.body.appendChild(splashElement);
|
||||
|
||||
// Run hide animation
|
||||
setTimeout(() => {
|
||||
splashElement.classList.add("hide");
|
||||
|
||||
// Selfdestruct element when hide animation finishes
|
||||
setTimeout(() => splashElement.remove(), 400);
|
||||
}, EMAIL_CPY_ANIM_DUR_MSECONDS + 100);
|
||||
}
|
||||
|
||||
new vv.Interactions("index", {
|
||||
// Copy email address to clipboard
|
||||
copyEmail: async () => {
|
||||
new Elevent("click", document.querySelector(".email"), async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText("victor@vlw.se");
|
||||
|
||||
|
@ -70,39 +72,37 @@ new vv.Interactions("index", {
|
|||
} catch (error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
},
|
||||
// Open the fullscreen menu
|
||||
openMenu: () => document.querySelector("menu").classList.add("active"),
|
||||
// Close the fullscreen menu
|
||||
closeMenu: () => document.querySelector("menu").classList.remove("active")
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Change site accent color on hover of menu items
|
||||
if (window.matchMedia("(hover: hover)")) {
|
||||
// Update root CSS variables
|
||||
const updateColor = (rgb = null, hue = 0) => {
|
||||
if (!rgb) {
|
||||
document.documentElement.style.removeProperty("--hue-accent");
|
||||
document.documentElement.style.removeProperty("--primer-color-accent");
|
||||
document.documentElement.style.removeProperty("--color-accent");
|
||||
{
|
||||
if (window.matchMedia("(hover: hover)")) {
|
||||
// Update root CSS variables
|
||||
const updateColor = (rgb = null, hue = 0) => {
|
||||
if (!rgb) {
|
||||
document.documentElement.style.removeProperty("--hue-accent");
|
||||
document.documentElement.style.removeProperty("--primer-color-accent");
|
||||
document.documentElement.style.removeProperty("--color-accent");
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
document.documentElement.style.setProperty("--hue-accent", `${hue}deg`);
|
||||
document.documentElement.style.setProperty("--hue-accent", `${hue}deg`);
|
||||
|
||||
document.documentElement.style.setProperty("--primer-color-accent", `${rgb}`);
|
||||
// Compiled color variable must to be updated to receive the new RGB values
|
||||
document.documentElement.style.setProperty("--color-accent", "rgb(var(--primer-color-accent)");
|
||||
};
|
||||
document.documentElement.style.setProperty("--primer-color-accent", `${rgb}`);
|
||||
// Compiled color variable must to be updated to receive the new RGB values
|
||||
document.documentElement.style.setProperty("--color-accent", "rgb(var(--primer-color-accent)");
|
||||
};
|
||||
|
||||
[...document.querySelectorAll("menu li")].forEach(element => {
|
||||
// Change site accent color to RGB and HUE rotation defined in element dataset
|
||||
element.addEventListener("mouseenter", (event) => updateColor(event.target.dataset.rgb, event.target.dataset.hue));
|
||||
// Reset initial accent color and hues
|
||||
element.addEventListener("mouseleave", () => updateColor());
|
||||
});
|
||||
[...document.querySelectorAll("menu li")].forEach(element => {
|
||||
// Change site accent color to RGB and HUE rotation defined in element dataset
|
||||
element.addEventListener("mouseenter", (event) => updateColor(event.target.dataset.rgb, event.target.dataset.hue));
|
||||
// Reset initial accent color and hues
|
||||
element.addEventListener("mouseleave", () => updateColor());
|
||||
});
|
||||
|
||||
// Reset color on navigation
|
||||
document.querySelector(vv._env.MAIN).addEventListener(vv.Navigation.events.LOADED, () => updateColor(), { once: true });
|
||||
// Reset color on navigation
|
||||
vv.Navigation.rootShellElement.addEventListener(vv.Navigation.EVENTS.STARTED, () => updateColor(), { once: true });
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
new vv.Interactions("search");
|
|
@ -1 +0,0 @@
|
|||
new vv.Interactions("work");
|
47
assets/js/document.js → assets/js/shells/document.js
Executable file → Normal file
47
assets/js/document.js → assets/js/shells/document.js
Executable file → Normal file
|
@ -1,38 +1,37 @@
|
|||
new vv.Interactions("document", {
|
||||
navigateHome: () => new vv.Navigation("/").navigate(),
|
||||
closeSearchbox: () => {
|
||||
import { Elevent } from "/assets/js/modules/npm/Elevent.mjs";
|
||||
|
||||
const CLASSNAME_SEARCHBOX_ACTIVE = "searchboxActive";
|
||||
|
||||
// Handle search box open/close buttons
|
||||
{
|
||||
// Open search box
|
||||
new Elevent("click", document.querySelector(".searchbox-open"), () => {
|
||||
document.querySelector("header").classList.add(CLASSNAME_SEARCHBOX_ACTIVE);
|
||||
// Select searchbox inner input element
|
||||
document.querySelector("searchbox input").focus();
|
||||
});
|
||||
|
||||
// Close searchbox
|
||||
new Elevent("click", document.querySelector(".searchbox-close"), () => {
|
||||
// Disable search button interaction while animation is running
|
||||
// This is required to prevent conflicts with the :hover "peak" transformation
|
||||
const searchButtonElement = document.querySelector("header button.search");
|
||||
const transformDuration = parseInt(window.getComputedStyle(searchButtonElement).getPropertyValue("--transform-duration"));
|
||||
searchButtonElement.style.setProperty("pointer-events", "none");
|
||||
|
||||
document.querySelector("header").classList.remove("searchboxActive");
|
||||
document.querySelector("header").classList.remove(CLASSNAME_SEARCHBOX_ACTIVE);
|
||||
|
||||
// Wait for the transform animation to finish
|
||||
setTimeout(() => searchButtonElement.style.removeProperty("pointer-events"), transformDuration);
|
||||
},
|
||||
openSearchbox: () => {
|
||||
document.querySelector("header").classList.add("searchboxActive");
|
||||
// Select searchbox inner input element
|
||||
document.querySelector("searchbox input").focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Crossfade pages on navigation
|
||||
{
|
||||
const mainElement = document.querySelector(vv._env.MAIN);
|
||||
|
||||
mainElement.addEventListener(vv.Navigation.events.LOADING, () => {
|
||||
mainElement.classList.add("loading");
|
||||
});
|
||||
}
|
||||
|
||||
mainElement.addEventListener(vv.Navigation.events.LOADED, () => {
|
||||
// Close searchbox on main page navigation
|
||||
document.querySelector("header").classList.remove("searchboxActive");
|
||||
|
||||
// Wait 200ms for the page fade-in animation to finish
|
||||
setTimeout(() => mainElement.classList.remove("loading"), 200);
|
||||
// Root shell navigation event handlers
|
||||
{
|
||||
// On all top shell navigations
|
||||
new Elevent(vv.Navigation.EVENTS.STARTED, vv.Navigation.rootShellElement, () => {
|
||||
// Close searchbox on top shell navigations
|
||||
document.querySelector("header").classList.remove(CLASSNAME_SEARCHBOX_ACTIVE);
|
||||
});
|
||||
}
|
||||
|
10
install.sh
Normal file
10
install.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Install dependencies
|
||||
composer install --optimize-autoloader
|
||||
npm install
|
||||
|
||||
# (Re)create public NPM modules folder
|
||||
rm -r assets/js/modules/npm
|
||||
mkdir assets/js/modules/npm
|
||||
|
||||
# Create link to Elevent MJS from public JS modules folder
|
||||
ln -sr node_modules/elevent/src/Elevent.mjs assets/js/modules/npm/Elevent.mjs
|
17
package-lock.json
generated
Normal file
17
package-lock.json
generated
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "vlw.se",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"elevent": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/elevent": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/elevent/-/elevent-1.0.2.tgz",
|
||||
"integrity": "sha512-ks5LBUBTg4Bpfmj99OcFAzuDGzBRDEZhTyxmq/Y3RbsdBQ4JCaIUYB0M15OBvBWgIn1BnCo4WCSmw0/YbCJliw=="
|
||||
}
|
||||
}
|
||||
}
|
5
package.json
Normal file
5
package.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"elevent": "^1.0.2"
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<style><?= VV::css("pages/error") ?></style>
|
||||
<canvas></canvas>
|
||||
<section class="error">
|
||||
<h1 glitch-text><span>4</span><span>0</span><span>4</span></h1>
|
||||
</section>
|
||||
<script type="module"><?= VV::js("pages/error") ?></script>
|
6
pages/about.php → public/about.php
Executable file → Normal file
6
pages/about.php → public/about.php
Executable file → Normal file
|
@ -1,4 +1,4 @@
|
|||
<style><?= VV::css("pages/about") ?></style>
|
||||
<style><?= VV::css("assets/css/pages/about") ?></style>
|
||||
<section class="intro">
|
||||
<h2 aria-hidden="true">Hi, I'm</h2>
|
||||
<h1>Victor Westerlund</h1>
|
||||
|
@ -31,7 +31,7 @@
|
|||
</section>
|
||||
<hr>
|
||||
<section class="version">
|
||||
<p>website version: <?= VV::include("pages/about/version") ?></p>
|
||||
<p>website version: <?= VV::include("public/about/version") ?></p>
|
||||
</section>
|
||||
|
||||
<div class="interests" aria-hidden="true">
|
||||
|
@ -49,4 +49,4 @@
|
|||
<p>photography</p>
|
||||
<p>videography</p>
|
||||
</div>
|
||||
<script><?= VV::js("pages/about") ?></script>
|
||||
<script type="module"><?= VV::js("assets/js/pages/about") ?></script>
|
|
@ -1,4 +1,4 @@
|
|||
<style><?= VV::css("pages/about/battlestation-retired") ?></style>
|
||||
<style><?= VV::css("assets/css/pages/about/battlestation-retired") ?></style>
|
||||
<section class="title">
|
||||
<h1>Retired components</h1>
|
||||
<p>I'd be happy to send you any component that you find here for "free". The only thing I ask in return is that you pay for shipping.</p>
|
||||
|
@ -33,4 +33,4 @@
|
|||
<button class="inline solid">Contact me</button>
|
||||
</a>
|
||||
</section>
|
||||
<script><?= VV::js("pages/about/battlestation-retired") ?></script>
|
||||
<script><?= VV::js("assets/js/pages/about/battlestation-retired") ?></script>
|
|
@ -25,26 +25,26 @@
|
|||
MbStorageSlotFormfactorEnum
|
||||
};
|
||||
|
||||
require_once Path::root("src/client/API.php");
|
||||
require_once Path::root("api/src/Endpoints.php");
|
||||
require_once VV::root("src/client/API.php");
|
||||
require_once VV::root("api/src/Endpoints.php");
|
||||
|
||||
// Load hardware database models
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Mb.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Cpu.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Gpu.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Psu.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Dram.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Storage.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Chassis.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Mb.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Cpu.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Gpu.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Psu.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Dram.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Storage.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Chassis.php");
|
||||
|
||||
// Load hardware config database models
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Config/MbPsu.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Config/MbGpu.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Config/MbDram.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Config/Config.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Config/MbStorage.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Config/ChassisMb.php");
|
||||
require_once Path::root("api/src/databases/models/Battlestation/Config/MbCpuCooler.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Config/MbPsu.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Config/MbGpu.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Config/MbDram.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Config/Config.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Config/MbStorage.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Config/ChassisMb.php");
|
||||
require_once VV::root("api/src/databases/models/Battlestation/Config/MbCpuCooler.php");
|
||||
|
||||
const GIGA = 0x3B9ACA00;
|
||||
const MEGA = 0xF4240;
|
||||
|
@ -55,7 +55,7 @@
|
|||
$config = $api->call(Endpoints::BATTLESTATION->value)->get();
|
||||
|
||||
?>
|
||||
<style><?= VV::css("pages/about/battlestation") ?></style>
|
||||
<style><?= VV::css("assets/css/pages/about/battlestation") ?></style>
|
||||
<?php if ($config->ok): ?>
|
||||
<section class="title">
|
||||
<h1>Battle­stations</h1>
|
||||
|
@ -93,12 +93,12 @@
|
|||
data-drives-twodotfive="<?= count(array_keys(array_column($motherboard["storage"], MbStorageModel::SLOT_FORMFACTOR->value), MbStorageSlotFormfactorEnum::TWODOTFIVE->value)) ?>"
|
||||
data-drives-threedotfive="<?= count(array_keys(array_column($motherboard["storage"], MbStorageModel::SLOT_FORMFACTOR->value), MbStorageSlotFormfactorEnum::THREEDOTFIVE->value)) ?>"
|
||||
>
|
||||
<?= VV::media("battlestation.svg") ?>
|
||||
<?= VV::embed("assets/media/battlestation.svg") ?>
|
||||
<div class="specs">
|
||||
|
||||
<?php // Show motherboard details ?>
|
||||
<?php if ($motherboard): ?>
|
||||
<div vv="battlestation" vv-call="setSpecActive" data-target="mb" class="spec">
|
||||
<div data-target="mb" class="spec">
|
||||
<p>Motherboard</p>
|
||||
<h3><?= $motherboard[MbModel::VENDOR_NAME->value] ?> <span><?= $motherboard[MbModel::VENDOR_MODEL->value] ?></span></h3>
|
||||
<div>
|
||||
|
@ -149,7 +149,7 @@
|
|||
ChassisModel::ID->value => $mb_chassis[ChassisMbModel::REF_CHASSIS_ID->value]
|
||||
])->get()->json()[0]; ?>
|
||||
|
||||
<div vv="battlestation" vv-call="setSpecActive" data-target="case" class="spec">
|
||||
<div data-target="case" class="spec">
|
||||
<p>Case</p>
|
||||
<h3><?= $case[ChassisModel::VENDOR_NAME->value] ?> <span><?= $case[ChassisModel::VENDOR_MODEL->value] ?></span></h3>
|
||||
<div>
|
||||
|
@ -192,7 +192,7 @@
|
|||
CpuModel::ID->value => $mb_cpu[MbCpuCoolerModel::REF_CPU_ID->value]
|
||||
])->get()->json()[0]; ?>
|
||||
|
||||
<div vv="battlestation" vv-call="setSpecActive" data-target="cpu" class="spec">
|
||||
<div data-target="cpu" class="spec">
|
||||
<p>CPU</p>
|
||||
<h3><?= $cpu[CpuModel::VENDOR_NAME->value] ?> <span><?= $cpu[CpuModel::VENDOR_MODEL->value] ?></span></h3>
|
||||
<div>
|
||||
|
@ -257,7 +257,7 @@
|
|||
GpuModel::ID->value => $mb_gpu[MbGpuModel::REF_GPU_ID->value]
|
||||
])->get()->json()[0]; ?>
|
||||
|
||||
<div vv="battlestation" vv-call="setSpecActive" data-target="gpu" class="spec">
|
||||
<div data-target="gpu" class="spec">
|
||||
<p>GPU</p>
|
||||
<h3><?= $gpu[GpuModel::VENDOR_NAME->value] ?> <span><?= $gpu[GpuModel::VENDOR_CHIP_MODEL->value] ?></span></h3>
|
||||
<div>
|
||||
|
@ -304,7 +304,7 @@
|
|||
PsuModel::ID->value => $mb_psu[MbPsuModel::REF_PSU_ID->value]
|
||||
])->get()->json()[0]; ?>
|
||||
|
||||
<div vv="battlestation" vv-call="setSpecActive" data-target="psu" class="spec">
|
||||
<div data-target="psu" class="spec">
|
||||
<p>PSU</p>
|
||||
<h3><?= $psu[PsuModel::VENDOR_NAME->value] ?> <span><?= $psu[PsuModel::VENDOR_MODEL->value] ?></span> <span><?= $psu[PsuModel::POWER->value] ?>W</span></h3>
|
||||
<div>
|
||||
|
@ -343,9 +343,9 @@
|
|||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<div vv="battlestation" vv-call="toggleGroup" class="group">
|
||||
<div class="group">
|
||||
<p>DRAM</p>
|
||||
<?= VV::media("icons/chevron.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/chevron.svg") ?>
|
||||
</div>
|
||||
|
||||
<div class="collection">
|
||||
|
@ -357,7 +357,7 @@
|
|||
DramModel::ID->value => $mb_dram[MbDramModel::REF_DRAM_ID->value]
|
||||
])->get()->json()[0]; ?>
|
||||
|
||||
<div vv="battlestation" vv-call="setSpecActive" data-target="dram" class="spec">
|
||||
<div data-target="dram" class="spec">
|
||||
<p>DRAM - <?= $dram[DramModel::TECHNOLOGY->value] ?></p>
|
||||
<h3><?= $dram[DramModel::VENDOR_NAME->value] ?>
|
||||
<span><?= $dram[DramModel::CAPACITY->value] / GIGA ?>GB</span>
|
||||
|
@ -422,9 +422,9 @@
|
|||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div vv="battlestation" vv-call="toggleGroup" class="group">
|
||||
<div class="group">
|
||||
<p>Storage</p>
|
||||
<?= VV::media("icons/chevron.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/chevron.svg") ?>
|
||||
</div>
|
||||
|
||||
<div class="collection">
|
||||
|
@ -436,7 +436,7 @@
|
|||
StorageModel::ID->value => $mb_storage[MbStorageModel::REF_STORAGE_ID->value]
|
||||
])->get()->json()[0]; ?>
|
||||
|
||||
<div vv="battlestation" vv-call="setSpecActive" data-target="drive" class="spec">
|
||||
<div data-target="drive" class="spec">
|
||||
<p><?= $storage[StorageModel::DISK_FORMFACTOR->value] ?> <?= $storage[StorageModel::DISK_TYPE->value] ?></p>
|
||||
<h3>
|
||||
<?= $storage[StorageModel::VENDOR_NAME->value] ?>
|
||||
|
@ -493,4 +493,4 @@
|
|||
</section>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
<script><?= VV::js("pages/about/battlestation") ?></script>
|
||||
<script type="module"><?= VV::js("assets/js/pages/about/battlestation") ?></script>
|
4
pages/about/version.php → public/about/version.php
Executable file → Normal file
4
pages/about/version.php → public/about/version.php
Executable file → Normal file
|
@ -7,10 +7,8 @@
|
|||
without any exceptions.
|
||||
*/
|
||||
|
||||
use Vegvisir\Path;
|
||||
|
||||
// Get tags from local git folder
|
||||
$dir = scandir(Path::root(".git/refs/tags"));
|
||||
$dir = scandir(VV::root(".git/refs/tags"));
|
||||
|
||||
// Get current version number from latest tag
|
||||
$version = end($dir);
|
22
pages/contact.php → public/contact.php
Executable file → Normal file
22
pages/contact.php → public/contact.php
Executable file → Normal file
|
@ -7,37 +7,37 @@
|
|||
|
||||
use VLW\API\Databases\VLWdb\Models\Messages\MessagesModel;
|
||||
|
||||
require_once Path::root("src/client/API.php");
|
||||
require_once Path::root("api/src/Endpoints.php");
|
||||
require_once VV::root("src/client/API.php");
|
||||
require_once VV::root("api/src/Endpoints.php");
|
||||
|
||||
require_once Path::root("api/src/databases/models/Messages/Messages.php");
|
||||
require_once VV::root("api/src/databases/models/Messages/Messages.php");
|
||||
|
||||
// Connect to VLW API
|
||||
$api = new API();
|
||||
|
||||
?>
|
||||
<style><?= VV::css("pages/contact") ?></style>
|
||||
<style><?= VV::css("assets/css/pages/contact") ?></style>
|
||||
<section>
|
||||
<h1>Let's chat</h1>
|
||||
<p>The best way to get in touch is by email, or with the form on this page. I will try to reply as quickly as possible, probably within a few hours. The time is <i><?= (new DateTime("now", new DateTimeZone($_ENV["time"]["date_time_zone"])))->format("h:i a") ?></i> in Sweden right now.</p>
|
||||
</section>
|
||||
<section class="social">
|
||||
<a href="mailto:victor@vlw.se"><social>
|
||||
<?= VV::media("icons/email.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/email.svg") ?>
|
||||
<p>e-mail</p>
|
||||
</social></a>
|
||||
<a href="https://mastodon.social/@vlwone"><social>
|
||||
<?= VV::media("icons/mastodon.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/mastodon.svg") ?>
|
||||
<p>mastodon</p>
|
||||
</social></a>
|
||||
<a href="https://web.libera.chat/#vlw.se"><social>
|
||||
<?= VV::media("icons/libera.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/libera.svg") ?>
|
||||
<p>libera.chat</p>
|
||||
</social></a>
|
||||
</section>
|
||||
<?= VV::media("line.svg") ?>
|
||||
<?= VV::embed("assets/media/line.svg") ?>
|
||||
<section class="pgp">
|
||||
<?= VV::media("icons/pin.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/pin.svg") ?>
|
||||
<h3>encrypt your message with my OpenPGP key.</h3>
|
||||
<p>my key is also listed on the <a href="https://keys.openpgp.org/search?q=victor%40vlw.se" target="_blank" rel="noopener noreferer">openPGP key server</a> for victor@vlw.se so your e-mail client can automatically retreive it if supported.</p>
|
||||
<div class="buttons">
|
||||
|
@ -45,7 +45,7 @@
|
|||
<a href="https://emailselfdefense.fsf.org/en/" target="_blank" rel="noopener noreferer"><button class="inline">more info</button></a>
|
||||
</div>
|
||||
</section>
|
||||
<?= VV::media("line.svg") ?>
|
||||
<?= VV::embed("assets/media/line.svg") ?>
|
||||
|
||||
<?php // Send message on POST request ?>
|
||||
<?php if ($_SERVER["REQUEST_METHOD"] === "POST"): ?>
|
||||
|
@ -88,4 +88,4 @@
|
|||
</form>
|
||||
</section>
|
||||
|
||||
<script><?= VV::js("pages/contact") ?></script>
|
||||
<script><?= VV::js("assets/js/pages/contact") ?></script>
|
6
public/error.php
Normal file
6
public/error.php
Normal file
|
@ -0,0 +1,6 @@
|
|||
<style><?= VV::css("assets/css/pages/error") ?></style>
|
||||
<canvas></canvas>
|
||||
<section class="error">
|
||||
<h1 glitch-text><span>4</span><span>0</span><span>4</span></h1>
|
||||
</section>
|
||||
<script type="module"><?= VV::js("assets/js/pages/error") ?></script>
|
10
pages/index.php → public/index.php
Executable file → Normal file
10
pages/index.php → public/index.php
Executable file → Normal file
|
@ -7,20 +7,20 @@
|
|||
}
|
||||
|
||||
?>
|
||||
<style><?= VV::css("pages/index") ?></style>
|
||||
<style><?= VV::css("assets/css/pages/index") ?></style>
|
||||
<div class="menu">
|
||||
<?= VV::media("line.svg") ?>
|
||||
<?= VV::embed("assets/media/line.svg") ?>
|
||||
<menu>
|
||||
<a href="/work" vv="index" vv-call="navigate"><li data-rgb="<?= RGB::WORK->value ?>" data-hue="90">work</li></a>
|
||||
<a href="/about" vv="index" vv-call="navigate"><li data-rgb="<?= RGB::ABOUT->value ?>" data-hue="390">about</li></a>
|
||||
<a href="/contact" vv="index" vv-call="navigate"><li data-rgb="<?= RGB::CONTACT->value ?>" data-hue="200">contact</li></a>
|
||||
</menu>
|
||||
<?= VV::media("line.svg") ?>
|
||||
<button class="email" vv="index" vv-call="copyEmail">
|
||||
<?= VV::embed("assets/media/line.svg") ?>
|
||||
<button class="email">
|
||||
<p>victor@vlw.se</p>
|
||||
<p class="cta">to copy</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<img src="/assets/media/gazing.jpg" alt="A portrait of Victor with a pair of cartoon glasses drawn in the shape of two V's over his eyes"/>
|
||||
<script><?= VV::js("pages/index") ?></script>
|
||||
<script type="module"><?= VV::js("assets/js/pages/index") ?></script>
|
16
pages/search.php → public/search.php
Executable file → Normal file
16
pages/search.php → public/search.php
Executable file → Normal file
|
@ -10,11 +10,11 @@
|
|||
WorkActionsModel
|
||||
};
|
||||
|
||||
require_once Path::root("src/client/API.php");
|
||||
require_once Path::root("api/src/Endpoints.php");
|
||||
require_once VV::root("src/client/API.php");
|
||||
require_once VV::root("api/src/Endpoints.php");
|
||||
|
||||
require_once Path::root("api/src/databases/models/Work/Work.php");
|
||||
require_once Path::root("api/src/databases/models/Work/WorkActions.php");
|
||||
require_once VV::root("api/src/databases/models/Work/Work.php");
|
||||
require_once VV::root("api/src/databases/models/Work/WorkActions.php");
|
||||
|
||||
// Search endpoint query paramter
|
||||
const SEARCH_PARAM = "q";
|
||||
|
@ -26,7 +26,7 @@
|
|||
$response = $api->call(Endpoints::SEARCH->value)->params([SEARCH_PARAM => $_GET[SEARCH_PARAM]])->get();
|
||||
|
||||
?>
|
||||
<style><?= VV::css("pages/search") ?></style>
|
||||
<style><?= VV::css("assets/css/pages/search") ?></style>
|
||||
<section class="search">
|
||||
<form method="GET">
|
||||
<search>
|
||||
|
@ -34,7 +34,7 @@
|
|||
</search>
|
||||
<button type="submit" class="inline solid">Search</button>
|
||||
</form>
|
||||
<?= VV::media("line.svg") ?>
|
||||
<?= VV::embed("assets/media/line.svg") ?>
|
||||
<button class="inline">advanced search options</button>
|
||||
</section>
|
||||
|
||||
|
@ -89,11 +89,11 @@
|
|||
</section>
|
||||
<?php else: ?>
|
||||
<section class="info empty">
|
||||
<?= VV::media("icons/search.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/search.svg") ?>
|
||||
<p>Start typing to search</p>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<script><?= VV::js("pages/search") ?></script>
|
||||
<script><?= VV::js("assets/js/pages/search") ?></script>
|
16
pages/work.php → public/work.php
Executable file → Normal file
16
pages/work.php → public/work.php
Executable file → Normal file
|
@ -11,12 +11,12 @@
|
|||
WorkActionsModel
|
||||
};
|
||||
|
||||
require_once Path::root("src/client/API.php");
|
||||
require_once Path::root("api/src/Endpoints.php");
|
||||
require_once VV::root("src/client/API.php");
|
||||
require_once VV::root("api/src/Endpoints.php");
|
||||
|
||||
require_once Path::root("api/src/databases/models/Work/Work.php");
|
||||
require_once Path::root("api/src/databases/models/Work/WorkTags.php");
|
||||
require_once Path::root("api/src/databases/models/Work/WorkActions.php");
|
||||
require_once VV::root("api/src/databases/models/Work/Work.php");
|
||||
require_once VV::root("api/src/databases/models/Work/WorkTags.php");
|
||||
require_once VV::root("api/src/databases/models/Work/WorkActions.php");
|
||||
|
||||
// Connect to VLW API
|
||||
$api = new API();
|
||||
|
@ -31,10 +31,10 @@
|
|||
}
|
||||
|
||||
?>
|
||||
<style><?= VV::css("pages/work") ?></style>
|
||||
<style><?= VV::css("assets/css/pages/work") ?></style>
|
||||
|
||||
<section class="git">
|
||||
<?= VV::media("icons/github.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/github.svg") ?>
|
||||
<p>Most of my free open-source software is available on GitHub and it's also mirrored on my server</p>
|
||||
<div class="buttons">
|
||||
<a href="https://github.com/victorwesterlund"><button class="inline solid">open GitHub</button></a>
|
||||
|
@ -178,4 +178,4 @@
|
|||
<p>Something went wrong!</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<script><?= VV::js("pages/work") ?></script>
|
||||
<script><?= VV::js("assets/js/pages/work") ?></script>
|
20
pages/document.php → shells/document.php
Executable file → Normal file
20
pages/document.php → shells/document.php
Executable file → Normal file
|
@ -38,8 +38,8 @@
|
|||
</script>
|
||||
|
||||
<?php // Bootstrapping ?>
|
||||
<style><?= VV::css("fonts") ?></style>
|
||||
<style><?= VV::css("document") ?></style>
|
||||
<style><?= VV::css("assets/css/fonts") ?></style>
|
||||
<style><?= VV::css("assets/css/shells/document") ?></style>
|
||||
|
||||
<title>Victor L. Westerlund</title>
|
||||
<link rel="icon" href="/assets/media/vw.svg"/>
|
||||
|
@ -49,28 +49,28 @@
|
|||
<nav>
|
||||
<p><a href="/" vv="document" vv-call="navigate">victor westerlund</a></p>
|
||||
</nav>
|
||||
<button class="search" vv="document" vv-call="openSearchbox">
|
||||
<?= VV::media("icons/search.svg") ?>
|
||||
<button class="search searchbox-open">
|
||||
<?= VV::embed("assets/media/icons/search.svg") ?>
|
||||
<p>search vlw.se...</p>
|
||||
</button>
|
||||
<button class="logo" vv="document" vv-call="navigateHome"><?= VV::media("vw.svg") ?></button>
|
||||
<button class="logo" vv="/"><?= VV::embed("assets/media/vw.svg") ?></button>
|
||||
<searchbox>
|
||||
<input type="search" autocomplete="off" placeholder="search vlw.se...">
|
||||
<button class="close" vv="document" vv-call="closeSearchbox"><?= VV::media("icons/close.svg") ?></button>
|
||||
<button class="close searchbox-close"><?= VV::embed("assets/media/icons/close.svg") ?></button>
|
||||
</searchbox>
|
||||
</header>
|
||||
|
||||
<main></main>
|
||||
<vv-shell></vv-shell>
|
||||
|
||||
<search-results>
|
||||
<div class="info empty">
|
||||
<?= VV::media("icons/search.svg") ?>
|
||||
<?= VV::embed("assets/media/icons/search.svg") ?>
|
||||
<p>start typing to search</p>
|
||||
</div>
|
||||
</search-results>
|
||||
|
||||
<?php // Bootstrapping ?>
|
||||
<script><?= VV::init() ?></script>
|
||||
<script><?= VV::js("document") ?></script>
|
||||
<?= VV::init() ?>
|
||||
<script type="module"><?= VV::js("assets/js/shells/document") ?></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue