Skip to content

Commit

Permalink
add userlist component
Browse files Browse the repository at this point in the history
styles for link
  • Loading branch information
ufaboy committed Dec 30, 2023
1 parent a748520 commit 8d30e95
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 55 deletions.
15 changes: 15 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,20 @@
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script>
const style = 'font-size:16px;';
console.log(`
%c*******************************************************
Hi,I am Azat Kashapov. Frontend Developer.
I love working with Vue, Pinia, Tailwind, Nuxt, Typescript,
WebSocket, GraphQL, TanStack Query, Web Extensions, Crypto,
Node.js (Fastify, Express)
If you have questions, pls text me https://t.me/ufaboy
or https://www.linkedin.com/in/azat-kashapov/
Have a nice day!
*******************************************************`, style)
</script>
</body>
</html>
50 changes: 3 additions & 47 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,53 +1,9 @@
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { useUsers } from '@/composables/user';
import IconSpinner from '@/components/IconSpinner.vue';
import UserCard from '@/components/UserCard.vue';
const { users, query, observerShow, getUsers } = useUsers();
// Reference to the IntersectionObserver instance.
const observer = ref<IntersectionObserver>();
// Reference to the HTML element used for the observer.
const observerElement = ref<HTMLInputElement | null>(null);
/**
* Lifecycle hook that is called after the component is mounted.
* It initializes an IntersectionObserver to load more users when the observer element is in view.
*/
onMounted(() => {
observer.value = new IntersectionObserver(
([entry]) => {
if (entry && entry.isIntersecting) {
getUsers();
query.value.page++;
}
},
{ threshold: 0.5 },
);
// Observes the specified element for intersection changes.
if (observerElement.value) observer.value.observe(observerElement.value);
});
/**
* Lifecycle hook that is called before the component is unmounted.
* It disconnects the IntersectionObserver to clean up resources.
* In this case it is not needed, but usually such observers are transferred to the plugin,
* and there you will already need it
*/
onBeforeUnmount(() => {
observer.value?.disconnect();
});
import UserList from './components/UserList.vue';
</script>

<template>
<main class="">
<h1 class="mb-8 px-4 py-2">User List</h1>
<!-- new syntax 3.4 short same bind :user -->
<UserCard v-for="(user, index) in users" :key="index" :user class="mt-3 first:mt-0" />
<div v-if="observerShow" ref="observerElement" class="flex justify-center items-center">
<IconSpinner />
</div>
<main>
<UserList />
</main>
</template>
26 changes: 25 additions & 1 deletion src/assets/style/style.css
Original file line number Diff line number Diff line change
@@ -1 +1,25 @@
@import './tailwind.css'
@import './tailwind.css';


.underline {
display: inline-block;
position: relative;
text-decoration: none;
color: black;
}

.underline::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 2px;
background-color: black;
transition: width 0.3s ease, left 0.3s ease;
}

.underline:hover::after {
width: 100%;
left: 0;
}
15 changes: 11 additions & 4 deletions src/components/UserCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { User } from '@/interfaces';
const props = defineProps<{
user: User;
}>();
const fullName = computed(() => {
return `${props.user.name.title} ${props.user.name.first} ${props.user.name.last}`;
});
Expand All @@ -17,14 +18,20 @@ const fullName = computed(() => {
alt="avatar"
width="100"
height="100"
onerror="this.onerror=null;this.src = '/default_avatar.svg'"
class="rounded-md hover:scale-110 cursor-pointer"
onerror="this.onerror=null;this.src = '/emcd-task/default_avatar.svg'"
class="rounded-md hover:scale-110 transition cursor-pointer"
/>
<figcaption class="flex flex-col ju gap-3">
<span class="max-w-52 md:max-w-min truncate font-semibold text-lg" :title="fullName">
<span class="max-w-56 md:max-w-min truncate font-semibold text-lg" :title="fullName">
{{ fullName }}
</span>
<span class="max-w-52 md:max-w-min truncate" :title="user.email">{{ user.email }}</span>
<a
:href="`mailto:${user.email}`"
class="underline max-w-56 md:max-w-min truncate"
:title="user.email"
>
{{ user.email }}
</a>
</figcaption>
</figure>
</template>
53 changes: 53 additions & 0 deletions src/components/UserList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { useUsers } from '@/composables/user';
import IconSpinner from '@/components/IconSpinner.vue';
import UserCard from '@/components/UserCard.vue';
const { users, query, observerShow, getUsers } = useUsers();
// Reference to the IntersectionObserver instance.
const observer = ref<IntersectionObserver>();
// Reference to the HTML element used for the observer.
const observerElement = ref<HTMLInputElement | null>(null);
/**
* Lifecycle hook that is called after the component is mounted.
* It initializes an IntersectionObserver to load more users when the observer element is in view.
*/
onMounted(() => {
observer.value = new IntersectionObserver(
([entry]) => {
if (entry && entry.isIntersecting) {
getUsers();
query.value.page++;
}
},
{ threshold: 0.5 },
);
// Observes the specified element for intersection changes.
if (observerElement.value) observer.value.observe(observerElement.value);
});
/**
* Lifecycle hook that is called before the component is unmounted.
* It disconnects the IntersectionObserver to clean up resources.
* In this case it is not needed, but usually such observers are transferred to the plugin,
* and there you will already need it
*/
onBeforeUnmount(() => {
observer.value?.disconnect();
});
</script>

<template>
<h1 class="mb-8 px-4 py-2">User List</h1>
<!-- new syntax 3.4 short same bind :user -->
<UserCard v-for="(user, index) in users" :key="index" :user class="mt-3 first:mt-0" />
<div v-if="observerShow" ref="observerElement" class="flex justify-center items-center">
<IconSpinner />
</div>
</template>
6 changes: 3 additions & 3 deletions src/composables/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export function useUsers() {
const url = getUrl(query.value);
loading.value = true;
const response = await fetchData<UserResponse>(url);
/* I usually use this code: users.value.push(...response.results);
There is an opinion that this method is not much inferior to apply */
Array.prototype.push.apply(users.value, response.results);
/* I usually use this code, there is an opinion that this method is not much inferior to apply:
Array.prototype.push.apply(users.value, response.results); */
users.value.push(...response.results);
} catch (error) {
console.log('getUsers error:', error);
} finally {
Expand Down

0 comments on commit 8d30e95

Please sign in to comment.