feat-git #10

Merged
Hare merged 5 commits from feat-git into master 2024-09-25 23:30:09 +09:00
11 changed files with 328 additions and 248 deletions
Showing only changes of commit 36237f0708 - Show all commits

@ -1 +1 @@
Subproject commit 3744bd78995594e5fdfcaeff32f426f1d41daffa Subproject commit d1d724d1170e8cd2460cf1beb5098161ac33ef9a

View File

@ -6,7 +6,7 @@
} }
:root { :root {
font-size: 16px; font-size: 18px;
} }
body { body {
@ -15,5 +15,5 @@ body {
color: #ffffff; color: #ffffff;
font-family: 'ZenKakuGothicNew-Regular', '游ゴシック体', 'Yu Gothic', YuGothic, 'ヒラギノ角ゴシック Pro', font-family: 'ZenKakuGothicNew-Regular', '游ゴシック体', 'Yu Gothic', YuGothic, 'ヒラギノ角ゴシック Pro',
'Hiragino Kaku Gothic Pro', 'メイリオ', Meiryo, Osaka, 'MS PGothic', sans-serif; 'Hiragino Kaku Gothic Pro', 'メイリオ', Meiryo, Osaka, 'MS PGothic', sans-serif;
font-size: 16px; font-size: 1rem;
} }

View File

@ -7,6 +7,8 @@ export type Article = {
category: string; category: string;
released_at: Date; released_at: Date;
updated_at: Date; updated_at: Date;
author: string;
email: string;
tags: string[]; tags: string[];
image: string; image: string;
publish: Publish; publish: Publish;

View File

@ -1,231 +1,243 @@
.document { .document {
--color-text: #ffffff; --color-text: #ffffff;
--color-concept: hsla(40, 100%, 90%, 0.5); --color-concept: hsla(40, 100%, 90%, 0.5);
--color-concept-hsl: 39, 100%, 25%; --color-concept-hsl: 39, 100%, 25%;
--color-outline: #ffffff40; --color-outline: #ffffff40;
width: 100%; width: 100%;
color: var(--color-text); color: var(--color-text);
h1 { padding-left: 2rem;
position: relative; box-sizing: border-box;
width: auto;
font-size: 2rem;
margin-bottom: 0.5rem;
}
hr { h1 {
padding: 0; position: relative;
margin: 0; width: auto;
border: none; font-size: 1.8rem;
border-top: 1px solid var(--color-outline); margin-bottom: 0.5rem;
} margin-left: -1rem;
}
>*:not(h1, hr) { hr {
margin-left: 2rem; padding: 0;
} margin: 0;
border: none;
border-top: 1px solid var(--color-outline);
margin-left: -1rem;
}
h2 { h2 {
font-size: 1.5rem; font-size: 1.5rem;
position: relative; position: relative;
&::before { // &::before {
content: '#'; // content: '#';
position: absolute; // position: absolute;
top: 0; // top: 0;
left: -1.5rem; // left: -1.5rem;
font-size: 1.75rem; // font-size: 1.75rem;
color: rgb(131, 131, 131); // color: rgb(131, 131, 131);
} // }
} }
h3 { h3 {
font-size: 1.25rem; font-size: 1.25rem;
} }
h4 { h4 {
font-size: 1.05rem; font-size: 1.05rem;
} }
hr { hr {
border: none; border: none;
border-top: 1px solid var(--color-outline); border-top: 1px solid var(--color-outline);
} }
img { img {
max-height: 300px; max-height: 300px;
} }
a { a {
color: var(--color-text); color: var(--color-text);
position: relative; position: relative;
display: inline-block; display: inline-block;
transform: translate(0, 0); transform: translate(0, 0);
text-shadow: 0 0 1rem hsl(var(--color-concept-hsl)); text-shadow: 0 0 1rem hsl(var(--color-concept-hsl));
transition: 0.2s ease-out; transition: 0.2s ease-out;
font-weight: normal; font-weight: normal;
&:hover { &:hover {
transform: translate(0, -0.1rem); transform: translate(0, -0.1rem);
} }
} }
blockquote { blockquote {
position: relative; position: relative;
font-size: 1.1rem; font-size: 1.1rem;
font-weight: bold; font-weight: bold;
padding: 0; padding: 0;
padding-left: 1rem; padding-left: 1rem;
color: rgb(162, 162, 162); color: rgb(162, 162, 162);
&::before { &::before {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
left: -0.5rem; left: -0.5rem;
font-size: 2rem; font-size: 2rem;
color: rgb(131, 131, 131); color: rgb(131, 131, 131);
} }
} }
warn { warn {
position: relative; position: relative;
display: block; display: block;
padding: 1rem 0.7rem 0.7rem; padding: 1rem 0.7rem 0.7rem;
background-image: linear-gradient(to right, var(--color-outline), transparent 75%); background-image: linear-gradient(to right, var(--color-outline), transparent 75%);
background-origin: border-box; background-origin: border-box;
box-shadow: inset 0 0 0 100vh var(--background-color); box-shadow: inset 0 0 0 100vh var(--background-color);
text-shadow: 0 0 1rem hsl(var(--color-concept-hsl), 1); text-shadow: 0 0 1rem hsl(var(--color-concept-hsl), 1);
border: 1px solid transparent; border: 1px solid transparent;
border-radius: 0.5rem;
&::before {
content: 'note:warn';
position: relative;
display: block;
top: 0;
font-size: 0.8rem;
margin-bottom: -0.3rem;
transform: translate(0, -0.5rem);
text-shadow: 0 0 1rem red;
}
}
code:not(pre>code) {
display: inline-block;
font-family: monospace;
font-size: 0.9rem;
background: #66666666;
padding: 0 0.3rem;
border-radius: 0.5rem; border-radius: 0.5rem;
}
&::before { pre {
content: 'note:warn'; font-family: monospace;
position: relative; position: relative;
display: block; display: block;
top: 0; margin-top: 0.75rem;
font-size: 0.8rem; margin-bottom: 0.75rem;
margin-bottom: -0.3rem; // border: 2px solid #ffffff40;
transform: translate(0, -0.5rem); border-radius: 0.5rem;
text-shadow: 0 0 1rem red; overflow-x: auto;
} font-size: 0.9rem;
}
pre { &::-webkit-scrollbar {
font-family: monospace; border-radius: 10px;
position: relative; height: 10px;
display: block; width: 8px;
margin-top: 0.75rem; background: #3d3d3d;
margin-bottom: 0.75rem; }
border: 2px solid #ffffff40;
border-radius: 0.5rem;
overflow-x: scroll;
&::-webkit-scrollbar { &::-webkit-scrollbar-thumb {
border-radius: 10px; background: #6f6f6f;
height: 10px; border-radius: 10px;
width: 8px; }
}
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-track {
background: #999; border-radius: 10px;
border-radius: 10px; }
}
&::-webkit-scrollbar-track { > code {
border-radius: 10px; display: inline-block;
} padding: 0.5rem;
border-radius: 0.6rem;
font-family: monospace;
box-sizing: border-box;
min-width: 100%;
}
}
>code { details {
display: inline-block; position: relative;
padding: 0.5rem; display: block;
border-radius: 0.6rem; border-radius: 0.5rem;
font-family: monospace; transition: 0.2s ease-out;
box-sizing: border-box; transition-property: height;
min-width: 100%; padding-inline-start: 0.1rem;
}
}
details { > summary {
position: relative; position: relative;
display: block; border-radius: 0.5rem;
border-radius: 0.5rem; list-style: ' ' outside;
transition: 0.2s ease-out; margin-left: 1rem;
transition-property: height; padding: 0.2rem;
padding-inline-start: 0.1rem; background: linear-gradient(to right, rgba(255, 255, 255, 0.25), transparent 200px);
cursor: pointer;
>summary { &:hover {
position: relative; text-shadow: 0 0 0.25rem rgb(255, 255, 255);
border-radius: 0.5rem; }
list-style: ' ' outside; }
margin-left: 1rem;
padding: 0.2rem;
background: linear-gradient(to right, rgba(255, 255, 255, 0.25), transparent 200px);
cursor: pointer;
&:hover { > p {
text-shadow: 0 0 0.25rem rgb(255, 255, 255); margin-block-start: 0.5rem;
} margin-block-end: 0.5rem;
} margin-left: 1rem;
display: none;
}
>p { &[open] {
margin-block-start: 0.5rem; > summary {
margin-block-end: 0.5rem; list-style: ' ' outside;
margin-left: 1rem; }
display: none;
}
&[open] { > p {
>summary { animation: detailsIn 0.5s ease;
list-style: ' ' outside; display: block;
} }
}
}
>p { @keyframes detailsIn {
animation: detailsIn 0.5s ease; 0% {
display: block; opacity: 0;
} transform: translateY(-10px);
} }
}
@keyframes detailsIn { 100% {
0% { opacity: 1;
opacity: 0; transform: none;
transform: translateY(-10px); }
} }
100% { table {
opacity: 1; border-spacing: 0;
transform: none; border: none;
} border: 1px solid var(--color-outline);
} border-radius: 10px;
overflow: hidden;
box-shadow: 0 0 0.5rem hsl(var(--color-concept-hsl), 0.5);
table { thead {
border-spacing: 0; background-color: rgba(0, 0, 0, 0.1);
border: none; color: #fff;
border: 1px solid var(--color-outline); }
border-radius: 10px;
overflow: hidden;
box-shadow: 0 0 0.5rem hsl(var(--color-concept-hsl), 0.5);
thead { tr {
background-color: rgba(0, 0, 0, 0.1); &:nth-child(2n) {
color: #fff; background-color: #ffffff0d;
} }
}
tr { td,
&:nth-child(2n) { th {
background-color: #ffffff0d; padding: 0.5em;
} border-left: 1px solid var(--color-outline);
}
td, &:first-child {
th { border-left: none;
padding: 0.5em; }
border-left: 1px solid var(--color-outline); }
}
&:first-child {
border-left: none;
}
}
}
} }

View File

@ -8,7 +8,7 @@
import type { Article } from '$lib/article'; import type { Article } from '$lib/article';
export let data: Article; export let data: Article;
const isUpdated = data.updated_at.getTime() != data.released_at.getTime(); const isUpdated = data.updated_at.getTime() != data.released_at.getTime();
</script> </script>
<svelte:head> <svelte:head>
@ -21,7 +21,7 @@
{#if isUpdated} {#if isUpdated}
<meta property="article:modified_time" content={data.updated_at.toISOString()} /> <meta property="article:modified_time" content={data.updated_at.toISOString()} />
{/if} {/if}
<meta property="article:author" content="HareWorks" /> <meta property="article:author" content={data.author} />
<meta property="article:section" content="Blog" /> <meta property="article:section" content="Blog" />
<meta property="article:tag" content={data.tags.join(',')} /> <meta property="article:tag" content={data.tags.join(',')} />
<meta name="robots" content={data.publish as publish.Publish} /> <meta name="robots" content={data.publish as publish.Publish} />
@ -35,20 +35,29 @@
<div class="title"> <div class="title">
<h1>{data.title}</h1> <h1>{data.title}</h1>
<div class="meta"> <div class="meta">
<span> <div class="left">
released <FormattedDate date={data.released_at} /> <span>
{#if isUpdated}<br /> released <FormattedDate date={data.released_at} />
updated <FormattedDate date={data.updated_at} /> {#if isUpdated}<br />
{/if} updated <FormattedDate date={data.updated_at} />
</span> {/if}
<span> </span>
<a href="/category/{data.category}" <span>
>{data.category[0].toUpperCase() + data.category.slice(1)}</a <a href="/category/{data.category}"
> >{data.category[0].toUpperCase() + data.category.slice(1)}</a
{#each data.tags as tag} >
<a href={`/search?tag=${tag}`}>{tag}</a> {#each data.tags as tag}
{/each} <a href={`/search?tag=${tag}`}>{tag}</a>
</span> {/each}
</span>
</div>
<div class="right">
<img
src="https://gitea.hareworks.net/avatars/e595ec10f8052671deab92caca78220fc838f63259bcd542a0d93f53e2371d52?size=512"
alt="Author"
/>
<div>@{data.author}</div>
</div>
</div> </div>
</div> </div>
<div class="panel"> <div class="panel">
@ -91,6 +100,11 @@
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
} }
.card {
position: fixed;
top: 0;
right: 0;
}
main { main {
border: 1px solid var(--line-primary); border: 1px solid var(--line-primary);
border-top: none; border-top: none;
@ -100,7 +114,7 @@
min-height: 100%; min-height: 100%;
padding: 20px; padding: 20px;
padding-top: 100px; padding-top: 100px;
max-width: 1000px; max-width: 800px;
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -110,7 +124,7 @@
font-size: 2rem; font-size: 2rem;
text-align: center; text-align: center;
margin: 0; margin: 0;
padding: 12px 100px 12px 0; padding: 12px;
border-bottom: 1px solid rgba(255, 255, 255, 0.3); border-bottom: 1px solid rgba(255, 255, 255, 0.3);
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
@ -120,29 +134,56 @@
.meta { .meta {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-direction: row;
padding: 0 20px; padding: 0 20px;
font-size: 0.8rem; font-size: 1rem;
span { > .left {
opacity: 0.6; display: flex;
} flex-direction: column;
a { justify-content: center;
margin-left: 5px; align-items: left;
padding: 0 5px; span {
color: inherit; opacity: 0.6;
text-decoration: none;
&:hover {
text-decoration: underline;
} }
&:first-child { a {
&::before { margin-left: 5px;
content: '🗀 '; padding: 0 5px;
color: inherit;
text-decoration: none;
&:hover {
text-decoration: underline;
} }
&::after { &:first-child {
content: '|'; margin-left: 0;
margin-left: 15px; padding-left: 0;
&::before {
content: '🗀 ';
}
&::after {
content: '|';
margin-left: 15px;
}
} }
} }
} }
> .right {
display: flex;
flex-direction: row;
justify-content: right;
align-items: center;
gap: 10px;
height: 50px;
margin: 10px;
img {
width: 50px;
height: 50px;
border-radius: 15%;
}
div {
font-size: 1rem;
}
}
} }
} }
.panel { .panel {

View File

@ -0,0 +1,15 @@
import { simpleGit, } from 'simple-git';
import type { SimpleGit, SimpleGitOptions } from 'simple-git';
console.log(process.cwd()+'/articles');
export const gitOptions: Partial<SimpleGitOptions> = {
baseDir: process.cwd()+'/articles',
binary: 'git',
maxConcurrentProcesses: 6,
config: [
'core.sshCommand=ssh -i ../key -F /dev/null'
],
};
const git: SimpleGit = simpleGit(gitOptions);
export default git;

View File

@ -1,3 +1,4 @@
//@ts-ignore
import { compile, escapeSvelte } from "mdsvex"; import { compile, escapeSvelte } from "mdsvex";
import { createHighlighter } from "shiki"; import { createHighlighter } from "shiki";
import { kanagawa_dark as theme } from "$lib/kanagawa" import { kanagawa_dark as theme } from "$lib/kanagawa"

View File

@ -10,10 +10,14 @@ import {
} from '$env/static/private' } from '$env/static/private'
const connectionString = `postgres://${PG_USER}:${PG_PASS}@${PG_HOST}:${PG_PORT}/${PG_DB}`; const connectionString = `postgres://${PG_USER}:${PG_PASS}@${PG_HOST}:${PG_PORT}/${PG_DB}`;
const pool = new Pool({ connectionString }); let pool = new Pool({ connectionString });
export const getConnection = () => pool; export const getConnection = () => pool;
export const reConnect = async () => {
pool = new Pool({ connectionString });
}
import init_db from '$lib/server/database/init'; import init_db from '$lib/server/database/init';
import PG from '$lib/server/database'; import PG from '$lib/server/database';
await init_db(await PG(pool)); await init_db(await PG(pool));

View File

@ -90,10 +90,14 @@ export default async function init(db: Postgres) {
}); });
const res = await db.query('select * from article where id = $1', [id]); const res = await db.query('select * from article where id = $1', [id]);
const author = gitlog.all[0].author_name; // console.log(gitlog);
const email = gitlog.all[0].author_email; const latest = gitlog.latest!;
const released_at = new Date(gitlog.all[0].date); const oldest = gitlog.all[gitlog.all.length - 1];
const updated_at = (gitlog.latest === null) ? released_at : new Date(gitlog.latest.date);
const author = oldest.author_name;
const email = oldest.author_email;
const released_at = new Date(oldest.date);
const updated_at = new Date(latest.date);
console.log(`Author: ${author} <${email}>\nReleased at: ${format(released_at)}\nUpdated at: ${format(updated_at)}`); console.log(`Author: ${author} <${email}>\nReleased at: ${format(released_at)}\nUpdated at: ${format(updated_at)}`);
const category = path.split('/')[3]; const category = path.split('/')[3];
@ -112,8 +116,8 @@ export default async function init(db: Postgres) {
'insert into article (id, released_at, updated_at, author, email, title, category, tags, image, publish, content) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)', 'insert into article (id, released_at, updated_at, author, email, title, category, tags, image, publish, content) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)',
[id, released_at, updated_at, author, email, title, category, tags, image, publish, content] [id, released_at, updated_at, author, email, title, category, tags, image, publish, content]
); );
} else if (res.rows[0].updated_at < updated_at) { // } else if (res.rows[0].updated_at < updated_at) {
// } else if (true) { } else if (true) {
console.log(`Update article: ${id}`); console.log(`Update article: ${id}`);
await db.query( await db.query(
'update article set released_at = $2, updated_at = $3, author = $4, email = $5, title = $6, category = $7, tags = $8, image = $9, publish = $10, content = $11 where id = $1', 'update article set released_at = $2, updated_at = $3, author = $4, email = $5, title = $6, category = $7, tags = $8, image = $9, publish = $10, content = $11 where id = $1',

View File

@ -1,6 +1,7 @@
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
import PG from '$lib/server/database'; import PG from '$lib/server/database';
import { format } from '$lib/scripts/formatted_date';
let data: { let data: {
recent: { recent: {
@ -28,7 +29,7 @@ export const load: PageServerLoad = async ({ params, locals }) => {
data.recent = recent_articles.rows.map((row) => ({ data.recent = recent_articles.rows.map((row) => ({
title: row.title, title: row.title,
image: row.image, image: row.image,
date: row.updated_at.toISOString().slice(0, 10), date: format(row.updated_at),
link: `/article/${row.category}/${row.id}`, link: `/article/${row.category}/${row.id}`,
tags: row.tags, tags: row.tags,
})); }));

View File

@ -130,7 +130,7 @@
height: 100dvh; height: 100dvh;
backdrop-filter: blur(2px); backdrop-filter: blur(2px);
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
.controls { .controls {
position: fixed; position: fixed;
@ -305,15 +305,15 @@
.tags { .tags {
ul { ul {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: left; justify-content: left;
flex-direction: row; flex-direction: row;
gap: 3px; gap: 3px;
li { li {
font-size: 1rem; font-size: 1rem;
padding: 3px 5px; padding: 3px 5px;
border: 1px solid var(--line-primary); border: 1px solid var(--line-primary);
border-radius: 5px; border-radius: 5px;
} }
} }
} }