mirror of
https://codeberg.org/VnPower/PixivFE
synced 2024-12-06 19:16:23 +01:00
rm prefetch and use htmx preload extension
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
// This adds the "preload" extension to htmx. By default, this will
|
||||
// preload the targets of any tags with `href` or `hx-get` attributes
|
||||
// if they also have a `preload` attribute as well. See documentation
|
||||
// for more details
|
||||
htmx.defineExtension('preload', {
|
||||
|
||||
onEvent: function(name, event) {
|
||||
// Only take actions on "htmx:afterProcessNode"
|
||||
if (name !== 'htmx:afterProcessNode') {
|
||||
return
|
||||
}
|
||||
|
||||
// SOME HELPER FUNCTIONS WE'LL NEED ALONG THE WAY
|
||||
|
||||
// attr gets the closest non-empty value from the attribute.
|
||||
var attr = function(node, property) {
|
||||
if (node == undefined) { return undefined }
|
||||
return node.getAttribute(property) || node.getAttribute('data-' + property) || attr(node.parentElement, property)
|
||||
}
|
||||
|
||||
// load handles the actual HTTP fetch, and uses htmx.ajax in cases where we're
|
||||
// preloading an htmx resource (this sends the same HTTP headers as a regular htmx request)
|
||||
var load = function(node) {
|
||||
// Called after a successful AJAX request, to mark the
|
||||
// content as loaded (and prevent additional AJAX calls.)
|
||||
var done = function(html) {
|
||||
if (!node.preloadAlways) {
|
||||
node.preloadState = 'DONE'
|
||||
}
|
||||
|
||||
if (attr(node, 'preload-images') == 'true') {
|
||||
document.createElement('div').innerHTML = html // create and populate a node to load linked resources, too.
|
||||
}
|
||||
}
|
||||
|
||||
return function() {
|
||||
// If this value has already been loaded, then do not try again.
|
||||
if (node.preloadState !== 'READY') {
|
||||
return
|
||||
}
|
||||
|
||||
// Special handling for HX-GET - use built-in htmx.ajax function
|
||||
// so that headers match other htmx requests, then set
|
||||
// node.preloadState = TRUE so that requests are not duplicated
|
||||
// in the future
|
||||
var hxGet = node.getAttribute('hx-get') || node.getAttribute('data-hx-get')
|
||||
if (hxGet) {
|
||||
htmx.ajax('GET', hxGet, {
|
||||
source: node,
|
||||
handler: function(elt, info) {
|
||||
done(info.xhr.responseText)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, perform a standard xhr request, then set
|
||||
// node.preloadState = TRUE so that requests are not duplicated
|
||||
// in the future.
|
||||
if (node.getAttribute('href')) {
|
||||
var r = new XMLHttpRequest()
|
||||
r.open('GET', node.getAttribute('href'))
|
||||
r.onload = function() { done(r.responseText) }
|
||||
r.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function processes a specific node and sets up event handlers.
|
||||
// We'll search for nodes and use it below.
|
||||
var init = function(node) {
|
||||
// If this node DOES NOT include a "GET" transaction, then there's nothing to do here.
|
||||
if (node.getAttribute('href') + node.getAttribute('hx-get') + node.getAttribute('data-hx-get') == '') {
|
||||
return
|
||||
}
|
||||
|
||||
// Guarantee that we only initialize each node once.
|
||||
if (node.preloadState !== undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get event name from config.
|
||||
var on = attr(node, 'preload') || 'mousedown'
|
||||
const always = on.indexOf('always') !== -1
|
||||
if (always) {
|
||||
on = on.replace('always', '').trim()
|
||||
}
|
||||
|
||||
// FALL THROUGH to here means we need to add an EventListener
|
||||
|
||||
// Apply the listener to the node
|
||||
node.addEventListener(on, function(evt) {
|
||||
if (node.preloadState === 'PAUSE') { // Only add one event listener
|
||||
node.preloadState = 'READY' // Required for the `load` function to trigger
|
||||
|
||||
// Special handling for "mouseover" events. Wait 100ms before triggering load.
|
||||
if (on === 'mouseover') {
|
||||
window.setTimeout(load(node), 100)
|
||||
} else {
|
||||
load(node)() // all other events trigger immediately.
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Special handling for certain built-in event handlers
|
||||
switch (on) {
|
||||
case 'mouseover':
|
||||
// Mirror `touchstart` events (fires immediately)
|
||||
node.addEventListener('touchstart', load(node))
|
||||
|
||||
// WHhen the mouse leaves, immediately disable the preload
|
||||
node.addEventListener('mouseout', function(evt) {
|
||||
if ((evt.target === node) && (node.preloadState === 'READY')) {
|
||||
node.preloadState = 'PAUSE'
|
||||
}
|
||||
})
|
||||
break
|
||||
|
||||
case 'mousedown':
|
||||
// Mirror `touchstart` events (fires immediately)
|
||||
node.addEventListener('touchstart', load(node))
|
||||
break
|
||||
}
|
||||
|
||||
// Mark the node as ready to run.
|
||||
node.preloadState = 'PAUSE'
|
||||
node.preloadAlways = always
|
||||
htmx.trigger(node, 'preload:init') // This event can be used to load content immediately.
|
||||
}
|
||||
|
||||
// Search for all child nodes that have a "preload" attribute
|
||||
const parent = event.target || event.detail.elt;
|
||||
parent.querySelectorAll("[preload]").forEach(function(node) {
|
||||
// Initialize the node with the "preload" attribute
|
||||
init(node)
|
||||
|
||||
// Initialize all child elements that are anchors or have `hx-get` (use with care)
|
||||
node.querySelectorAll('a,[hx-get],[data-hx-get]').forEach(init)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -3,7 +3,9 @@
|
||||
{{- block body() }}
|
||||
|
||||
<!-- Prefetch links -->
|
||||
{*
|
||||
<link rel="prefetch" href="/users/{{ .Illust.User.ID }}">
|
||||
*}
|
||||
|
||||
<div class="row justify-content-center g-4">
|
||||
<!-- col-md-9 to ensure that artworks don't take forever to scroll past, especially if there are multiple, but col-12 to display artworks at full width on small devices -->
|
||||
@@ -17,10 +19,17 @@
|
||||
<div class="custom-card bg-charcoal-surface1 py-3 px-4">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="/users/{{ .Illust.User.ID }}">
|
||||
<a
|
||||
href="/users/{{ .Illust.User.ID }}"
|
||||
preload="mousedown"
|
||||
>
|
||||
<img src="{{ .Illust.User.Avatar }}" alt="{{ .Illust.User.Name }}" class="rounded-circle object-fit-cover me-3" style="width: 48px; height: 48px;">
|
||||
</a>
|
||||
<a href="/users/{{ .Illust.User.ID }}" class="text-body">
|
||||
<a
|
||||
href="/users/{{ .Illust.User.ID }}"
|
||||
class="text-body"
|
||||
preload="mousedown"
|
||||
>
|
||||
<h2 class="m-0">{{ .Illust.User.Name }}</h2>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
{{- block body() }}
|
||||
|
||||
<!-- Prefetch links -->
|
||||
{*
|
||||
<link rel="prefetch" href="/users/{{ .Artworks[0].UserID }}">
|
||||
*}
|
||||
|
||||
{{- range .Artworks }}
|
||||
<div class="row justify-content-center g-4">
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
{{- if activeIndex > 0 }}
|
||||
<div class="col-12 d-flex justify-content-center">
|
||||
<a class="nav-link d-inline text-center text-body-secondary fw-semibold"
|
||||
href="{{ baseURL }}{{paths[activeIndex-1]}}">
|
||||
href="{{ baseURL }}{{paths[activeIndex-1]}}"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ names[activeIndex-1] }}
|
||||
</a>
|
||||
</div>
|
||||
@@ -29,7 +31,9 @@
|
||||
{{- if activeIndex < len(paths) - 1 }}
|
||||
<div class="col-12 d-flex justify-content-center">
|
||||
<a class="nav-link d-inline text-center text-body-secondary fw-semibold"
|
||||
href="{{ baseURL }}{{paths[activeIndex+1]}}">
|
||||
href="{{ baseURL }}{{paths[activeIndex+1]}}"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ names[activeIndex+1] }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
<ul class="dropdown-menu">
|
||||
{{ range data.DropdownPages }}
|
||||
{{ if .Number == data.CurrentPage }}
|
||||
<li><a class="dropdown-item active" href="{{ .URL }}">{{ .Number }}</a></li>
|
||||
<li><a class="dropdown-item active" href="{{ .URL }}" preload="mousedown">{{ .Number }}</a></li>
|
||||
{{ else }}
|
||||
<li><a class="dropdown-item" href="{{ .URL }}">{{ .Number }}</a></li>
|
||||
<li><a class="dropdown-item" href="{{ .URL }}" preload="mousedown">{{ .Number }}</a></li>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</ul>
|
||||
@@ -23,14 +23,14 @@
|
||||
<ul class="pagination mb-0">
|
||||
<!-- Previous page button -->
|
||||
{{ if data.HasPrevious }}
|
||||
<li class="page-item"><a class="page-link" href="{{ data.PreviousURL }}">Previous</a></li>
|
||||
<li class="page-item"><a class="page-link" href="{{ data.PreviousURL }}" preload="mousedown">Previous</a></li>
|
||||
{{ else }}
|
||||
<li class="page-item disabled"><span class="page-link">Previous</span></li>
|
||||
{{ end }}
|
||||
|
||||
<!-- First page and ellipsis (if needed) -->
|
||||
{{ if data.Pages[0].Number > 1 }}
|
||||
<li class="page-item"><a class="page-link" href="{{ data.FirstURL }}">1</a></li>
|
||||
<li class="page-item"><a class="page-link" href="{{ data.FirstURL }}" preload="mousedown">1</a></li>
|
||||
{{ if data.Pages[0].Number > 2 }}
|
||||
<li class="page-item disabled"><span class="page-link">...</span></li>
|
||||
{{ end }}
|
||||
@@ -41,7 +41,7 @@
|
||||
{{ if .Number == data.CurrentPage }}
|
||||
<li class="page-item active"><span class="page-link">{{ .Number }}</span></li>
|
||||
{{ else }}
|
||||
<li class="page-item"><a class="page-link" href="{{ .URL }}">{{ .Number }}</a></li>
|
||||
<li class="page-item"><a class="page-link" href="{{ .URL }}" preload="mousedown">{{ .Number }}</a></li>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
@@ -51,13 +51,13 @@
|
||||
{{ if data.LastPage < data.MaxPage - 1 }}
|
||||
<li class="page-item disabled"><span class="page-link">...</span></li>
|
||||
{{ end }}
|
||||
<li class="page-item"><a class="page-link" href="{{ data.LastURL }}">{{ data.MaxPage }}</a></li>
|
||||
<li class="page-item"><a class="page-link" href="{{ data.LastURL }}" preload="mousedown">{{ data.MaxPage }}</a></li>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Next page button -->
|
||||
{{ if data.HasNext }}
|
||||
<li class="page-item"><a class="page-link" href="{{ data.NextURL }}">Next</a></li>
|
||||
<li class="page-item"><a class="page-link" href="{{ data.NextURL }}" preload="mousedown">Next</a></li>
|
||||
{{ else }}
|
||||
<li class="page-item disabled"><span class="page-link">Next</span></li>
|
||||
{{ end }}
|
||||
|
||||
@@ -15,16 +15,28 @@
|
||||
{{- block RankingNav() }}
|
||||
{{ url := "/ranking?content=" + Content + "&mode=" + Mode + "&page=1" }}
|
||||
{{- if .Data.PrevDate != "false" }}
|
||||
<a href="{{ url }}&date={{.Data.PrevDate}}" class="custom-btn-secondary me-2">
|
||||
<a
|
||||
href="{{ url }}&date={{.Data.PrevDate}}"
|
||||
class="custom-btn-secondary me-2"
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>
|
||||
<i class="bi bi-arrow-left-circle-fill me-2"></i>Past
|
||||
</span>
|
||||
</a>
|
||||
{{- end }}
|
||||
<a href="{{ url }}" class="custom-btn-secondary me-2">
|
||||
<a
|
||||
href="{{ url }}"
|
||||
class="custom-btn-secondary me-2"
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>Latest</span>
|
||||
</a>
|
||||
<a href="{{ url }}&date={{.Data.NextDate}}" class="custom-btn-secondary{{ .Data.NextDate == "false" ? " disabled" : "" }}"{{ .Data.NextDate == "false" ? " aria-disabled=\"true\"" : "" }}>
|
||||
<a
|
||||
href="{{ url }}&date={{.Data.NextDate}}"
|
||||
class="custom-btn-secondary{{ .Data.NextDate == "false" ? " disabled" : "" }}"{{ .Data.NextDate == "false" ? " aria-disabled=\"true\"" : "" }}
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>
|
||||
Next<i class="bi bi-arrow-right-circle-fill ms-2"></i>
|
||||
</span>
|
||||
|
||||
@@ -24,7 +24,13 @@
|
||||
|
||||
{{- block Switcher(baseURL, paths, names, activeState) }}
|
||||
{{- range i, k := paths }}
|
||||
<a href="{{ baseURL }}{{k}}" class="btn {{ len(k) >= 3 && k[len(k) - 3:] == "r18" ? "btn-danger" : "custom-btn-secondary" }} bg-charcoal-surface2 me-2 mb-2 d-flex align-items-center justify-content-center position-relative {{ activeState == k ? "active" : "" }}" aria-pressed="{{ activeState == k ? "true" : "false" }}" role="button">
|
||||
<a
|
||||
href="{{ baseURL }}{{k}}"
|
||||
class="btn {{ len(k) >= 3 && k[len(k) - 3:] == "r18" ? "btn-danger" : "custom-btn-secondary" }} bg-charcoal-surface2 me-2 mb-2 d-flex align-items-center justify-content-center position-relative {{ activeState == k ? "active" : "" }}"
|
||||
aria-pressed="{{ activeState == k ? "true" : "false" }}"
|
||||
role="button"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{- if activeState == k }}
|
||||
<i class="bi bi-circle-fill start-icon start-0 me-3"></i>
|
||||
{{- end }}
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
{{ activeState == k ? "active border-custom-color fw-bold" : "fw-semibold" }}
|
||||
border-4 px-3"
|
||||
{{ activeState == k ? `aria-current="page"` : "" }}
|
||||
href="{{ baseURL }}{{k}}">
|
||||
href="{{ baseURL }}{{k}}"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ names[i] }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
{{ activeState == k ? "active border-custom-color fw-bold" : "fw-semibold" }}
|
||||
border-4 px-3"
|
||||
{{ activeState == k ? `aria-current="page"` : "" }}
|
||||
href="{{ baseURL }}{{k}}">
|
||||
href="{{ baseURL }}{{k}}"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ names[i] }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
{{- import "blocks/underlinenav" }}
|
||||
{{- block body() }}
|
||||
<!-- Prefetch links -->
|
||||
{*
|
||||
<link rel="prefetch" href="/discovery/novel">
|
||||
*}
|
||||
|
||||
<div class="row justify-content-center g-4">
|
||||
<h1 class="text-center"><i class="bi bi-compass me-2"></i>Discovery</h1>
|
||||
|
||||
@@ -79,12 +79,12 @@
|
||||
<!-- Artist avatar, artwork name, and artist name -->
|
||||
<div class="col-12 col-xl-8 mb-3 mb-xl-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="/users/{{ .User.ID }}" class="me-3">
|
||||
<a href="/users/{{ .User.ID }}" class="me-3" preload="mousedown">
|
||||
<img src="{{ .User.Avatar }}" alt="{{ .User.Name }}" class="rounded-circle object-fit-cover" style="width: 64px; height: 64px;"/>
|
||||
</a>
|
||||
<div>
|
||||
<h1 class="mb-2">{{ .Title }}</h1>
|
||||
<h3 class="mb-0"><a href="/users/{{ .User.ID }}" class="text-muted text-decoration-none">{{ .User.Name }}</a></h3>
|
||||
<h3 class="mb-0"><a href="/users/{{ .User.ID }}" class="text-muted text-decoration-none" preload="mousedown">{{ .User.Name }}</a></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -177,7 +177,7 @@
|
||||
{* NOTE: tried styling these tags similarly to the "View on pixiv.net" button, but even then they still draw too much attention and break visual hierarchy *}
|
||||
<div class="d-inline-block mb-2 me-2">
|
||||
<small>
|
||||
<a href="/tags/{{ escapeString(.Name) }}" class="text-primary-emphasis fw-semibold text-decoration-none text-wrap p-0 mb-0">#{{ .Name }}</a>
|
||||
<a href="/tags/{{ escapeString(.Name) }}" class="text-primary-emphasis fw-semibold text-decoration-none text-wrap p-0 mb-0" preload="mousedown">#{{ .Name }}</a>
|
||||
{{- if .TranslatedName }}
|
||||
{* NOTE: the .TranslatedName actually has a surprisingly high contrast ratio at 7.18 here; also nesting small tags is cursed but it works *}
|
||||
<small class="text-body-secondary fw-medium">({{ .TranslatedName }})</small>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<div class="row">
|
||||
<div class="col-4 col-md-3">
|
||||
<a href="/novel/{{ .ID }}" class="text-decoration-none">
|
||||
<a
|
||||
href="/novel/{{ .ID }}"
|
||||
class="text-decoration-none"
|
||||
preload="mousedown"
|
||||
>
|
||||
<div class="ratio ratio-3x4">
|
||||
<div class="thumbnail-wrapper rounded overflow-hidden">
|
||||
<img src="{{ .CoverURL }}" alt="{{ .Title }}" class="img-fluid object-fit-cover w-100 h-100" loading="lazy" />
|
||||
@@ -16,6 +20,7 @@
|
||||
href="/novel/{{ .ID }}"
|
||||
title="{{ .Title }}"
|
||||
class="text-body text-decoration-none"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ .Title }}
|
||||
</a>
|
||||
@@ -28,6 +33,7 @@
|
||||
href="/novel/series/{{ .SeriesID }}"
|
||||
title="{{ .SeriesTitle }}"
|
||||
class="small text-body-secondary text-decoration-none"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ .SeriesTitle }}
|
||||
</a>
|
||||
@@ -41,13 +47,16 @@
|
||||
|
||||
<!-- Author info -->
|
||||
<div class="d-flex align-items-center me-auto mb-3">
|
||||
<a href="/users/{{ .UserID }}">
|
||||
<a href="/users/{{ .UserID }}"
|
||||
preload="mousedown"
|
||||
>
|
||||
<img src="{{ .UserAvatar }}" alt="{{ .UserName }}" class="rounded-circle object-fit-cover me-2" style="width: 24px; height: 24px" />
|
||||
</a>
|
||||
<a
|
||||
href="/users/{{ .UserID }}"
|
||||
title="{{ .UserName }}"
|
||||
class="text-body-secondary text-decoration-none"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ .UserName }}
|
||||
</a>
|
||||
@@ -83,7 +92,7 @@
|
||||
{* Intentionally empty to not render anything to avoid duplication *}
|
||||
{{- else }}
|
||||
<span class="badge fw-normal text-muted me-2 mb-2 p-0 text-wrap text-break text-start">
|
||||
<a href="/tags/{{ escapeString(.) }}" class="text-decoration-none text-wrap text-break">#{{ . }}</a>
|
||||
<a href="/tags/{{ escapeString(.) }}" class="text-decoration-none text-wrap text-break" preload="mousedown">#{{ . }}</a>
|
||||
</span>
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -4,16 +4,28 @@
|
||||
<!-- Full buttons for md and above -->
|
||||
<div class="d-none d-md-flex flex-row align-items-center justify-content-between w-100">
|
||||
{{- if .MonthBefore.Link != "false" }}
|
||||
<a href="{{ url }}{{ .MonthBefore.Link }}#checkpoint" class="custom-btn-secondary me-2">
|
||||
<a
|
||||
href="{{ url }}{{ .MonthBefore.Link }}#checkpoint"
|
||||
class="custom-btn-secondary me-2"
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>
|
||||
<i class="bi bi-arrow-left-circle-fill me-2"></i>Past month
|
||||
</span>
|
||||
</a>
|
||||
{{- end }}
|
||||
<a href="{{ url }}#checkpoint" class="custom-btn-secondary me-2">
|
||||
<a
|
||||
href="{{ url }}#checkpoint"
|
||||
class="custom-btn-secondary me-2"
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>Current month</span>
|
||||
</a>
|
||||
<a href="{{ url }}{{ .MonthAfter.Link }}#checkpoint" class="custom-btn-secondary{{ .MonthAfter.Link == "false" ? " disabled" : "" }}"{{ .MonthAfter.Link == "false" ? " aria-disabled=\"true\"" : "" }}>
|
||||
<a
|
||||
href="{{ url }}{{ .MonthAfter.Link }}#checkpoint"
|
||||
class="custom-btn-secondary{{ .MonthAfter.Link == "false" ? " disabled" : "" }}"{{ .MonthAfter.Link == "false" ? " aria-disabled=\"true\"" : "" }}
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>
|
||||
Next month<i class="bi bi-arrow-right-circle-fill ms-2"></i>
|
||||
</span>
|
||||
@@ -23,16 +35,28 @@
|
||||
<!-- Shortened buttons for below md -->
|
||||
<div class="d-flex d-md-none flex-row align-items-center justify-content-between w-100">
|
||||
{{- if .MonthBefore.Link != "false" }}
|
||||
<a href="{{ url }}{{ .MonthBefore.Link }}#checkpoint" class="custom-btn-secondary me-2">
|
||||
<a
|
||||
href="{{ url }}{{ .MonthBefore.Link }}#checkpoint"
|
||||
class="custom-btn-secondary me-2"
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>
|
||||
<i class="bi bi-arrow-left-circle-fill me-2"></i>Past
|
||||
</span>
|
||||
</a>
|
||||
{{- end }}
|
||||
<a href="{{ url }}#checkpoint" class="custom-btn-secondary me-2">
|
||||
<a
|
||||
href="{{ url }}#checkpoint"
|
||||
class="custom-btn-secondary me-2"
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>Current</span>
|
||||
</a>
|
||||
<a href="{{ url }}{{ .MonthAfter.Link }}#checkpoint" class="custom-btn-secondary{{ .MonthAfter.Link == "false" ? " disabled" : "" }}"{{ .MonthAfter.Link == "false" ? " aria-disabled=\"true\"" : "" }}>
|
||||
<a
|
||||
href="{{ url }}{{ .MonthAfter.Link }}#checkpoint"
|
||||
class="custom-btn-secondary{{ .MonthAfter.Link == "false" ? " disabled" : "" }}"{{ .MonthAfter.Link == "false" ? " aria-disabled=\"true\"" : "" }}
|
||||
preload="mousedown"
|
||||
>
|
||||
<span>
|
||||
Next<i class="bi bi-arrow-right-circle-fill ms-2"></i>
|
||||
</span>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{{- target := CookieList["pixivfe-ThumbnailToNewTab"] }}
|
||||
<!-- The thumbnail-at.jet.html fragment templates in the artist's avatar and name -->
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="/users/{{ .ArtistID }}">
|
||||
<a
|
||||
href="/users/{{ .ArtistID }}"
|
||||
preload="mousedown"
|
||||
>
|
||||
<img
|
||||
src="{{ .ArtistAvatar }}"
|
||||
alt="{{ .ArtistName }}"
|
||||
@@ -13,6 +16,7 @@
|
||||
href="/users/{{ .ArtistID }}"
|
||||
title="{{ .ArtistName }}"
|
||||
class="text-body-secondary text-truncate"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ .ArtistName }}
|
||||
</a>
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
<div class="position-relative h-100 thumbnail-hover-dark">
|
||||
<!-- Placing the anchor element out here so that the div that contains the tags acts as a hyperlink -->
|
||||
<div> <!-- Empty div for the illust preview (it needs to wrap the anchor) -->
|
||||
<a target="{{ target }}" href="/artworks/{{ .ID }}" class="d-block h-100">
|
||||
<a
|
||||
target="{{ target }}"
|
||||
href="/artworks/{{ .ID }}" class="d-block h-100"
|
||||
preload="mousedown"
|
||||
>
|
||||
<div class="position-absolute top-0 start-0 p-2 d-flex justify-content-between w-100">
|
||||
<div class="d-flex flex-column align-items-start z-3">
|
||||
<!-- When an artwork is listed on the ranking page -->
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
href="/artworks/{{ .ID }}"
|
||||
title="{{ .Title }}"
|
||||
class="fw-bold text-body text-decoration-none"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{ .Title }}
|
||||
</a>
|
||||
|
||||
@@ -18,7 +18,13 @@
|
||||
<div class="col-12">
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between align-items-center mb-4">
|
||||
<h2 class="mb-3 mb-md-0">Today's illustration rankings</h2>
|
||||
<a href="/ranking" class="custom-btn-secondary">See more</a>
|
||||
<a
|
||||
href="/ranking"
|
||||
class="custom-btn-secondary"
|
||||
preload="mousedown"
|
||||
>
|
||||
See more
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row row-cols-2 row-cols-md-4 row-cols-lg-6 g-4">
|
||||
@@ -30,7 +36,13 @@
|
||||
<div class="col-12">
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between align-items-center mb-4">
|
||||
<h2 class="mb-3 mb-md-0">Newest articles on pixivision</h2>
|
||||
<a href="/pixivision" class="custom-btn-secondary">See more</a>
|
||||
<a
|
||||
href="/pixivision"
|
||||
class="custom-btn-secondary"
|
||||
preload="mousedown"
|
||||
>
|
||||
See more
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="overflow-scroll" id="horizontal-scroll">
|
||||
@@ -40,7 +52,10 @@
|
||||
{* NOTE: intentionally choosing indivisible col widths to create a visible affordance *}
|
||||
<div class="col-11 col-md-9 col-lg-5 position-relative">
|
||||
<div class="custom-card bg-charcoal-surface1 thumbnail-hover-dark">
|
||||
<a href="/pixivision/a/{{.ID}}">
|
||||
<a
|
||||
href="/pixivision/a/{{.ID}}"
|
||||
preload="mousedown"
|
||||
>
|
||||
<div class="thumbnail-wrapper rounded-top-5 overflow-hidden">
|
||||
<img src="{{.Thumbnail}}" class="card-img-top rounded-top-5" alt="{{.Title}}" />
|
||||
</div>
|
||||
@@ -48,7 +63,13 @@
|
||||
<div class="custom-card-body">
|
||||
<!-- Title -->
|
||||
<h4 class="text-center lh-lg mb-0">
|
||||
<a href="/pixivision/a/{{.ID}}" class="text-body text-decoration-none">{{.Title}} </a>
|
||||
<a
|
||||
href="/pixivision/a/{{.ID}}"
|
||||
class="text-body text-decoration-none"
|
||||
preload="mousedown"
|
||||
>
|
||||
{{.Title}}
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
@@ -82,7 +103,13 @@
|
||||
<div class="col-12">
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between align-items-center mb-4">
|
||||
<h2 class="mb-3 mb-md-0">Latest works by followed</h2>
|
||||
<a href="/self/followingWorks" class="custom-btn-secondary">See more</a>
|
||||
<a
|
||||
href="/self/followingWorks"
|
||||
class="custom-btn-secondary"
|
||||
preload="mousedown"
|
||||
>
|
||||
See more
|
||||
</a>
|
||||
</div> <div class="row row-cols-2 row-cols-md-4 row-cols-lg-6 g-4">
|
||||
{{- if len(.Data.Following) > 0 }}
|
||||
{{- include "fragments/small-tn" .Data.Following }}
|
||||
@@ -98,7 +125,13 @@
|
||||
<div class="col-12">
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between align-items-center mb-4">
|
||||
<h2 class="mb-3 mb-md-0">Today's illustration rankings</h2>
|
||||
<a href="/ranking" class="custom-btn-secondary">See more</a>
|
||||
<a
|
||||
href="/ranking"
|
||||
class="custom-btn-secondary"
|
||||
preload="mousedown"
|
||||
>
|
||||
See more
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row row-cols-2 row-cols-md-4 row-cols-lg-6 g-4">
|
||||
@@ -110,7 +143,13 @@
|
||||
<div class="col-12">
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between align-items-center mb-4">
|
||||
<h2 class="mb-3 mb-md-0">Newest articles on pixivision</h2>
|
||||
<a href="/pixivision" class="custom-btn-secondary">See more</a>
|
||||
<a
|
||||
href="/pixivision"
|
||||
class="custom-btn-secondary"
|
||||
preload="mousedown"
|
||||
>
|
||||
See more
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="overflow-scroll" id="horizontal-scroll">
|
||||
@@ -141,7 +180,7 @@
|
||||
<!-- Recommended works by tag -->
|
||||
{{- range .Data.RecommendByTags }}
|
||||
<div class="col-12">
|
||||
<h2>Recommended illustrations tagged <a href="/tags/{{ .Name }}" class="text-decoration-none">#{{ .Name }}</a></h2>
|
||||
<h2>Recommended illustrations tagged <a href="/tags/{{ .Name }}" class="text-decoration-none" preload="mousedown">#{{ .Name }}</a></h2>
|
||||
<div class="row row-cols-2 row-cols-md-4 row-cols-lg-6 g-4">
|
||||
{{- include "fragments/small-tn" .Artworks }}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<html lang="en" data-bs-theme="dark" hx-ext="preload">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
@@ -19,6 +19,7 @@
|
||||
<link href="/css/bootstrap-style.css" rel="stylesheet" />
|
||||
|
||||
<script src="/js/htmx@1.9.10.min.js" integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"></script>
|
||||
<script src="/js/htmx-ext-preload@2.0.1.js" integrity="sha384-RKN7eKLXIb5YEIk2f3Gk2dAWySh5p13qfjNHwDevzo8XdDPuzL3SE7WoMgcjZ9wn"></script>
|
||||
<script src="/js/on-page-load.js" integrity="sha384-FBakXYEa42a0uP3tfUR9CyQRC/Alh/X+9boxQmVFZ7D6KV35lCzL3PhPwRSs+09n"></script>
|
||||
<script src="/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"></script>
|
||||
{* TODO: load these JS files only on pages that require them *}
|
||||
@@ -69,7 +70,7 @@
|
||||
<div id="loading-indicator" class="fixed-top z-3"></div>
|
||||
<nav class="navbar bg-charcoal-surface1 py-3 mb-4 js-required" id="main-navbar">
|
||||
<div class="container">
|
||||
<div class="d-flex">
|
||||
<div class="d-flex" preload="mousedown">
|
||||
<!-- Offcanvas menu for navigation items -->
|
||||
<button class="navbar-toggler border-0 p-0 me-3" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasNavbar" aria-controls="offcanvasNavbar" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
{{ fontType := .FontType }}
|
||||
{{ viewMode := .ViewMode }}
|
||||
|
||||
{*
|
||||
<!-- Prefetch links -->
|
||||
<link rel="prefetch" href="/users/{{ .User.ID }}/novels">
|
||||
{{- if .Novel.SeriesNavData }}
|
||||
<link rel="prefetch" href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}">
|
||||
{{- end }}
|
||||
*}
|
||||
|
||||
<div class="row justify-content-center g-4">
|
||||
|
||||
@@ -31,19 +33,19 @@
|
||||
<!-- Series name -->
|
||||
{{- if .Novel.SeriesNavData }}
|
||||
<h3 class="fw-normal mb-2">
|
||||
<a href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}" class="text-body-secondary text-decoration-none">
|
||||
<a href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}" class="text-body-secondary text-decoration-none" preload="mousedown">
|
||||
{{- .Novel.SeriesNavData.Title }} #{{- .Novel.SeriesNavData.Order}}
|
||||
</a>
|
||||
</h3>
|
||||
{{- end}}
|
||||
|
||||
<!-- Author -->
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<a href="/users/{{ .User.ID }}/novels" class="text-decoration-none">
|
||||
<div class="d-flex align-items-center mb-2">>
|
||||
<a href="/users/{{ .User.ID }}/novels" class="text-decoration-none" preload="mousedown">
|
||||
<img src="{{ .User.Avatar }}" alt="{{ .User.Name }}" class="rounded-circle me-2" style="width: 30px; height: 30px" />
|
||||
</a>
|
||||
<h4 class="mb-0">
|
||||
<a href="/users/{{ .User.ID }}/novels" class="text-body-secondary text-decoration-none">
|
||||
<a href="/users/{{ .User.ID }}/novels" class="text-body-secondary text-decoration-none" preload="mousedown">
|
||||
{{ .User.Name }}
|
||||
</a>
|
||||
</h4>
|
||||
@@ -94,7 +96,7 @@
|
||||
{{- else }}
|
||||
<div class="d-inline-block mb-2 me-2">
|
||||
<small>
|
||||
<a href="/tags/{{ escapeString(.Name) }}" class="text-primary-emphasis fw-semibold text-decoration-none text-wrap p-0 mb-0">#{{ .Name }}</a>
|
||||
<a href="/tags/{{ escapeString(.Name) }}" class="text-primary-emphasis fw-semibold text-decoration-none text-wrap p-0 mb-0" preload="mousedown">#{{ .Name }}</a>
|
||||
</small>
|
||||
</div>
|
||||
{{- end }}
|
||||
@@ -123,7 +125,7 @@
|
||||
<div class="custom-card mt-4">
|
||||
<div class="custom-card-body bg-charcoal-surface2">
|
||||
<h3 class="text-center px-3 mb-2">
|
||||
<a href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}" class="text-body text-decoration-none">
|
||||
<a href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}" class="text-body text-decoration-none" preload="mousedown">
|
||||
{{- .Novel.SeriesNavData.Title }}
|
||||
</a>
|
||||
</h3>
|
||||
@@ -131,11 +133,11 @@
|
||||
{* NOTE: formatting for the i18n crawler *}
|
||||
{{ seriesWorks := len(.NovelSeriesContentTitles) }}
|
||||
{{- if seriesWorks == 1 }}
|
||||
<a href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}" class="text-body-secondary text-decoration-none">
|
||||
<a href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}" class="text-body-secondary text-decoration-none" preload="mousedown">
|
||||
<i class="bi bi-stack me-2"></i>{{ seriesWorks }} work in this series
|
||||
</a>
|
||||
{{- else }}
|
||||
<a href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}" class="text-body-secondary text-decoration-none">
|
||||
<a href="/novel/series/{{ .Novel.SeriesNavData.SeriesID }}" class="text-body-secondary text-decoration-none" preload="mousedown">
|
||||
<i class="bi bi-stack me-2"></i>{{ seriesWorks }} works in this series
|
||||
</a>
|
||||
{{- end }}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{{- extends "layout/default" }}
|
||||
{{- import "blocks/underlinenav" }}
|
||||
{{- block body() }}
|
||||
|
||||
{*
|
||||
<!-- Prefetch links -->
|
||||
<link rel="prefetch" href="/discovery">
|
||||
*}
|
||||
|
||||
<div class="row justify-content-center g-4">
|
||||
<h1 class="text-center"><i class="bi bi-compass me-2"></i>Discovery</h1>
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
{{- import "blocks/pagination" }}
|
||||
{{- block body() }}
|
||||
|
||||
{*
|
||||
<!-- Prefetch links -->
|
||||
<link rel="prefetch" href="/users/{{ .User.ID }}/novels">
|
||||
*}
|
||||
|
||||
<div class="row justify-content-center g-4">
|
||||
<div class="col-12 col-lg-9">
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
{{- url = "/ranking?mode=" + "daily" + "&date=" + .Data.CurrentDate + "&page=1&content=" }}
|
||||
{{- end }}
|
||||
|
||||
{*
|
||||
<!-- Prefetch links -->
|
||||
<!-- TODO: get the ranking endpoint stable first before setting up prefetch -->
|
||||
<!-- <link rel="prefetch" href="{{ url }}&date={{.Data.PrevDate}}">
|
||||
<link rel="prefetch" href="{{ url }}&date={{.Data.NextDate}}"> -->
|
||||
*}
|
||||
|
||||
<div class="row justify-content-center g-4">
|
||||
<h1 class="text-center"><i class="bi bi-bar-chart-line me-2"></i>{{ .Title }}</h1>
|
||||
|
||||
Reference in New Issue
Block a user