Compare commits
3 Commits
main
...
shadi/deve
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4462c62e6c | ||
![]() |
6299d5ec81 | ||
![]() |
54fe65d31a |
|
@ -1,5 +1,5 @@
|
||||||
NUXT_PUBLIC_API_NAME=api/
|
VITE_API_NAME=api/
|
||||||
NUXT_PUBLIC_BASE_URL=http://192.168.23.60/
|
VITE_BASE_URL=http://192.168.23.60/
|
||||||
|
|
||||||
VITE_APP_NAME=Hadith
|
VITE_APP_NAME=Hadith
|
||||||
|
|
||||||
|
|
|
@ -1,289 +0,0 @@
|
||||||
1. Organize Your Code into Logical Sections
|
|
||||||
|
|
||||||
Structure your component script into clear sections to improve readability. A common approach is to group related logic together.
|
|
||||||
Example Structure:
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 1. Imports
|
|
||||||
import { ref, computed, onMounted } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
// 2. Reactive State
|
|
||||||
const count = ref(0)
|
|
||||||
const name = ref('')
|
|
||||||
|
|
||||||
// 3. Computed Properties
|
|
||||||
const doubledCount = computed(() => count.value * 2)
|
|
||||||
|
|
||||||
// 4. Functions / Methods
|
|
||||||
function increment() {
|
|
||||||
count.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Lifecycle Hooks
|
|
||||||
onMounted(() => {
|
|
||||||
console.log('Component mounted')
|
|
||||||
})
|
|
||||||
|
|
||||||
// 6. Watchers
|
|
||||||
watch(count, (newValue, oldValue) => {
|
|
||||||
console.log(`Count changed from ${oldValue} to ${newValue}`)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
2. Use script setup Syntax
|
|
||||||
|
|
||||||
The <script setup> syntax is the recommended way to write Composition API components. It provides a more concise and intuitive syntax.
|
|
||||||
Example:
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const message = ref('Hello, Vue 3!')
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
3. Use Descriptive Variable and Function Names
|
|
||||||
|
|
||||||
Choose meaningful names for variables, functions, and computed properties to make your code self-documenting.
|
|
||||||
Example:
|
|
||||||
// Bad
|
|
||||||
const x = ref(0)
|
|
||||||
|
|
||||||
// Good
|
|
||||||
const userCount = ref(0)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
4. Extract Reusable Logic into Composables
|
|
||||||
Move reusable logic into composables (custom hooks) to keep your components clean and promote code reuse.
|
|
||||||
Example Composable:
|
|
||||||
|
|
||||||
// composables/useCounter.js
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
export function useCounter(initialValue = 0) {
|
|
||||||
const count = ref(initialValue)
|
|
||||||
|
|
||||||
function increment() {
|
|
||||||
count.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
function reset() {
|
|
||||||
count.value = initialValue
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
count,
|
|
||||||
increment,
|
|
||||||
reset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Usage in a Component:
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { useCounter } from '~/composables/useCounter'
|
|
||||||
|
|
||||||
const { count, increment } = useCounter()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<p>Count: {{ count }}</p>
|
|
||||||
<button @click="increment">Increment</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
5. Use ref for Primitive Values and reactive for Objects
|
|
||||||
|
|
||||||
- Use ref for primitive values (e.g., numbers, strings, booleans).
|
|
||||||
- Use reactive for objects or arrays.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
const count = ref(0) // Primitive value
|
|
||||||
const user = reactive({ name: 'John', age: 30 }) // Object
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
6. Use Computed Properties for Derived State
|
|
||||||
|
|
||||||
Use computed to create reactive properties that depend on other state. This ensures the derived state is always up-to-date.
|
|
||||||
Example:
|
|
||||||
const firstName = ref('John')
|
|
||||||
const lastName = ref('Doe')
|
|
||||||
|
|
||||||
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
7. Use Watchers Sparingly
|
|
||||||
|
|
||||||
Watchers (watch and watchEffect) are powerful but can make your code harder to understand if overused. Prefer computed properties or event-driven updates where possible.
|
|
||||||
Example:
|
|
||||||
watch(count, (newValue, oldValue) => {
|
|
||||||
console.log(`Count changed from ${oldValue} to ${newValue}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
8. Group Related Logic Together
|
|
||||||
|
|
||||||
Keep related reactive state, computed properties, and functions together to make your code easier to follow.
|
|
||||||
Example:
|
|
||||||
// User-related logic
|
|
||||||
const user = reactive({ name: 'John', age: 30 })
|
|
||||||
const isAdult = computed(() => user.age >= 18)
|
|
||||||
function updateUser(newName) {
|
|
||||||
user.name = newName
|
|
||||||
}
|
|
||||||
|
|
||||||
-----------
|
|
||||||
|
|
||||||
9. Use Lifecycle Hooks for Side Effects
|
|
||||||
|
|
||||||
Use lifecycle hooks (onMounted, onUnmounted, etc.) for side effects like fetching data or setting up event listeners.
|
|
||||||
Example:
|
|
||||||
onMounted(() => {
|
|
||||||
console.log('Component mounted')
|
|
||||||
fetchData()
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
console.log('Component unmounted')
|
|
||||||
cleanup()
|
|
||||||
})
|
|
||||||
|
|
||||||
----------------
|
|
||||||
|
|
||||||
10. Use TypeScript for Better Type Safety
|
|
||||||
If your project uses TypeScript, leverage it to add type safety to your components.
|
|
||||||
Example:
|
|
||||||
<script setup lang="ts">
|
|
||||||
interface User {
|
|
||||||
name: string
|
|
||||||
age: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = ref<User>({ name: 'John', age: 30 })
|
|
||||||
</script>
|
|
||||||
|
|
||||||
--------------
|
|
||||||
|
|
||||||
11. Keep Templates Clean
|
|
||||||
|
|
||||||
Avoid putting too much logic in your template. Instead, move complex logic into the script or composables.
|
|
||||||
Example:
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<p>{{ fullName }}</p>
|
|
||||||
<button @click="increment">Increment</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const firstName = ref('John')
|
|
||||||
const lastName = ref('Doe')
|
|
||||||
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
|
|
||||||
|
|
||||||
function increment() {
|
|
||||||
// Logic here
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
------------
|
|
||||||
|
|
||||||
12. Use provide and inject for Prop Drilling
|
|
||||||
Avoid prop drilling by using provide and inject to share state across deeply nested components.
|
|
||||||
Example:
|
|
||||||
// Parent component
|
|
||||||
import { provide, ref } from 'vue'
|
|
||||||
|
|
||||||
const theme = ref('dark')
|
|
||||||
provide('theme', theme)
|
|
||||||
|
|
||||||
// Child component
|
|
||||||
import { inject } from 'vue'
|
|
||||||
|
|
||||||
const theme = inject('theme')
|
|
||||||
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
13. Use v-model for Two-Way Binding
|
|
||||||
|
|
||||||
Use v-model to simplify two-way binding between parent and child components.
|
|
||||||
Example:
|
|
||||||
<!-- Parent component -->
|
|
||||||
<template>
|
|
||||||
<ChildComponent v-model:name="userName" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const userName = ref('John')
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Child component -->
|
|
||||||
<template>
|
|
||||||
<input :value="name" @input="$emit('update:name', $event.target.value)" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
defineProps(['name'])
|
|
||||||
defineEmits(['update:name'])
|
|
||||||
</script>
|
|
||||||
|
|
||||||
----------
|
|
||||||
|
|
||||||
14. Use defineProps and defineEmits for TypeScript Support
|
|
||||||
|
|
||||||
When using TypeScript, use defineProps and defineEmits to define props and emits with type safety.
|
|
||||||
Example:
|
|
||||||
<script setup lang="ts">
|
|
||||||
const props = defineProps<{
|
|
||||||
title: string
|
|
||||||
count: number
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(event: 'update:count', value: number): void
|
|
||||||
}>()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
-------------
|
|
||||||
|
|
||||||
15. Use Scoped Styles
|
|
||||||
|
|
||||||
Use scoped styles (<style scoped>) to ensure styles are component-specific and don’t leak into other components.
|
|
||||||
Example:
|
|
||||||
<style scoped>
|
|
||||||
.button {
|
|
||||||
background-color: blue;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
------------------
|
|
||||||
|
|
||||||
16. Use Environment Variables
|
|
||||||
|
|
||||||
Use environment variables for configuration (e.g., API URLs) to keep your code flexible and secure.
|
|
||||||
Example:
|
|
||||||
const apiUrl = import.meta.env.VITE_API_URL
|
|
||||||
|
|
||||||
-------------
|
|
||||||
|
|
||||||
17. Write Unit Tests
|
|
||||||
|
|
||||||
Write unit tests for your components and composables to ensure they work as expected.
|
|
||||||
Example:
|
|
||||||
import { render } from '@testing-library/vue'
|
|
||||||
import MyComponent from '@/components/MyComponent.vue'
|
|
||||||
|
|
||||||
test('renders correctly', () => {
|
|
||||||
const { getByText } = render(MyComponent)
|
|
||||||
expect(getByText('Hello, Vue 3!')).toBeInTheDocument()
|
|
||||||
})
|
|
|
@ -36,7 +36,7 @@ If it is, remove it from the index
|
||||||
git rm --cached systems/chat_ui
|
git rm --cached systems/chat_ui
|
||||||
|
|
||||||
If system/chat_ui exits, remote it(chat_ui)
|
If system/chat_ui exits, remote it(chat_ui)
|
||||||
rm -r systems/chat_ui
|
rm -rf systems/chat_ui
|
||||||
|
|
||||||
Add the submodule
|
Add the submodule
|
||||||
git submodule add https://github.com/example/repo.git systems/chat_ui
|
git submodule add https://github.com/example/repo.git systems/chat_ui
|
||||||
|
|
18
app.vue
18
app.vue
|
@ -2,9 +2,27 @@
|
||||||
<UApp :locale="fa_ir">
|
<UApp :locale="fa_ir">
|
||||||
<NuxtLoadingIndicator />
|
<NuxtLoadingIndicator />
|
||||||
<NuxtRouteAnnouncer />
|
<NuxtRouteAnnouncer />
|
||||||
|
<!-- <DevOnly> -->
|
||||||
|
<!-- this component will only be rendered during development -->
|
||||||
|
<!-- <LazyDebugBar /> -->
|
||||||
|
|
||||||
|
<!-- if you ever require to have a replacement during production -->
|
||||||
|
<!-- be sure to test these using `nuxt preview` -->
|
||||||
|
<!-- <template #fallback> -->
|
||||||
|
<!-- <div>empty div for flex.justify-between</div> -->
|
||||||
|
<!-- </template> -->
|
||||||
|
<!-- </DevOnly> -->
|
||||||
|
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
|
<!-- this component will be rendered on client-side -->
|
||||||
|
<!-- <NuxtClientFallback
|
||||||
|
fallback-tag="span"
|
||||||
|
fallback="NuxtClientFallback"
|
||||||
|
@ssr-error="logSomeError"
|
||||||
|
> -->
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
|
<!-- <BrokeInSsr /> -->
|
||||||
|
<!-- </NuxtClientFallback> -->
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</UApp>
|
</UApp>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
// composables/useHadithaSearchComposable.js
|
|
||||||
import { useStorage } from "@vueuse/core";
|
|
||||||
|
|
||||||
export const useHadithaSearchComposable = <T>(url: string, options = {}) => {
|
|
||||||
// Get the authentication token (e.g., from a cookie or local storage)
|
|
||||||
// const token = useCookie('auth-token') // Assuming you store the token in a cookie
|
|
||||||
let token = useStorage("id_token", "GuestAccess");
|
|
||||||
const config = useRuntimeConfig();
|
|
||||||
console.info(config);
|
|
||||||
|
|
||||||
const baseURL =
|
|
||||||
config.public.NUXT_PUBLIC_BASE_URL + config.public.NUXT_PUBLIC_API_NAME;
|
|
||||||
|
|
||||||
// Add headers to the request
|
|
||||||
const headers = {
|
|
||||||
Authorization: token.value,
|
|
||||||
...options.headers, // Merge with any existing headers
|
|
||||||
};
|
|
||||||
|
|
||||||
// Use useFetch with the headers
|
|
||||||
return useFetch<T>(url, {
|
|
||||||
...options,
|
|
||||||
baseURL,
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -13,7 +13,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||||
onRequest({ request, options, error }) {
|
onRequest({ request, options, error }) {
|
||||||
options.baseURL =
|
options.baseURL =
|
||||||
import.meta.env.VITE_BASE_URL +
|
import.meta.env.VITE_BASE_URL +
|
||||||
import.meta.env.NUXT_PUBLIC_API_NAME+
|
import.meta.env.VITE_API_NAME +
|
||||||
options.baseURL;
|
options.baseURL;
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|
|
@ -3,13 +3,12 @@ import { useStorage } from "@vueuse/core";
|
||||||
|
|
||||||
export default defineNuxtPlugin((nuxtApp) => {
|
export default defineNuxtPlugin((nuxtApp) => {
|
||||||
let token = useStorage("id_token", "GuestAccess").value;
|
let token = useStorage("id_token", "GuestAccess").value;
|
||||||
const config = useRuntimeConfig();
|
|
||||||
|
|
||||||
const api = $fetch.create({
|
const api = $fetch.create({
|
||||||
onRequest({ request, options, error }) {
|
onRequest({ request, options, error }) {
|
||||||
options.baseURL =
|
options.baseURL =
|
||||||
config.public.NUXT_PUBLIC_BASE_URL +
|
import.meta.env.VITE_BASE_URL +
|
||||||
config.public.NUXT_PUBLIC_API_NAME +
|
import.meta.env.VITE_API_NAME +
|
||||||
options.baseURL;
|
options.baseURL;
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
|
@ -41,14 +40,13 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||||
getRequest: (url, options = {}) => api(url, { method: "GET", ...options }),
|
getRequest: (url, options = {}) => api(url, { method: "GET", ...options }),
|
||||||
postRequest: (url, body, options = {}) =>
|
postRequest: (url, body, options = {}) =>
|
||||||
api(url, { method: "POST", body, ...options }),
|
api(url, { method: "POST", body, ...options }),
|
||||||
deleteRequest: (url, options = {}) =>
|
deleteRequest: (url, options = {}) => api(url, { method: "DELETE", ...options }),
|
||||||
api(url, { method: "DELETE", ...options }),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Expose to useNuxtApp().$api and useNuxtApp().$http
|
// Expose to useNuxtApp().$api and useNuxtApp().$http
|
||||||
return {
|
return {
|
||||||
provide: {
|
provide: {
|
||||||
http,
|
http
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,12 +9,6 @@ export default [
|
||||||
path: "/haditha/search",
|
path: "/haditha/search",
|
||||||
file: "~/systems/hadith_ui/pages/haditha/search/index.vue",
|
file: "~/systems/hadith_ui/pages/haditha/search/index.vue",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "hadithaSearchShow",
|
|
||||||
path: "/haditha/search/:id/:slug?",
|
|
||||||
file: "~/systems/hadith_ui/pages/haditha/search/[id]/[slug]/index.vue",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "hadithaChatBot",
|
name: "hadithaChatBot",
|
||||||
path: "/haditha/chat-bot",
|
path: "/haditha/chat-bot",
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2a5f878608e9cc9e508ab4de70337c2673344596
|
Subproject commit be90244a87e87eb66759bd10fabf5e881998b055
|
|
@ -1 +1 @@
|
||||||
Subproject commit 832f5dbf525ebddbcfa8873b5b3c88325f446a3c
|
Subproject commit 953d98f3beb62044c320f5fcfb8a000f5e8264d0
|
|
@ -275,7 +275,7 @@ export const userAvatar = (user = undefined) => {
|
||||||
if (user?.avatar && user?.avatar?.length) {
|
if (user?.avatar && user?.avatar?.length) {
|
||||||
return (
|
return (
|
||||||
import.meta.env.VITE_BASE_URL +
|
import.meta.env.VITE_BASE_URL +
|
||||||
import.meta.env.NUXT_PUBLIC_API_NAME+
|
import.meta.env.VITE_API_NAME +
|
||||||
fileUrl() +
|
fileUrl() +
|
||||||
user.avatar
|
user.avatar
|
||||||
);
|
);
|
||||||
|
@ -362,9 +362,9 @@ export const getGroupAvatar = async (user = undefined) => {
|
||||||
const initials = nameArray[0].charAt(0);
|
const initials = nameArray[0].charAt(0);
|
||||||
return generateAvatarFromChars(initials);
|
return generateAvatarFromChars(initials);
|
||||||
}
|
}
|
||||||
|
} else return (await import("~/assets/common/img/default.svg")).default;
|
||||||
}
|
}
|
||||||
}
|
} else return (await import("~/assets/common/img/default.svg")).default;
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return (await import("~/assets/common/img/default.svg")).default;
|
return (await import("~/assets/common/img/default.svg")).default;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ export async function useAPI<T>(
|
||||||
url: string | (() => string),
|
url: string | (() => string),
|
||||||
options?: UseFetchOptions<T>
|
options?: UseFetchOptions<T>
|
||||||
) {
|
) {
|
||||||
const prexFixUrlWithApiName = import.meta.env.NUXT_PUBLIC_API_NAME+ url;
|
const prexFixUrlWithApiName = import.meta.env.VITE_API_NAME + url;
|
||||||
|
|
||||||
return await useFetch(prexFixUrlWithApiName, {
|
return await useFetch(prexFixUrlWithApiName, {
|
||||||
...options,
|
...options,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user