Implement content generation
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app" tabindex="0" @keyup="press">
|
<div class="app" tabindex="0" @keyup="press">
|
||||||
<div v-if="isHumanWin">
|
<div v-if="!ready">
|
||||||
|
<p>Загрузка...</p>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="isHumanWin">
|
||||||
<p>Победа! Было очень сложно, но вы справились, поздравляю!</p>
|
<p>Победа! Было очень сложно, но вы справились, поздравляю!</p>
|
||||||
<button class="btn" @click.prevent="restart">Заново</button>
|
<button class="btn" @click.prevent="restart">Заново</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -23,12 +26,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import Predictor from '@anwinged/predictor';
|
|
||||||
|
|
||||||
const MAX_SCORE = 50;
|
const MAX_SCORE = 50;
|
||||||
|
|
||||||
function makePredictor() {
|
let Predictor: any;
|
||||||
|
|
||||||
|
async function makePredictor() {
|
||||||
|
if (!Predictor) {
|
||||||
|
const mod = await import('@anwinged/predictor');
|
||||||
|
Predictor = mod.default || mod;
|
||||||
|
}
|
||||||
return new Predictor({
|
return new Predictor({
|
||||||
base: 2,
|
base: 2,
|
||||||
daemons: [
|
daemons: [
|
||||||
@@ -42,7 +50,13 @@ function makePredictor() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const predictor = ref(makePredictor());
|
const ready = ref(false);
|
||||||
|
const predictor = ref<any>(null);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
predictor.value = await makePredictor();
|
||||||
|
ready.value = true;
|
||||||
|
});
|
||||||
|
|
||||||
const isHumanWin = computed(() => predictor.value.score >= MAX_SCORE);
|
const isHumanWin = computed(() => predictor.value.score >= MAX_SCORE);
|
||||||
const isRobotWin = computed(() => predictor.value.score <= -MAX_SCORE);
|
const isRobotWin = computed(() => predictor.value.score <= -MAX_SCORE);
|
||||||
@@ -61,8 +75,8 @@ function press(evt: KeyboardEvent) {
|
|||||||
pass(evt.key === '1' ? 0 : 1);
|
pass(evt.key === '1' ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function restart() {
|
async function restart() {
|
||||||
predictor.value = makePredictor();
|
predictor.value = await makePredictor();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import PredictorDemo from '../../components/PredictorDemo.vue';
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<PredictorDemo client:visible />
|
<PredictorDemo client:only="vue" />
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
8
src/pages/404.astro
Normal file
8
src/pages/404.astro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
import InternalLayout from '../layouts/InternalLayout.astro';
|
||||||
|
---
|
||||||
|
<InternalLayout title="Страница не найдена" description="Страница не найдена">
|
||||||
|
<h1 class="text-4xl font-bold mt-3 mb-4">404</h1>
|
||||||
|
<p>Ой, страница не найдена.</p>
|
||||||
|
<p>Давайте посмотрим, что интересное есть на <a href="/">главной</a>.</p>
|
||||||
|
</InternalLayout>
|
||||||
25
src/pages/articles/[slug].astro
Normal file
25
src/pages/articles/[slug].astro
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
import { getCollection, render } from 'astro:content';
|
||||||
|
import ArticleLayout from '../../layouts/ArticleLayout.astro';
|
||||||
|
import { parseDateFromId } from '../../utils/articles';
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const articles = await getCollection('articles');
|
||||||
|
return articles.map((article) => ({
|
||||||
|
params: { slug: article.id },
|
||||||
|
props: { article },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { article } = Astro.props;
|
||||||
|
const { Content } = await render(article);
|
||||||
|
const date = parseDateFromId(article.id);
|
||||||
|
---
|
||||||
|
<ArticleLayout
|
||||||
|
title={article.data.title}
|
||||||
|
description={article.data.description}
|
||||||
|
keywords={article.data.keywords}
|
||||||
|
date={date}
|
||||||
|
>
|
||||||
|
<Content />
|
||||||
|
</ArticleLayout>
|
||||||
16
src/pages/articles/index.astro
Normal file
16
src/pages/articles/index.astro
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
|
import InternalLayout from '../../layouts/InternalLayout.astro';
|
||||||
|
import ArticleList from '../../components/ArticleList.astro';
|
||||||
|
import { parseDateFromId } from '../../utils/articles';
|
||||||
|
|
||||||
|
const allArticles = await getCollection('articles', ({ data }) => !data.draft);
|
||||||
|
const articles = allArticles.map((a) => ({
|
||||||
|
slug: a.id,
|
||||||
|
date: parseDateFromId(a.id),
|
||||||
|
title: a.data.title,
|
||||||
|
}));
|
||||||
|
---
|
||||||
|
<InternalLayout title="Заметки" description="Заметки">
|
||||||
|
<ArticleList articles={articles} />
|
||||||
|
</InternalLayout>
|
||||||
7
src/pages/gallery/index.astro
Normal file
7
src/pages/gallery/index.astro
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
import InternalLayout from '../../layouts/InternalLayout.astro';
|
||||||
|
---
|
||||||
|
<InternalLayout title="Галерея" description="Фотогалерея">
|
||||||
|
<h1 class="text-4xl font-bold mt-3 mb-4">Галерея</h1>
|
||||||
|
<p>Скоро здесь будут фотографии.</p>
|
||||||
|
</InternalLayout>
|
||||||
@@ -1,5 +1,15 @@
|
|||||||
---
|
---
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||||
|
import ArticleList from '../components/ArticleList.astro';
|
||||||
|
import { parseDateFromId } from '../utils/articles';
|
||||||
|
|
||||||
|
const allArticles = await getCollection('articles', ({ data }) => !data.draft);
|
||||||
|
const articles = allArticles.map((a) => ({
|
||||||
|
slug: a.id,
|
||||||
|
date: parseDateFromId(a.id),
|
||||||
|
title: a.data.title,
|
||||||
|
}));
|
||||||
---
|
---
|
||||||
<BaseLayout description="Личный сайт Антона Вахрушева">
|
<BaseLayout description="Личный сайт Антона Вахрушева">
|
||||||
<main class="max-w-content mx-auto px-3 sm:px-0">
|
<main class="max-w-content mx-auto px-3 sm:px-0">
|
||||||
@@ -13,6 +23,10 @@ import BaseLayout from '../layouts/BaseLayout.astro';
|
|||||||
|
|
||||||
<div class="border-t border-rule my-8"></div>
|
<div class="border-t border-rule my-8"></div>
|
||||||
|
|
||||||
|
<ArticleList articles={articles} />
|
||||||
|
|
||||||
|
<div class="border-t border-rule my-8"></div>
|
||||||
|
|
||||||
<ul class="list-none p-0 m-0">
|
<ul class="list-none p-0 m-0">
|
||||||
<li>
|
<li>
|
||||||
<a href="mailto:anton@vakhrushev.me">anton@vakhrushev.me</a>
|
<a href="mailto:anton@vakhrushev.me">anton@vakhrushev.me</a>
|
||||||
|
|||||||
10
src/utils/articles.ts
Normal file
10
src/utils/articles.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Парсит дату из ID статьи (формат: "2019-05-01-slug").
|
||||||
|
*/
|
||||||
|
export function parseDateFromId(id: string): Date {
|
||||||
|
const match = id.match(/^(\d{4})-(\d{2})-(\d{2})-/);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`Cannot parse date from article id: ${id}`);
|
||||||
|
}
|
||||||
|
return new Date(`${match[1]}-${match[2]}-${match[3]}`);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user