mirror of
https://codeberg.org/vlw/vlw.se.git
synced 2025-09-14 05:13:46 +02:00
wip: 2024-11-21T08:42:36+0100 (1732174956)
This commit is contained in:
parent
ff7d4f5397
commit
30cbff10eb
8 changed files with 412 additions and 280 deletions
|
@ -3,6 +3,9 @@
|
|||
:root {
|
||||
--primer-color-accent: 3, 255, 219;
|
||||
--color-accent: rgb(var(--primer-color-accent));
|
||||
|
||||
--color-reflect: 220, 26, 0;
|
||||
--color-vegvisir: 0, 128, 255;
|
||||
}
|
||||
|
||||
vv-shell {
|
||||
|
@ -38,95 +41,85 @@ section.git .buttons {
|
|||
gap: var(--padding);
|
||||
}
|
||||
|
||||
/* ## Timeline */
|
||||
/* ## Hero */
|
||||
|
||||
section.timeline {
|
||||
--timestamp-gap: calc(var(--padding) / 2);
|
||||
section.hero {
|
||||
--color-accent: rgba(255, 255, 255);
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section.timeline :is(.year, .month, .day) {
|
||||
display: grid;
|
||||
grid-template-columns: calc(40px + var(--timestamp-gap)) 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
gap: var(--padding);
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
section.timeline .track {
|
||||
--opacity: .15;
|
||||
--width: 2%;
|
||||
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%, transparent calc(50% - var(--width)),
|
||||
rgba(255, 255, 255, var(--opacity)) calc(50% - var(--width)), rgba(255, 255, 255, var(--opacity)) calc(50% + var(--width)),
|
||||
transparent calc(50% + var(--width)), transparent 100%
|
||||
);
|
||||
section.hero .item {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
position: relative;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 0 0 2px white;
|
||||
}
|
||||
|
||||
section.timeline .track p {
|
||||
position: sticky;
|
||||
top: calc(var(--running-size) + var(--padding));
|
||||
padding: calc(var(--padding) / 2) 0;
|
||||
background-color: black;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
section.timeline :not(.year) > .track p::before {
|
||||
content: "/ ";
|
||||
color: rgba(255, 255, 255, .3);
|
||||
}
|
||||
|
||||
/* ### Item */
|
||||
|
||||
section.timeline .items .item {
|
||||
section.hero .wrapper {
|
||||
z-index: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: baseline;
|
||||
flex-direction: column;
|
||||
gap: calc(var(--padding) / 2);
|
||||
padding: var(--padding);
|
||||
padding: calc(var(--padding) * 1.5);
|
||||
}
|
||||
|
||||
section.timeline .items .item + .item {
|
||||
border-top: solid 2px rgba(255, 255, 255, .2);
|
||||
section.hero p {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
section.timeline .items .item:first-of-type {
|
||||
margin-top: var(--padding);
|
||||
border-top: solid 2px var(--color-accent);
|
||||
section.hero button {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
/* No border style for the latest item (from the top) in the list */
|
||||
section.timeline .year:first-of-type .month:first-of-type .day:first-of-type .items .item:first-of-type {
|
||||
margin-top: unset;
|
||||
border-top: unset;
|
||||
/* ### Vegivisr */
|
||||
|
||||
section.hero .item.vegvisir {
|
||||
background-color: rgb(var(--color-vegvisir));
|
||||
}
|
||||
|
||||
section.timeline .items .item .tags {
|
||||
/* ### Reflect */
|
||||
|
||||
section.hero .item.reflect {
|
||||
background: linear-gradient(0deg, rgba(215,31,5,1) 0%, rgba(233,102,102,1) 49%, rgba(251,251,251,1) 49%, rgba(215,31,5,1) 50%, rgba(215,31,5,1) 100%);
|
||||
}
|
||||
|
||||
/* ### Background */
|
||||
|
||||
section.hero .item .bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
section.hero .item video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/* ## Heading */
|
||||
|
||||
section.heading {
|
||||
display: flex;
|
||||
gap: calc(var(--padding) / 2);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
section.timeline .items .item .tags .tag {
|
||||
font-size: 11px;
|
||||
letter-spacing: 1px;
|
||||
color: rgba(255, 255, 255, .7);
|
||||
background-color: rgba(255, 255, 255, .15);
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
section.timeline .items .item img {
|
||||
max-width: 100%;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
section.timeline .items .item .actions {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
/* ## Note */
|
||||
|
||||
section.note {
|
||||
text-align: center;
|
||||
section.heading svg {
|
||||
fill: white;
|
||||
height: 2em;
|
||||
}
|
||||
|
||||
/* # Size queries */
|
||||
|
@ -153,42 +146,3 @@ section.note {
|
|||
justify-content: end;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
section.timeline {
|
||||
padding: unset;
|
||||
}
|
||||
|
||||
section.timeline .track {
|
||||
position: relative;
|
||||
background: unset;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
section.timeline .track p {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
section.timeline :is(.years, .year, .months, .month, .days, .day) {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
section.timeline .items {
|
||||
position: relative;
|
||||
left: -140px;
|
||||
}
|
||||
|
||||
section.timeline .items .item {
|
||||
padding: calc(var(--padding) * 1.5) 0;
|
||||
width: calc(100vw - (var(--padding) * 3.5));
|
||||
}
|
||||
|
||||
section.timeline .items .item:first-of-type {
|
||||
border-top-color: rgba(var(--primer-color-accent), .2);
|
||||
}
|
||||
|
||||
section.timeline .year:first-of-type .month:first-of-type .day:first-of-type .items .item:first-of-type {
|
||||
margin-top: var(--padding);
|
||||
}
|
||||
}
|
147
public/assets/css/pages/work/timeline.css
Normal file
147
public/assets/css/pages/work/timeline.css
Normal file
|
@ -0,0 +1,147 @@
|
|||
/* # Overrides */
|
||||
|
||||
:root {
|
||||
--primer-color-accent: 3, 255, 219;
|
||||
--color-accent: rgb(var(--primer-color-accent));
|
||||
}
|
||||
|
||||
vv-shell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--padding);
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
overflow-x: initial;
|
||||
}
|
||||
|
||||
/* # Sections */
|
||||
|
||||
/* ## Timeline */
|
||||
|
||||
section.timeline {
|
||||
--timestamp-gap: calc(var(--padding) / 2);
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section.timeline :is(.year, .month, .day) {
|
||||
display: grid;
|
||||
grid-template-columns: calc(40px + var(--timestamp-gap)) 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
section.timeline .track {
|
||||
--opacity: .15;
|
||||
--width: 2%;
|
||||
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%, transparent calc(50% - var(--width)),
|
||||
rgba(255, 255, 255, var(--opacity)) calc(50% - var(--width)), rgba(255, 255, 255, var(--opacity)) calc(50% + var(--width)),
|
||||
transparent calc(50% + var(--width)), transparent 100%
|
||||
);
|
||||
}
|
||||
|
||||
section.timeline .track p {
|
||||
position: sticky;
|
||||
top: calc(var(--running-size) + var(--padding));
|
||||
padding: calc(var(--padding) / 2) 0;
|
||||
background-color: black;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
section.timeline :not(.year) > .track p::before {
|
||||
content: "/ ";
|
||||
color: rgba(255, 255, 255, .3);
|
||||
}
|
||||
|
||||
/* ### Item */
|
||||
|
||||
section.timeline .items .item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(var(--padding) / 2);
|
||||
padding: var(--padding);
|
||||
}
|
||||
|
||||
section.timeline .items .item + .item {
|
||||
border-top: solid 2px rgba(255, 255, 255, .2);
|
||||
}
|
||||
|
||||
section.timeline .items .item:first-of-type {
|
||||
margin-top: var(--padding);
|
||||
border-top: solid 2px var(--color-accent);
|
||||
}
|
||||
|
||||
/* No border style for the latest item (from the top) in the list */
|
||||
section.timeline .year:first-of-type .month:first-of-type .day:first-of-type .items .item:first-of-type {
|
||||
margin-top: unset;
|
||||
border-top: unset;
|
||||
}
|
||||
|
||||
section.timeline .items .item .tags {
|
||||
display: flex;
|
||||
gap: calc(var(--padding) / 2);
|
||||
}
|
||||
|
||||
section.timeline .items .item .tags .tag {
|
||||
font-size: 11px;
|
||||
letter-spacing: 1px;
|
||||
color: rgba(255, 255, 255, .7);
|
||||
background-color: rgba(255, 255, 255, .15);
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
section.timeline .items .item img {
|
||||
max-width: 100%;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
section.timeline .items .item .actions {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
/* ## Note */
|
||||
|
||||
section.note {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
section.timeline {
|
||||
padding: unset;
|
||||
}
|
||||
|
||||
section.timeline .track {
|
||||
position: relative;
|
||||
background: unset;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
section.timeline .track p {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
section.timeline :is(.years, .year, .months, .month, .days, .day) {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
section.timeline .items {
|
||||
position: relative;
|
||||
left: -140px;
|
||||
}
|
||||
|
||||
section.timeline .items .item {
|
||||
padding: calc(var(--padding) * 1.5) 0;
|
||||
width: calc(100vw - (var(--padding) * 3.5));
|
||||
}
|
||||
|
||||
section.timeline .items .item:first-of-type {
|
||||
border-top-color: rgba(var(--primer-color-accent), .2);
|
||||
}
|
||||
|
||||
section.timeline .year:first-of-type .month:first-of-type .day:first-of-type .items .item:first-of-type {
|
||||
margin-top: var(--padding);
|
||||
}
|
||||
}
|
|
@ -285,6 +285,7 @@ search-results {
|
|||
transform: scale(.99);
|
||||
transform-origin: 100% 0;
|
||||
overflow-y: scroll;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
search-results:not([vv-page]) {
|
||||
|
|
1
public/assets/media/icons/star.svg
Normal file
1
public/assets/media/icons/star.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 5.1 KiB |
BIN
public/assets/media/vegvisir.webm
Normal file
BIN
public/assets/media/vegvisir.webm
Normal file
Binary file not shown.
202
public/work.php
202
public/work.php
|
@ -1,38 +1,4 @@
|
|||
<?php
|
||||
|
||||
use Vegvisir\Path;
|
||||
|
||||
use VLW\Client\API;
|
||||
use VLW\API\Endpoints;
|
||||
|
||||
use VLW\API\Databases\VLWdb\Models\Work\{
|
||||
WorkModel,
|
||||
WorkTagsModel,
|
||||
WorkActionsModel
|
||||
};
|
||||
|
||||
require_once VV::root("src/client/API.php");
|
||||
require_once VV::root("api/src/Endpoints.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();
|
||||
|
||||
// Retreive rows from work endpoints
|
||||
$resp_work = $api->call(Endpoints::WORK->value)->get();
|
||||
|
||||
// Resolve tags and actions if we got work results
|
||||
if ($resp_work->ok) {
|
||||
$work_tags = $api->call(Endpoints::WORK_TAGS->value)->get()->json();
|
||||
$work_actions = $api->call(Endpoints::WORK_ACTIONS->value)->get()->json();
|
||||
}
|
||||
|
||||
?>
|
||||
<style><?= VV::css("public/assets/css/pages/work") ?></style>
|
||||
|
||||
<section class="git">
|
||||
<?= VV::embed("public/assets/media/icons/codeberg.svg") ?>
|
||||
<p>I have moved most of my free open-source software <a href="https://giveupgithub.com">away from GitHub</a> to <a href="https://codeberg.org/vlw">Codeberg</a>. I also have a mirror of everything and sources for some smaller projects on <a href="https://git.vlw.se">Forgejo</a>.</p>
|
||||
|
@ -41,141 +7,33 @@
|
|||
<a href="https://git.vlw.se"><button class="inline">Forgejo</button></a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php if ($resp_work->ok): ?>
|
||||
<?php
|
||||
|
||||
/*
|
||||
Order response from endpoint into a multi-dimensional array.
|
||||
For example, a single item created at 14th of February 2024 would be ordered like this
|
||||
[2024 => [[02 => [14 => [<row_data>]]]]]
|
||||
*/
|
||||
|
||||
$rows = [];
|
||||
// Create array of arrays ordered by decending year, month, day, items
|
||||
foreach ($resp_work->json() as $row) {
|
||||
// Create array for current year if it doesn't exist
|
||||
if (!array_key_exists($row[WorkModel::DATE_YEAR->value], $rows)) {
|
||||
$rows[$row[WorkModel::DATE_YEAR->value]] = [];
|
||||
}
|
||||
|
||||
// Create array for current month if it doesn't exist
|
||||
if (!array_key_exists($row[WorkModel::DATE_MONTH->value], $rows[$row[WorkModel::DATE_YEAR->value]])) {
|
||||
$rows[$row[WorkModel::DATE_YEAR->value]][$row[WorkModel::DATE_MONTH->value]] = [];
|
||||
}
|
||||
|
||||
// Create array for current day if it doesn't exist
|
||||
if (!array_key_exists($row[WorkModel::DATE_DAY->value], $rows[$row[WorkModel::DATE_YEAR->value]][$row[WorkModel::DATE_MONTH->value]])) {
|
||||
$rows[$row[WorkModel::DATE_YEAR->value]][$row[WorkModel::DATE_MONTH->value]][$row[WorkModel::DATE_DAY->value]] = [];
|
||||
}
|
||||
|
||||
// Append item to ordered array
|
||||
$rows[$row[WorkModel::DATE_YEAR->value]][$row[WorkModel::DATE_MONTH->value]][$row[WorkModel::DATE_DAY->value]][] = $row;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<section class="timeline">
|
||||
<?php // Get year int from key and array of months for current year ?>
|
||||
<?php foreach($rows as $year => $months): ?>
|
||||
<div class="year">
|
||||
<div class="track">
|
||||
<p><?= $year ?></p>
|
||||
</div>
|
||||
|
||||
<div class="months">
|
||||
<?php // Get month int from key and array of days for current month ?>
|
||||
<?php foreach($months as $month => $days): ?>
|
||||
<div class="month">
|
||||
<div class="track">
|
||||
<?php // Append leading zero to month ?>
|
||||
<p><?= sprintf("%02d", $month) ?></p>
|
||||
</div>
|
||||
|
||||
<div class="days">
|
||||
<?php // Get day int from key and array of items for current day ?>
|
||||
<?php foreach($days as $day => $items): ?>
|
||||
<div class="day">
|
||||
<div class="track">
|
||||
<?php // Append leading zero to day ?>
|
||||
<p><?= sprintf("%02d", $day) ?></p>
|
||||
</div>
|
||||
|
||||
<div class="items">
|
||||
<?php foreach($items as $item): ?>
|
||||
<div class="item">
|
||||
|
||||
<?php // Get array index ids from tags array where work entity id matches ref_work_id ?>
|
||||
<?php $tag_ids = array_keys(array_column($work_tags, WorkTagsModel::REF_WORK_ID->value), $item[WorkModel::ID->value]); ?>
|
||||
|
||||
<?php // List tags if available ?>
|
||||
<?php if($tag_ids): ?>
|
||||
<div class="tags">
|
||||
<?php foreach($tag_ids as $tag_id): ?>
|
||||
<?php // Get tag details from tag array by index id ?>
|
||||
<?php $tag = $work_tags[$tag_id]; ?>
|
||||
|
||||
<p class="tag <?= $tag[WorkTagsModel::NAME->value] ?>"><?= $tag[WorkTagsModel::NAME->value] ?></p>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Show large heading if defined ?>
|
||||
<?php if (!empty($item[WorkModel::TITLE->value])): ?>
|
||||
<h2><?= $item[WorkModel::TITLE->value] ?></h2>
|
||||
<?php endif; ?>
|
||||
|
||||
<p><?= $item[WorkModel::SUMMARY->value] ?></p>
|
||||
|
||||
<?php // Get array index ids from actions array where work entity id matches ref_work_id ?>
|
||||
<?php $action_ids = array_keys(array_column($work_actions, WorkTagsModel::REF_WORK_ID->value), $item[WorkModel::ID->value]); ?>
|
||||
|
||||
<?php // List actions if defined for item ?>
|
||||
<?php if($action_ids): ?>
|
||||
<div class="actions">
|
||||
<?php foreach($action_ids as $action_id): ?>
|
||||
<?php
|
||||
// Get tag details from tag array by index id
|
||||
$action = $work_actions[$action_id];
|
||||
|
||||
$link_attr = !$action[WorkActionsModel::EXTERNAL->value]
|
||||
// Bind VV Interactions for local links
|
||||
? "vv='work' vv-call='navigate'"
|
||||
// Open external links in a new tab
|
||||
: "target='_blank'";
|
||||
|
||||
$link_href = $action[WorkActionsModel::HREF->value] === null
|
||||
// Navigate to work details page if no href is defined
|
||||
? "/work/{$item[WorkModel::ID->value]}"
|
||||
// Href is defined so use it directly
|
||||
: $action[WorkActionsModel::HREF->value];
|
||||
?>
|
||||
|
||||
<a href="<?= $link_href ?>" <?= $link_attr ?>><button class="inline <?= $action["class_list"] ?>"><?= $action["display_text"] ?></button></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</section>
|
||||
<section class="note">
|
||||
<p>This is not really the end of the list. I will add some of my notable older work at some point.</p>
|
||||
</section>
|
||||
<?php else: ?>
|
||||
<p>Something went wrong!</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<script><?= VV::js("assets/js/pages/work") ?></script>
|
||||
<section class="hero">
|
||||
<div class="item vegvisir">
|
||||
<div class="wrapper">
|
||||
<h1>Vegvisir</h1>
|
||||
<p>A PHP and JavaScript navigation framework for the seamless [open] web seas.</p>
|
||||
<a href=""><button class="inline">Read more</button></a>
|
||||
</div>
|
||||
<div class="bg">
|
||||
<video muted autoplay loop src="/assets/media/vegvisir.webm"></video>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item reflect">
|
||||
<div class="wrapper">
|
||||
<h1>Reflect</h1>
|
||||
<p>A strange framework for building REST APIs in PHP.</p>
|
||||
<a href=""><button class="inline">Read more</button></a>
|
||||
</div>
|
||||
<div class="bg"></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="heading">
|
||||
<?= VV::embed("public/assets/media/icons/star.svg") ?>
|
||||
<h1>Featured</h1>
|
||||
<?= VV::embed("public/assets/media/icons/star.svg") ?>
|
||||
</section>
|
||||
<section class="heading">
|
||||
<a href="/work/timeline"><button class="inline">
|
||||
<p>View timeline</p>
|
||||
</button></a>
|
||||
</section>
|
171
public/work/timeline.php
Normal file
171
public/work/timeline.php
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
use Vegvisir\Path;
|
||||
|
||||
use VLW\Client\API;
|
||||
use VLW\API\Endpoints;
|
||||
|
||||
use VLW\API\Databases\VLWdb\Models\Work\{
|
||||
WorkModel,
|
||||
WorkTagsModel,
|
||||
WorkActionsModel
|
||||
};
|
||||
|
||||
require_once VV::root("src/client/API.php");
|
||||
require_once VV::root("api/src/Endpoints.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();
|
||||
|
||||
// Retreive rows from work endpoints
|
||||
$resp_work = $api->call(Endpoints::WORK->value)->get();
|
||||
|
||||
// Resolve tags and actions if we got work results
|
||||
if ($resp_work->ok) {
|
||||
$work_tags = $api->call(Endpoints::WORK_TAGS->value)->get()->json();
|
||||
$work_actions = $api->call(Endpoints::WORK_ACTIONS->value)->get()->json();
|
||||
}
|
||||
|
||||
?>
|
||||
<style><?= VV::css("public/assets/css/pages/work/timeline") ?></style>
|
||||
|
||||
<?php if ($resp_work->ok): ?>
|
||||
<?php
|
||||
|
||||
/*
|
||||
Order response from endpoint into a multi-dimensional array.
|
||||
For example, a single item created at 14th of February 2024 would be ordered like this
|
||||
[2024 => [[02 => [14 => [<row_data>]]]]]
|
||||
*/
|
||||
|
||||
$rows = [];
|
||||
// Create array of arrays ordered by decending year, month, day, items
|
||||
foreach ($resp_work->json() as $row) {
|
||||
// Create array for current year if it doesn't exist
|
||||
if (!array_key_exists($row[WorkModel::DATE_YEAR->value], $rows)) {
|
||||
$rows[$row[WorkModel::DATE_YEAR->value]] = [];
|
||||
}
|
||||
|
||||
// Create array for current month if it doesn't exist
|
||||
if (!array_key_exists($row[WorkModel::DATE_MONTH->value], $rows[$row[WorkModel::DATE_YEAR->value]])) {
|
||||
$rows[$row[WorkModel::DATE_YEAR->value]][$row[WorkModel::DATE_MONTH->value]] = [];
|
||||
}
|
||||
|
||||
// Create array for current day if it doesn't exist
|
||||
if (!array_key_exists($row[WorkModel::DATE_DAY->value], $rows[$row[WorkModel::DATE_YEAR->value]][$row[WorkModel::DATE_MONTH->value]])) {
|
||||
$rows[$row[WorkModel::DATE_YEAR->value]][$row[WorkModel::DATE_MONTH->value]][$row[WorkModel::DATE_DAY->value]] = [];
|
||||
}
|
||||
|
||||
// Append item to ordered array
|
||||
$rows[$row[WorkModel::DATE_YEAR->value]][$row[WorkModel::DATE_MONTH->value]][$row[WorkModel::DATE_DAY->value]][] = $row;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<section class="timeline">
|
||||
<?php // Get year int from key and array of months for current year ?>
|
||||
<?php foreach($rows as $year => $months): ?>
|
||||
<div class="year">
|
||||
<div class="track">
|
||||
<p><?= $year ?></p>
|
||||
</div>
|
||||
|
||||
<div class="months">
|
||||
<?php // Get month int from key and array of days for current month ?>
|
||||
<?php foreach($months as $month => $days): ?>
|
||||
<div class="month">
|
||||
<div class="track">
|
||||
<?php // Append leading zero to month ?>
|
||||
<p><?= sprintf("%02d", $month) ?></p>
|
||||
</div>
|
||||
|
||||
<div class="days">
|
||||
<?php // Get day int from key and array of items for current day ?>
|
||||
<?php foreach($days as $day => $items): ?>
|
||||
<div class="day">
|
||||
<div class="track">
|
||||
<?php // Append leading zero to day ?>
|
||||
<p><?= sprintf("%02d", $day) ?></p>
|
||||
</div>
|
||||
|
||||
<div class="items">
|
||||
<?php foreach($items as $item): ?>
|
||||
<div class="item">
|
||||
|
||||
<?php // Get array index ids from tags array where work entity id matches ref_work_id ?>
|
||||
<?php $tag_ids = array_keys(array_column($work_tags, WorkTagsModel::REF_WORK_ID->value), $item[WorkModel::ID->value]); ?>
|
||||
|
||||
<?php // List tags if available ?>
|
||||
<?php if($tag_ids): ?>
|
||||
<div class="tags">
|
||||
<?php foreach($tag_ids as $tag_id): ?>
|
||||
<?php // Get tag details from tag array by index id ?>
|
||||
<?php $tag = $work_tags[$tag_id]; ?>
|
||||
|
||||
<p class="tag <?= $tag[WorkTagsModel::NAME->value] ?>"><?= $tag[WorkTagsModel::NAME->value] ?></p>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Show large heading if defined ?>
|
||||
<?php if (!empty($item[WorkModel::TITLE->value])): ?>
|
||||
<h2><?= $item[WorkModel::TITLE->value] ?></h2>
|
||||
<?php endif; ?>
|
||||
|
||||
<p><?= $item[WorkModel::SUMMARY->value] ?></p>
|
||||
|
||||
<?php // Get array index ids from actions array where work entity id matches ref_work_id ?>
|
||||
<?php $action_ids = array_keys(array_column($work_actions, WorkTagsModel::REF_WORK_ID->value), $item[WorkModel::ID->value]); ?>
|
||||
|
||||
<?php // List actions if defined for item ?>
|
||||
<?php if($action_ids): ?>
|
||||
<div class="actions">
|
||||
<?php foreach($action_ids as $action_id): ?>
|
||||
<?php
|
||||
// Get tag details from tag array by index id
|
||||
$action = $work_actions[$action_id];
|
||||
|
||||
$link_attr = !$action[WorkActionsModel::EXTERNAL->value]
|
||||
// Bind VV Interactions for local links
|
||||
? "vv='work' vv-call='navigate'"
|
||||
// Open external links in a new tab
|
||||
: "target='_blank'";
|
||||
|
||||
$link_href = $action[WorkActionsModel::HREF->value] === null
|
||||
// Navigate to work details page if no href is defined
|
||||
? "/work/{$item[WorkModel::ID->value]}"
|
||||
// Href is defined so use it directly
|
||||
: $action[WorkActionsModel::HREF->value];
|
||||
?>
|
||||
|
||||
<a href="<?= $link_href ?>" <?= $link_attr ?>><button class="inline <?= $action["class_list"] ?>"><?= $action["display_text"] ?></button></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</section>
|
||||
<section class="note">
|
||||
<p>This is not really the end of the list. I will add some of my notable older work at some point.</p>
|
||||
</section>
|
||||
<?php else: ?>
|
||||
<p>Something went wrong!</p>
|
||||
<?php endif; ?>
|
||||
<script><?= VV::js("assets/js/pages/work/timeline") ?></script>
|
Loading…
Add table
Reference in a new issue