This commit is contained in:
+25
-13
@@ -6,21 +6,33 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="description" content="ぼざクリ ぼざろクリーチャーシリーズ 伊地知ニジカ リンク集 Wiki ニコニコ" />
|
<meta name="description" content="ぼざクリ ぼざろクリーチャーシリーズ 伊地知ニジカ リンク集 Wiki ニコニコ" />
|
||||||
<title>ぼざクリ タグ広場 〜 ぼざろクリーチャーシリーズ綜合リンク集</title>
|
<title>ぼざクリ タグ広場 〜 ぼざろクリーチャーシリーズ綜合リンク集</title>
|
||||||
<script type="application/ld+json">
|
<!-- helmet -->
|
||||||
{
|
|
||||||
"@context": "http://schema.org",
|
|
||||||
"@type": "WebSite",
|
|
||||||
"url": "https://hub.nizika.monster",
|
|
||||||
"potentialAction": {
|
|
||||||
"@type": "SearchAction",
|
|
||||||
"target": "https://hub.nizika.monster/posts?tags={search_term}",
|
|
||||||
"query-input": "required name=search_term"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root">
|
||||||
|
<div class="flex flex-col h-screen w-screen">
|
||||||
|
<nav class="px-3 flex justify-between items-center w-full min-h-[48px]
|
||||||
|
bg-yellow-200 dark:bg-red-975 md:bg-yellow-50">
|
||||||
|
<div class="flex items-center gap-2 h-full">
|
||||||
|
<a class="mx-4 text-xl font-bold text-pink-600 hover:text-pink-400
|
||||||
|
dark:text-pink-300 dark:hover:text-pink-100"
|
||||||
|
href="/">
|
||||||
|
ぼざクリ タグ広場
|
||||||
|
</a>
|
||||||
|
<a class="hidden md:flex h-full items-center px-2" href="/posts">広場</a>
|
||||||
|
<a class="hidden md:flex h-full items-center px-2" href="/tags">タグ</a>
|
||||||
|
<a class="hidden md:flex h-full items-center px-2" href="/wiki/ヘルプ:ホーム">Wiki</a>
|
||||||
|
<a class="hidden md:flex h-full items-center px-2" href="/users">ユーザ</a>
|
||||||
|
</div>
|
||||||
|
<a href="#" class="md:hidden ml-auto pr-4
|
||||||
|
text-pink-600 hover:text-pink-400
|
||||||
|
dark:text-pink-300 dark:hover:text-pink-100">
|
||||||
|
Menu
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<!-- outlet -->
|
||||||
|
</div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
RewriteBase /
|
RewriteBase /
|
||||||
|
|
||||||
|
# routes #
|
||||||
|
|
||||||
RewriteCond %{REQUEST_URI} !^/api
|
RewriteCond %{REQUEST_URI} !^/api
|
||||||
RewriteCond %{REQUEST_URI} !^/sitemap\.xml
|
RewriteCond %{REQUEST_URI} !^/sitemap\.xml
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import crypto from 'crypto'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
@@ -14,7 +15,10 @@ const SITE_TITLE = 'ぼざクリ タグ広場'
|
|||||||
const DOMAIN = 'https://hub.nizika.monster'
|
const DOMAIN = 'https://hub.nizika.monster'
|
||||||
const API_BASE_URL = 'https://hub.nizika.monster/api'
|
const API_BASE_URL = 'https://hub.nizika.monster/api'
|
||||||
|
|
||||||
const fetchPosts = async () => (await axios.get (`${ API_BASE_URL }/posts`)).data.posts
|
const fetchPosts = async tagName => (await axios.get (`${ API_BASE_URL }/posts`,
|
||||||
|
{ params: { ...(tagName && { tags: tagName,
|
||||||
|
match: 'all',
|
||||||
|
limit: '20' }) } })).data.posts
|
||||||
const fetchPostIds = async () => (await fetchPosts ()).map (post => post.id)
|
const fetchPostIds = async () => (await fetchPosts ()).map (post => post.id)
|
||||||
|
|
||||||
const fetchTags = async () => (await axios.get (`${ API_BASE_URL }/tags`)).data
|
const fetchTags = async () => (await axios.get (`${ API_BASE_URL }/tags`)).data
|
||||||
@@ -23,20 +27,82 @@ const fetchTagNames = async () => (await fetchTags ()).map (tag => tag.name)
|
|||||||
const fetchWikiPages = async () => (await axios.get (`${ API_BASE_URL }/wiki`)).data
|
const fetchWikiPages = async () => (await axios.get (`${ API_BASE_URL }/wiki`)).data
|
||||||
const fetchWikiTitles = async () => (await fetchWikiPages ()).map (page => page.title)
|
const fetchWikiTitles = async () => (await fetchWikiPages ()).map (page => page.title)
|
||||||
|
|
||||||
|
const createPostListOutlet = async tagName => `
|
||||||
|
<main class="flex-1 overflow-y-auto p-4">
|
||||||
|
<div class="mt-4">
|
||||||
|
<div class="flex gap-4"><a href="#" class="font-bold">広場</a></div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<div class="flex flex-wrap gap-6 p-4">
|
||||||
|
${ (await fetchPosts (tagName)).map (post => `
|
||||||
|
<a class="w-40 h-40 overflow-hidden rounded-lg shadow-md hover:shadow-lg"
|
||||||
|
href="/posts/${ post.id }">
|
||||||
|
<img alt="${ post.title }"
|
||||||
|
title="${ post.title }"
|
||||||
|
loading="eager"
|
||||||
|
fetchpriority="high"
|
||||||
|
decoding="async"
|
||||||
|
class="object-none w-full h-full"
|
||||||
|
src="${ post.url }" />
|
||||||
|
</a>`).join ('') }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>`
|
||||||
|
|
||||||
|
const createPostDetailOutlet = post => `
|
||||||
|
<div class="md:flex md:flex-1">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
${ ['deerjikist', 'meme', 'character', 'general', 'material', 'meta', 'nico']
|
||||||
|
.map (cat => '<ul>' + post.tags.filter (tag => tag.category === cat).map (tag => `
|
||||||
|
<li>
|
||||||
|
<span>
|
||||||
|
<a href="/wiki/${ encodeURIComponent (tag.name) }">?</a>
|
||||||
|
</span>
|
||||||
|
<a href="/posts?${ new URLSearchParams ({ tags: tag.name }) }">
|
||||||
|
${ tag.name }
|
||||||
|
</a>
|
||||||
|
<span>${ tag['post_count'] }</span>
|
||||||
|
</li>`).join ('') + '</ul>').join ('') }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<main class="flex-1 overflow-y-auto p-4">
|
||||||
|
<img src="${ post.thumbnail }" alt="${ post.url }" />
|
||||||
|
</main>
|
||||||
|
</div>`
|
||||||
|
|
||||||
const posts = (await fetchPosts ()).map (post => [
|
const posts = (await fetchPosts ()).map (post => [
|
||||||
`/posts/${ post.id }`,
|
`/posts/${ post.id }`,
|
||||||
`${ post.title || post.url } | ${ SITE_TITLE }` ])
|
`${ post.title || post.url } | ${ SITE_TITLE }`,
|
||||||
|
createPostDetailOutlet (post)])
|
||||||
|
|
||||||
const tags = (await fetchTags ()).map (tag => [
|
const tags = []
|
||||||
`/posts?${ new URLSearchParams ({ tags: tag.name }) }`,
|
for (const tag of await fetchTags ())
|
||||||
`${ tag.name } | ${ SITE_TITLE }`])
|
{
|
||||||
|
tags.push ([`/posts?${ new URLSearchParams ({ tags: tag.name }) }`,
|
||||||
|
`${ tag.name } | ${ SITE_TITLE }`,
|
||||||
|
await createPostListOutlet (tag.name)])
|
||||||
|
}
|
||||||
|
|
||||||
const wikiPages = (await fetchWikiPages ()).map (page => [
|
const wikiPages = (await fetchWikiPages ()).map (page => [
|
||||||
`/wiki/${ encodeURIComponent (page.title) }`,
|
`/wiki/${ encodeURIComponent (page.title) }`,
|
||||||
`${ page.title } Wiki | ${ SITE_TITLE }`])
|
`${ page.title } Wiki | ${ SITE_TITLE }`])
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
['/', `${ SITE_TITLE } 〜 ぼざろクリーチャーシリーズ綜合リンク集サイト`],
|
['/', `${ SITE_TITLE } 〜 ぼざろクリーチャーシリーズ綜合リンク集`,
|
||||||
|
await createPostListOutlet (), `
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "http://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"url": "https://hub.nizika.monster",
|
||||||
|
"potentialAction": {
|
||||||
|
"@type": "SearchAction",
|
||||||
|
"target": "https://hub.nizika.monster/posts?tags={search_term}",
|
||||||
|
"query-input": "required name=search_term"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>`],
|
||||||
...tags,
|
...tags,
|
||||||
...posts,
|
...posts,
|
||||||
['/wiki', `Wiki | ${ SITE_TITLE }`],
|
['/wiki', `Wiki | ${ SITE_TITLE }`],
|
||||||
@@ -70,3 +136,29 @@ ${ routes.map (([route, title]) => ` <item>
|
|||||||
|
|
||||||
fs.writeFileSync (path.resolve ('dist/sitemap.xml'), xml)
|
fs.writeFileSync (path.resolve ('dist/sitemap.xml'), xml)
|
||||||
fs.writeFileSync (path.resolve ('dist/rss.xml'), rss)
|
fs.writeFileSync (path.resolve ('dist/rss.xml'), rss)
|
||||||
|
|
||||||
|
const baseHTML = fs.readFileSync (path.resolve ('dist/index.html'), 'utf8')
|
||||||
|
let htaccess = fs.readFileSync (path.resolve ('dist/.htaccess'), 'utf8')
|
||||||
|
routes.forEach (([route, title, outlet, helmet]) => {
|
||||||
|
const fileName = (
|
||||||
|
route === '/'
|
||||||
|
? 'index.html'
|
||||||
|
: `${ crypto.createHash ('sha256').update (encodeURIComponent (route)).digest ('hex') }.html`)
|
||||||
|
|
||||||
|
let html = baseHTML.replace (/(?<=<title>).*?(?=<\/title>)/, title)
|
||||||
|
html = html.replace ('<!-- outlet -->', outlet || '')
|
||||||
|
html = html.replace ('<!-- helmet -->', helmet || '')
|
||||||
|
fs.writeFileSync (path.resolve (`dist/${ fileName }`), html)
|
||||||
|
|
||||||
|
const [routeBase, q] = route.split ('?')
|
||||||
|
if (route !== '/')
|
||||||
|
{
|
||||||
|
htaccess = htaccess.replace ('# routes #', `
|
||||||
|
RewriteCond %{REQUEST_URI} ^${ routeBase }$
|
||||||
|
${ q ? `RewriteCond %{QUERY_STRING} (^|&)${ q }(&|$)` : '' }
|
||||||
|
RewriteRule ^ /${ fileName } [L]
|
||||||
|
# routes #
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
fs.writeFileSync (path.resolve ('dist/.htaccess'), htaccess.replace ('# routes #', ''))
|
||||||
|
|||||||
Reference in New Issue
Block a user