1
0
mirror of https://github.com/robonen/lorem-blog.git synced 2026-03-20 02:44:39 +00:00

Merge pull request #5 from robonen/chore/update-deps

chore: update deps and use useAsyncData composable in blog context
This commit is contained in:
2025-07-14 02:52:29 +07:00
committed by GitHub
11 changed files with 682 additions and 483 deletions

View File

@@ -1,6 +1,7 @@
import antfu from '@antfu/eslint-config';
export default antfu({
export default antfu(
{
stylistic: {
indent: 2,
semi: true,
@@ -9,12 +10,19 @@ export default antfu({
'style/comma-dangle': ['error', 'always-multiline'],
},
},
vue: true,
typescript: true,
rules: {
'unused-imports/no-unused-imports': 'error',
'regexp/no-obscure-range': ['error', {
allowed: 'all',
}],
},
vue: true,
typescript: true,
});
},
{
files: ['**/*.vue'],
rules: {
'import/first': 'off',
},
},
);

View File

@@ -3,7 +3,7 @@
"type": "module",
"version": "1.0.0",
"private": true,
"packageManager": "pnpm@10.12.1",
"packageManager": "pnpm@10.13.1",
"scripts": {
"dev": "vite",
"build": "vite build",
@@ -15,24 +15,24 @@
},
"dependencies": {
"@robonen/stdlib": "^0.0.7",
"@robonen/vue": "^0.0.7",
"@tailwindcss/vite": "^4.1.8",
"tailwindcss": "^4.1.8",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
"@robonen/vue": "^0.0.9",
"@tailwindcss/vite": "^4.1.11",
"tailwindcss": "^4.1.11",
"vue": "^3.5.17",
"vue-router": "^4.5.1"
},
"devDependencies": {
"@antfu/eslint-config": "^4.14.1",
"@antfu/eslint-config": "^4.16.2",
"@robonen/tsconfig": "^0.0.2",
"@types/jsdom": "^21.1.7",
"@types/node": "^22.14.0",
"@vitejs/plugin-vue": "^5.2.3",
"@types/node": "^22.16.3",
"@vitejs/plugin-vue": "^6.0.0",
"@vue/test-utils": "^2.4.6",
"eslint": "^9.28.0",
"eslint": "^9.31.0",
"eslint-plugin-vuejs-accessibility": "^2.4.1",
"jsdom": "^26.0.0",
"vite": "^6.2.4",
"vitest": "^3.1.1",
"vue-tsc": "^2.2.8"
"jsdom": "^26.1.0",
"vite": "^7.0.4",
"vitest": "^3.2.4",
"vue-tsc": "^3.0.1"
}
}

1036
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import { BlogHeader, useProvidingPosts } from '@/widgets/Blog';
import { BlogList } from '@/widgets/Blog';
import { BlogHeader, BlogList, useProvidingPosts } from '@/widgets/Blog';
useProvidingPosts(() => fetch('/posts.json').then((response) => {
if (!response.ok) {

View File

@@ -1,4 +1,5 @@
import { type MaybeRefOrGetter, onScopeDispose, toValue, watchEffect } from 'vue';
import type { MaybeRefOrGetter } from 'vue';
import { onScopeDispose, toValue, watchEffect } from 'vue';
export function useBodyScrollLock(isLocked: MaybeRefOrGetter<boolean>) {
let originalOverflow: string | null = null;

View File

@@ -1,5 +1,6 @@
import type { TemplateRef } from 'vue';
import { clamp } from '@robonen/stdlib';
import { nextTick, onMounted, onUnmounted, ref, type TemplateRef, watch } from 'vue';
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
export function useTextAreaAutosize(textareaRef: TemplateRef<HTMLTextAreaElement | null>) {
const minHeight = ref(0);

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import { type BadgeVariant, badgeVariants } from './types';
import type { BadgeVariant } from './types';
import { badgeVariants } from './types';
export interface BadgeProps {
variant?: BadgeVariant;

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import type { ButtonProps } from './types';
import { computed } from 'vue';
import { type ButtonProps, buttonSizes, buttonVariants } from './types';
import { buttonSizes, buttonVariants } from './types';
const props = withDefaults(defineProps<ButtonProps>(), {
variant: 'primary',

View File

@@ -41,6 +41,8 @@ describe('blog Context', () => {
const context = useProvidingPosts(mockLoader);
expect(context.loading.value).toBe(true);
await nextTick();
await nextTick();
expect(mockLoader).toHaveBeenCalled();
@@ -115,6 +117,8 @@ describe('blog Context', () => {
it('should return available tags from all posts', async () => {
const context = useProvidingPosts(mockLoader);
await nextTick();
await nextTick();
const expectedTags = ['vue', 'javascript', 'frontend', 'typescript', 'react', 'comparison'];
@@ -158,6 +162,7 @@ describe('blog Context', () => {
const context = useProvidingPosts(errorLoader);
await nextTick();
await nextTick();
expect(consoleErrorSpy).toHaveBeenCalledWith('Failed to load posts:', expect.any(Error));
expect(context.loading.value).toBe(false);

View File

@@ -1,7 +1,7 @@
import type { PostComment } from '@/entities/Comment';
import type { Post } from '@/entities/Post';
import { useInjectionStore } from '@robonen/vue';
import { computed, reactive, ref, shallowRef } from 'vue';
import { useAsyncState, useInjectionStore } from '@robonen/vue';
import { computed, reactive, shallowRef } from 'vue';
import { kmpSearch } from '@/shared/utils';
type PostItem = Post & {
@@ -16,8 +16,22 @@ export const {
useProvidingState: useProvidingPosts,
useInjectedState: useInjectedPosts,
} = useInjectionStore((loader: () => Promise<any>) => {
const posts = shallowRef<PostItem[]>([]);
const loading = ref(false);
const {
state: posts,
isLoading: loading,
executeImmediately: loadPosts,
} = useAsyncState<PostItem[]>(
async () => {
const response = await loader();
return response.data as PostItem[];
},
[],
{
onError(error) {
console.error('Failed to load posts:', error);
},
},
);
const selectedPost = shallowRef<PostItem | null>(null);
@@ -54,21 +68,6 @@ export const {
return Array.from(tagsSet);
});
const loadPosts = async () => {
loading.value = true;
try {
const data = await loader();
posts.value = data!.data as PostItem[];
}
catch (error) {
console.error('Failed to load posts:', error);
}
finally {
loading.value = false;
}
};
function toggleTag(tag: string) {
if (filters.tags.has(tag))
filters.tags.delete(tag);
@@ -85,9 +84,6 @@ export const {
filters.tags.clear();
}
// Initial load
loadPosts();
return {
posts,
loading,

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import type { NavigationMenuItem } from '../NavigationMenu';
import { Logo } from '@/shared/icons';
import { NavigationMenu, type NavigationMenuItem } from '../NavigationMenu';
import { NavigationMenu } from '../NavigationMenu';
const items = [
{ name: 'Главная', path: '/' },