This commit is contained in:
Parsa Nazer
2025-02-10 18:18:21 +03:30
26 changed files with 716 additions and 31 deletions
+36
View File
@@ -271,4 +271,40 @@
button {
@apply cursor-pointer;
}
.vpd-main {
@apply !w-full !border-none !p-0;
}
.vpd-input-group {
@apply !flex-row-reverse;
}
.vpd-input-group > input {
@apply !border-e-0 !rounded-none !rounded-s-100 !px-4;
}
.vpd-input-group > label {
@apply !rounded-e-100;
}
.vpd-main > .vpd-wrapper > .vpd-container {
@apply !rounded-xl !overflow-hidden;
}
.vpd-main.error > .vpd-input-group > #vpd-vpd-date-picker {
@apply border-danger-600 border-2;
}
.vpd-main > .vpd-input-group > .vpd-icon-btn {
@apply !bg-black;
}
.vpd-main.error > .vpd-input-group > .vpd-icon-btn {
@apply bg-danger-600 border-danger-600 border-t-2 border-r-2 border-b;
}
.vpd-controls button {
@apply flex justify-center items-center;
}
}
+48
View File
@@ -0,0 +1,48 @@
<script setup lang="ts">
// imports
import DatePicker from "vue3-persian-datetime-picker";
// types
type Props = {
modelValue: string;
};
type Emits = {
"update:modelValue": [value: string];
};
// props
const props = defineProps<Props>();
const { modelValue } = toRefs(props);
// emit
const emit = defineEmits<Emits>();
// computed
const value = computed({
get: () => modelValue.value ?? "",
set: (value) => emit("update:modelValue", value),
});
</script>
<template>
<ClientOnly>
<DatePicker
format="jYYYY-jMM-jDD"
displayFormat="jYYYY-jMM-jDD"
:editable="false"
placeholder="وارد نشده"
altFormat="jYYYY-jMM-jDD"
color="#000000"
inputClass="!py-3.5 placeholder-slate-400 rounded-e-100 !border-[1.5px] hover:!border-black !transition-all !border-slate-200 !text-sm"
:autoSubmit="false"
v-model="value"
/>
</ClientOnly>
</template>
+1 -1
View File
@@ -43,7 +43,7 @@ const isHomePage = computed(() => route.path === "/");
? `${account.first_name.charAt(
0
)} ${account.last_name.charAt(0)}`
: ''
: 'بدون نام کاربری'
"
/>
</NuxtLink>
+10 -10
View File
@@ -5,15 +5,17 @@ type Props = {
error?: boolean;
message?: string;
placeholder?: string;
modelValue?: string;
modelValue: string;
};
// props
const props = withDefaults(defineProps<Props>(), {
variant: "solid",
disabled: false,
placeholder: "وارد نشده",
});
const { variant, message, error, disabled } = toRefs(props);
const { variant, message, error, disabled, modelValue } = toRefs(props);
// emits
@@ -25,6 +27,11 @@ const inputRef = ref<HTMLInputElement | null>(null);
// computed
const value = computed({
get: () => modelValue.value ?? "",
set: (value) => emit("update:modelValue", value),
});
const classes = computed(() => {
return [
"flex items-center text-black justify-between cursor-text transition-all border-[1.5px] gap-3 typo-label-md px-4 py-3.5 selection:bg-slate-100 rounded-100",
@@ -38,12 +45,6 @@ const classes = computed(() => {
},
];
});
// methods
const onInput = (e: any) => {
emit("update:modelValue", e.target.value);
};
</script>
<template>
@@ -51,8 +52,7 @@ const onInput = (e: any) => {
<slot name="startItem" />
<input
:value="modelValue"
@input="onInput"
v-model="value"
ref="inputRef"
class="outline-none flex-1 text-sm placeholder-slate-400"
:placeholder="placeholder"
+94
View File
@@ -0,0 +1,94 @@
<script setup lang="ts">
// types
type Props = {
modelValue: boolean;
icon?: string;
title: string;
iconSize?: string;
};
type Emits = {
"update:modelValue": [value: boolean];
close: [value: null];
};
// props
const props = defineProps<Props>();
const { modelValue } = toRefs(props);
// emit
const emit = defineEmits<Emits>();
// computed
const isShow = computed({
get: () => modelValue.value ?? false,
set: (value) => {
emit("update:modelValue", value);
emit("close", null);
},
});
</script>
<template>
<DialogRoot v-model:open="isShow">
<DialogTrigger>
<slot name="trigger" />
</DialogTrigger>
<DialogPortal>
<DialogOverlay
class="bg-black/50 backdrop-blur-sm data-[state=open]:animate-overlay-show fixed inset-0 z-999"
/>
<div
class="fixed inset-0 w-full h-svh z-9999 flex-center"
v-if="isShow"
>
<div
class="overflow-y-auto max-h-svh absolute left-[50%] py-10 w-fit max-w-[50rem] translate-x-[-50%]"
>
<DialogContent
class="data-[state=open]:animate-content-show text-black font-iran-yekan-x focus:outline-none z-[100]"
>
<div
class="rounded-3xl bg-white shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px]"
>
<div
class="w-full flex items-center px-6 justify-between py-[1.5rem] border-b border-slate-200"
>
<DialogClose
class="inline-flex size-8 items-center justify-center transition-all rounded-full bg-gray-50 border border-slate-200 hover:border-black focus:outline-none"
aria-label="Close"
>
<Icon
name="bi:x-lg"
class="**:fill-black"
/>
</DialogClose>
<DialogTitle
class="typo-sub-h-xl font-semibold flex items-center gap-3"
>
{{ title }}
<Icon
v-if="!!icon"
:name="icon"
:size="iconSize"
/>
</DialogTitle>
</div>
<div class="w-full px-6">
<slot name="content" />
</div>
</div>
</DialogContent>
</div>
</div>
</DialogPortal>
</DialogRoot>
</template>
<style scoped></style>
+30 -12
View File
@@ -2,45 +2,63 @@
// types
type Props = {
variant?: "solid" | "outlined";
disabled?: boolean;
modelValue: string;
error?: boolean;
options: string[];
placeholder: string;
placeholder?: string;
};
type Emit = {
type Emits = {
"update:modelValue": [value: string];
};
// props
const props = defineProps<Props>();
const props = withDefaults(defineProps<Props>(), {
variant: "solid",
disabled: false,
placeholder: "وارد نشده",
});
const { modelValue } = toRefs(props);
const { modelValue, variant, error } = toRefs(props);
// emit
const emit = defineEmits<Emit>();
const emit = defineEmits<Emits>();
// state
// computed
const selectedValue = computed({
get: () => modelValue.value,
get: () => modelValue.value ?? undefined,
set: (value: string) => emit("update:modelValue", value),
});
const classes = computed(() => {
return [
"flex items-center text-black justify-between cursor-text transition-all border-[1.5px] gap-3 typo-label-md px-4 py-3.5 selection:bg-slate-100 rounded-100 flex-1 w-full outline-none",
{
"input-solid": variant.value === "solid",
"input-outlined": variant.value === "outlined",
"input-effects": !error.value,
[variant.value === "solid"
? "input-solid-error"
: "input-outlined-error"]: error.value,
},
];
});
// watch
</script>
<template>
<SelectRoot v-model="selectedValue" dir="rtl">
<SelectTrigger
class="w-full flex items-center justify-between resize-none bg-slate-50 border-slate-200 hover:border-black focus:border-black h-[10rem] max-h-[12rem] text-black cursor-pointer transition-all border-[1.5px] gap-3 typo-label-md px-4 py-[12.5px] selection:bg-slate-100 rounded-100 outline-none flex-1 !text-sm placeholder-slate-400"
aria-label="Customise options"
>
<SelectTrigger :class="classes" class="" aria-label="Customise options">
<SelectValue
:placeholder="placeholder"
:class="selectedValue ? 'text-black' : 'text-slate-400'"
class="font-iran-yekan-x"
class="font-iran-yekan-x text-sm placeholder-slate-400"
/>
<Icon name="bi:chevron-down" size="16" />
</SelectTrigger>
+2 -2
View File
@@ -5,7 +5,7 @@ type Props = {
modelValue: boolean;
};
type Emit = {
type Emits = {
"update:modelValue": [value: boolean];
};
@@ -17,7 +17,7 @@ const { modelValue } = toRefs(props);
// emit
const emit = defineEmits<Emit>();
const emit = defineEmits<Emits>();
// computed
@@ -0,0 +1,30 @@
<script setup lang="ts">
// types
type Props = {
title: string;
icon: string;
};
// props
defineProps<Props>();
</script>
<template>
<div
class="flex items-center justify-between w-full gap-3 px-5 py-4 rounded-xl bg-slate-50 border border-slate-200"
>
<div class="flex items-center w-full gap-3 lg:w-1/2">
<button class="flex-center lg:hidden">
<Icon name="bi:chevron-right" size="24" class="**:fill-black" />
</button>
<p class="font-semibold lg:text-lg text-black">
{{ title }}
</p>
</div>
<Icon :name="icon" size="24" class="**:fill-black" />
</div>
</template>
<style scoped></style>
@@ -0,0 +1,28 @@
<script setup lang="ts">
// types
type Props = {
title: string;
};
// props
defineProps<Props>();
</script>
<template>
<div class="flex flex-col w-full">
<div class="flex flex-col items-start">
<div class="w-full flex items-center p-5">
<span class="typo-sub-h-lg">{{ title }}</span>
</div>
</div>
<div class="w-full flex flex-col border border-slate-200 rounded-xl">
<div class="w-full p-5">
<slot />
</div>
</div>
</div>
</template>
<style scoped></style>
@@ -3,6 +3,33 @@
import useGetAccount from "~/composables/api/account/useGetAccount";
// state
const route = useRoute();
const profileLinks = ref([
{
icon: "bi:person-vcard",
title: "پروفایل",
path: { name: "profile" },
},
{
icon: "bi:map",
title: "آدرس ها",
path: { name: "profile-addresses" },
},
{
icon: "bi:cart",
title: "خرید ها و سفارش ها",
path: { name: "profile-purchases-and-orders" },
},
{
icon: "bi:ticket",
title: "تیکت ها",
path: { name: "profile-tickets" },
},
]);
// queries
const { data: account, suspense } = useGetAccount();
@@ -30,6 +57,31 @@ await suspense();
/>
</div>
</div>
<div
class="w-full flex flex-col gap-2 rounded-xl bg-slate-50 border border-slate-200 p-4"
>
<NuxtLink
v-for="(link, index) in profileLinks"
:key="index"
:to="{ ...link.path }"
:class="
route.name == link.path.name
? 'bg-black text-slate-100 **:fill-slate-100 '
: '**:fill-black '
"
class="flex items-center justify-between transition-all rounded-lg py-4 px-3"
>
<span class="flex-center gap-3">
<div class="size-5 flex-center">
<Icon :name="link.icon" />
</div>
<span class="text-sm">{{ link.title }}</span>
</span>
<Icon name="bi:chevron-left" class="transition-all" />
</NuxtLink>
</div>
</div>
</template>
@@ -0,0 +1,23 @@
<script setup lang="ts">
// types
type Props = {
title: string;
};
// props
defineProps<Props>();
</script>
<template>
<div
class="flex items-center w-full lg:py-4 lg:border-b px-5 border-slate-200"
>
<p class="font-semibold lg:text-lg text-black">
{{ title }}
</p>
</div>
</template>
<style scoped></style>
@@ -0,0 +1,33 @@
<script setup lang="ts">
// types
type Props = {
id?: string;
label: string;
required?: boolean;
error?: any;
};
// props
withDefaults(defineProps<Props>(), {
required: false,
});
</script>
<template>
<div class="w-full flex flex-col gap-2">
<div class="flex items-center gap-1 ps-2">
<label :for="id" class="typo-label-sm">{{ label }}</label>
<span v-if="required" class="text-danger-600">*</span>
</div>
<slot />
<div
class="w-full typo-label-xs flex items-center py-1 px-3 rounded-md text-danger-600"
>
این فیلد الزامی است
</div>
</div>
</template>
<style scoped></style>
@@ -0,0 +1,116 @@
<script setup lang="ts">
// state
const isShow = ref(false);
const currentProfile = ref("");
const avatars = ref([
"/avatars/1.jpg",
"/avatars/2.jpg",
"/avatars/3.jpg",
"/avatars/4.jpg",
"/avatars/5.jpg",
"/avatars/1.jpg",
"/avatars/2.jpg",
"/avatars/3.jpg",
"/avatars/4.jpg",
"/avatars/5.jpg",
"/avatars/1.jpg",
"/avatars/2.jpg",
"/avatars/3.jpg",
"/avatars/4.jpg",
"/avatars/5.jpg",
"/avatars/1.jpg",
"/avatars/2.jpg",
"/avatars/3.jpg",
"/avatars/4.jpg",
"/avatars/5.jpg",
"/avatars/1.jpg",
"/avatars/2.jpg",
"/avatars/3.jpg",
"/avatars/4.jpg",
"/avatars/5.jpg",
"/avatars/5.jpg",
"/avatars/1.jpg",
"/avatars/2.jpg",
"/avatars/3.jpg",
"/avatars/4.jpg",
"/avatars/5.jpg",
"/avatars/1.jpg",
"/avatars/2.jpg",
"/avatars/3.jpg",
"/avatars/4.jpg",
"/avatars/5.jpg",
]);
</script>
<template>
<Modal v-model="isShow" title="عکس پروفایل" icon="bi:image" iconSize="20">
<template #trigger>
<button
class="bg-black text-slate-100 rounded-full p-2 flex-center absolute -bottom-0 -right-0"
>
<Icon name="bi:pencil" class="**:fill-slate-100" size="12" />
</button>
</template>
<template #content>
<div class="w-max">
<div
class="w-full flex flex-col-reverse items-center justify-between py-10 gap-10 px-4"
>
<div
class="flex items-center justify-between w-full flex-wrap gap-4 max-w-[500px]"
>
<button
v-for="(avatar, index) in avatars"
:key="index"
class="size-20 rounded-full focus:ring-2 focus:ring-offset-1 focus:ring-black transition-all"
>
<Avatar
:src="avatar"
:alt="`avatar-${index}`"
class="size-full"
/>
</button>
</div>
<div
class="w-full flex-center gap-4 max-w-[500px] flex-wrap"
>
<button
class="size-8 rounded-full bg-orange-100 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
/>
<button
class="size-8 rounded-full bg-orange-200 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
/>
<button
class="size-8 rounded-full bg-amber-600 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
/>
<button
class="size-8 rounded-full bg-amber-700 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
/>
<button
class="size-8 rounded-full bg-amber-800 whitespace-nowrap ring-2 hover:ring-black ring-slate-200 ring-offset-3"
/>
</div>
<div class="w-full flex-col-center gap-5">
<div
class="size-32 border border-slate-200 rounded-full"
>
<Avatar
:src="currentProfile"
:alt="''"
class="size-full"
/>
</div>
<Button class="rounded-full">آپلود عکس شما</Button>
</div>
</div>
</div>
</template>
</Modal>
</template>
<style scoped></style>
+12 -2
View File
@@ -1,4 +1,14 @@
<script setup lang="ts"></script>
<script setup lang="ts">
// imports
import useGetAccount from "~/composables/api/account/useGetAccount";
// queries
const { suspense } = useGetAccount();
await suspense();
</script>
<template>
<div
@@ -7,7 +17,7 @@
>
<Header />
<main
class="w-full overflow-x-hidden container flex items-start gap-[5rem]"
class="w-full overflow-x-hidden container flex items-start gap-[2rem]"
>
<ProfileSidebar />
<div class="w-9/12">
+50 -1
View File
@@ -29,7 +29,8 @@
"vue": "latest",
"vue-router": "latest",
"vue-scrollto": "^2.20.0",
"vue-skeletor": "^1.0.6"
"vue-skeletor": "^1.0.6",
"vue3-persian-datetime-picker": "^1.2.2"
},
"devDependencies": {
"@nuxt/test-utils": "^3.15.4",
@@ -7528,6 +7529,12 @@
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/jalaali-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/jalaali-js/-/jalaali-js-1.2.7.tgz",
"integrity": "sha512-gE+YHWSbygYAoJa+Xg8LWxGILqFOxZSBQQw39ghel01fVFUxV7bjL0x1JFsHcLQ3uPjvn81HQMa+kxwyPWnxGQ==",
"license": "MIT"
},
"node_modules/jiti": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
@@ -8520,6 +8527,39 @@
"integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
"license": "MIT"
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/moment-jalaali": {
"version": "0.9.6",
"resolved": "https://registry.npmjs.org/moment-jalaali/-/moment-jalaali-0.9.6.tgz",
"integrity": "sha512-v8wXjQplvk5ez+sUqgsWIrafwIf1BEXXvzTYwsg1wHcqh27nSgKPCJ6FnZRrCz03MoNyB9N31L0oms+vE8Rq7g==",
"license": "MIT",
"dependencies": {
"jalaali-js": "^1.1.0",
"moment": "^2.22.2",
"moment-timezone": "^0.5.21",
"rimraf": "^3.0.2"
}
},
"node_modules/moment-timezone": {
"version": "0.5.47",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.47.tgz",
"integrity": "sha512-UbNt/JAWS0m/NJOebR0QMRHBk0hu03r5dx9GK8Cs0AS3I81yDcOc9k+DytPItgVvBP7J6Mf6U2n3BPAacAV9oA==",
"license": "MIT",
"dependencies": {
"moment": "^2.29.4"
},
"engines": {
"node": "*"
}
},
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
@@ -12704,6 +12744,15 @@
"integrity": "sha512-ER4vHlFSXCW3ixK2DlczUE6CZliHsn4d2TvZ9/26C6Oq8zoyEY23BsqweMPtF8QULSz1+G5m2New1BwKNVOZhQ==",
"license": "MIT"
},
"node_modules/vue3-persian-datetime-picker": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/vue3-persian-datetime-picker/-/vue3-persian-datetime-picker-1.2.2.tgz",
"integrity": "sha512-d7nkj5vgtUvEXZboSdRmP1uwBfXvXgXqdvsOOMQb34jiMZU/aBDrTYWTEe1N+XKF9pvTTJn8Rws9ttJmyhK/hw==",
"license": "MIT",
"dependencies": {
"moment-jalaali": "^0.9.4"
}
},
"node_modules/w3c-xmlserializer": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+2 -1
View File
@@ -35,7 +35,8 @@
"vue": "latest",
"vue-router": "latest",
"vue-scrollto": "^2.20.0",
"vue-skeletor": "^1.0.6"
"vue-skeletor": "^1.0.6",
"vue3-persian-datetime-picker": "^1.2.2"
},
"devDependencies": {
"@nuxt/test-utils": "^3.15.4",
+1 -1
View File
@@ -5,7 +5,7 @@ const contactInfo = ref({
name: "",
email: "",
phone: "",
requestType: "",
requestType: undefined,
message: "",
});
+1
View File
@@ -3,6 +3,7 @@
definePageMeta({
middleware: "check-is-logged-in",
layout: "profile",
});
</script>
+145 -1
View File
@@ -1,14 +1,158 @@
<script setup lang="ts">
// imports
import useGetAccount from "~/composables/api/account/useGetAccount";
// meta
definePageMeta({
middleware: "check-is-logged-in",
layout: "profile",
});
// state
const personalData = ref({
name: "",
last_name: "",
phone: "",
gender: undefined,
email: "",
birthDate: "",
});
const alises = ref([
"شکارچی",
"آیفون باز",
"خوش سلیقه",
"دست و دلباز",
"چرم باز",
]);
// queries
const { data: account } = useGetAccount();
</script>
<template>
<div></div>
<div class="w-full flex flex-col gap-10">
<ProfilePageTitle title="پروفایل" icon="bi:person-vcard" />
<div class="flex flex-col gap-6">
<div
class="w-full flex items-center justify-between border p-6 rounded-xl border-slate-200"
>
<div class="flex items-center justify-start gap-5 w-8/12">
<div
class="size-32 shrink-0 rounded-full border border-slate-200 flex-center relative"
>
<Avatar
:src="account!.profile_photo"
:alt="
account?.first_name && account?.last_name
? `${account?.first_name.charAt(
0
)} ${account?.last_name.charAt(0)}`
: 'بدون نام کاربری'
"
/>
<PictureModal />
</div>
<div class="flex flex-col gap-3">
<span class="typo-sub-h-lg"
>{{ account?.first_name }}
{{ account?.last_name }}</span
>
<span class="typo-sub-h-sm font-light text-slate-600">
با اولین خریدتون هوش مصنوعی وبسایتمون واستون یک
بایوگرافی درست میکنه :)
</span>
<span
class="flex-center border border-yellow-500 pe-3.5 ps-1 w-max rounded-full"
>
<div class="rounded-full p-2">
<Icon
name="bi:patch-check"
class="**:fill-yellow-400"
size="20"
/>
</div>
<span class="text-xs text-yellow-500"
>جزو ۳ مشتری برتر</span
>
</span>
</div>
</div>
<div class="flex flex-col items-start gap-3 w-4/12">
<span class="typo-sub-h-lg">لقب های شما</span>
<span class="flex w-full flex-wrap gap-2">
<span
v-for="(alise, index) in alises"
:key="index"
class="flex-center bg-slate-50 border border-slate-200 py-2 px-3 w-max rounded-full"
>
<span class="text-xs text-black">{{ alise }}</span>
</span>
</span>
</div>
</div>
<ProfileSection title="اطلاعات شما">
<div
class="w-full grid grid-cols-1 lg:grid-cols-2 gap-x-3 gap-y-5"
>
<PersonalDataField id="personal-data-name" label="نام">
<Input v-model="personalData.name" variant="outlined" />
</PersonalDataField>
<PersonalDataField
id="personal-data-last-name"
label="نام خانوادگی"
>
<Input
v-model="personalData.last_name"
variant="outlined"
/>
</PersonalDataField>
<PersonalDataField id="personal-data-gender" label="جنسیت">
<Select
v-model="personalData.gender"
:options="['مرد', 'زن']"
variant="outlined"
/>
</PersonalDataField>
<PersonalDataField
id="personal-data-birth-date"
label="تاریخ تولد"
>
<Datepicker v-model="personalData.birthDate" />
</PersonalDataField>
<PersonalDataField
id="personal-data-phone"
label="تلفن همراه"
>
<Input
v-model="personalData.phone"
variant="outlined"
/>
</PersonalDataField>
<PersonalDataField
id="personal-email"
label="حساب الکترونیکی"
>
<Input
v-model="personalData.email"
variant="outlined"
/>
</PersonalDataField>
</div>
</ProfileSection>
</div>
<!-- <div class="w-fill grid grid-cols-1 lg:grid-cols-2">
</div> -->
</div>
</template>
<style scoped></style>
@@ -3,6 +3,7 @@
definePageMeta({
middleware: "check-is-logged-in",
layout: "profile",
});
</script>
@@ -3,6 +3,7 @@
definePageMeta({
middleware: "check-is-logged-in",
layout: "profile",
});
</script>
Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 984 KiB