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:
@@ -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',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
28
package.json
28
package.json
@@ -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
1036
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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: '/' },
|
||||
|
||||
Reference in New Issue
Block a user