Skip to content

Commit

Permalink
Merge pull request #32 from menthorlabs/creators/image
Browse files Browse the repository at this point in the history
Creators/image
  • Loading branch information
BernardoSM authored Nov 14, 2023
2 parents 4de33f5 + 3510b42 commit c08c06a
Show file tree
Hide file tree
Showing 42 changed files with 1,152 additions and 171 deletions.
3 changes: 2 additions & 1 deletion .env.development
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
NUXT_PUBLIC_APP_URL=http://localhost:3001/
NUXT_PUBLIC_SITE_URL=https://menthor.io/
NUXT_PUBLIC_API_URL=http://localhost:3000/dev
#NUXT_PUBLIC_API_URL=http://localhost:3000/dev
NUXT_PUBLIC_API_URL=https://2vzfiy8py1.execute-api.sa-east-1.amazonaws.com/dev
NUXT_PUBLIC_UMAMI_HOST="https://analytics.umami.is/script.js"
NUXT_PUBLIC_UMAMI_ID="3ff16063-e916-4083-ad5e-66dcec525c16"
NUXT_PUBLIC_APP_UMAMI_ID="8746ccb0-1a39-489a-8c8f-a394e4e2ee3b"
Expand Down
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: [menthorlabs]
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"typescript.tsdk": "node_modules/typescript/lib",
"cSpell.language": "en,pt,pt-BR",
"cSpell.enabledLanguageIds": ["javascript", "typescript"],
"cSpell.words": ["nuxt", "menthor", "ofetch", "menthorlabs", "sakura", "pinia"],
"cSpell.words": ["nuxt", "menthor", "ofetch", "menthorlabs", "sakura", "pinia", "colorthief"],
}
58 changes: 58 additions & 0 deletions apps/app/components/atoms/CreatorsImageCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<script setup lang="ts">
import { useClipboard } from "@vueuse/core";
const { fileUrl = "" } = defineProps<{
fileUrl: string;
}>();
const source = ref(fileUrl);
const { copy, copied } = useClipboard({ source });
</script>

<template>
<div
v-if="fileUrl === 'loading'"
class="flex items-center justify-center w-full aspect-video bg-zinc-100 animate-pulse"
>
<svg
class="w-10 h-10 text-zinc-200"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 20 18"
>
<path
d="M18 0H2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2Zm-5.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm4.376 10.481A1 1 0 0 1 16 15H4a1 1 0 0 1-.895-1.447l3.5-7A1 1 0 0 1 7.468 6a.965.965 0 0 1 .9.5l2.775 4.757 1.546-1.887a1 1 0 0 1 1.618.1l2.541 4a1 1 0 0 1 .028 1.011Z"
/>
</svg>
</div>
<div v-else class="relative group">
<div
class="absolute top-2 right-2 z-20 hidden group-hover:flex items-center gap-1"
>
<nuxt-link external target="_blank" :to="fileUrl">
<MIconButton icon="external-link-alt" class="!text-white" />
</nuxt-link>
<MIconButton icon="times" class="!text-white" />
</div>

<div
class="absolute z-10 top-0 left-0 w-full h-full items-center justify-center bg-black/50 cursor-pointer hidden group-hover:flex"
@click="copy()"
>
<span class="font-semibold text-sm text-white">
{{ copied ? "Copiado!" : "Copiar url" }}
</span>
</div>
<div class="aspect-video w-full overflow-hidden bg-zinc-100">
<nuxt-img
:src="fileUrl"
:quality="85"
format="webp"
width="250"
height="140"
alt="Roadmap"
class="h-full w-full object-cover object-center transition-all group-hover:scale-110"
/>
</div>
</div>
</template>
18 changes: 18 additions & 0 deletions apps/app/components/molecules/LeftMenuCreators.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<div class="w-full flex-1 p-3">
<div class="text-zinc-700 font-medium pl-4 py-[10px] text-sm">
Criação de conteúdo
</div>
<nuxt-link
to="/creators/images"
class="group"
exact-active-class="is-active"
>
<LeftMenuItem
icon="image"
text="Imagens"
class="group-[.is-active]:text-zinc-950 group-[.is-active]:bg-zinc-100"
/>
</nuxt-link>
</div>
</template>
19 changes: 13 additions & 6 deletions apps/app/components/molecules/TaskModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ async function sendSubmission(status: "Pending" | "Draft") {
if (!currentLesson) return;
const payload: typeof submissionsStore.submission = {
Filename: submissionsStore.submission?.Filename || "",
Content: submissionsStore.submission?.Content || "",
SubmissionType: currentLesson.submissionContent,
SubmissionStatus: status,
Expand All @@ -62,9 +63,11 @@ async function sendSubmission(status: "Pending" | "Draft") {
submissionsStore.submission?.SubmissionType === "Image" &&
uploadedFile.value
) {
await submissionsStore.requestUrl(uploadedFile.value.type);
await submissionsStore.uploadFileOnUrl(uploadedFile.value);
submissionsStore.submission.Content = `https://menthor-lessons.s3.sa-east-1.amazonaws.com/${submissionsStore.uploadUrl?.fileName}`;
const response = await submissionsStore.requestUrl(
uploadedFile.value.type
);
await submissionsStore.uploadFileOnUrl(uploadedFile.value, response.url);
submissionsStore.submission.Filename = response.fileName;
await submissionsStore.updateSubmission();
}
coursesStore.updateCourseLessons(currentLesson._id);
Expand All @@ -90,7 +93,7 @@ async function uploadFile(file: File) {
if (!submissionsStore.submission) return;
uploadedFile.value = file;
submissionsStore.submission.Content = URL.createObjectURL(file);
submissionsStore.submission.Filename = URL.createObjectURL(file);
}
</script>

Expand Down Expand Up @@ -119,9 +122,13 @@ async function uploadFile(file: File) {
class="mb-4"
/>
<nuxt-img
v-if="submissionsStore.submission.Content"
v-if="submissionsStore.submission.Filename"
class="rounded overflow-hidden"
:src="submissionsStore.submission.Content"
:src="
submissionsStore.submission.Filename.includes('blob')
? submissionsStore.submission.Filename
: `https://menthor-lessons.s3.sa-east-1.amazonaws.com/${submissionsStore.submission.Filename}`
"
alt="Submission Image"
/>
</template>
Expand Down
7 changes: 7 additions & 0 deletions apps/app/components/molecules/TopBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const shadowGenerator = (color: Array<Color>): string => {
<template>
<div
class="absolute left-0 top-0 flex h-[90px] w-full justify-center overflow-hidden pointer-events-none"
v-if="shadowStore.primaryColors && shadowStore.secondaryColors"
>
<div class="relative h-full w-full max-w-[1017px]">
<div
Expand Down Expand Up @@ -66,6 +67,12 @@ const shadowGenerator = (color: Array<Color>): string => {
<NuxtLink to="/profile">
<DropdownItem icon="circle-user" name="Perfil" />
</NuxtLink>
<NuxtLink
to="/creators/images"
v-if="userStore.user?.publicMetadata?.isCreator"
>
<DropdownItem icon="star" name="Creators" />
</NuxtLink>
<NuxtLink to="/sign-out">
<DropdownItem icon="arrow-right-from-bracket" name="Sair" />
</NuxtLink>
Expand Down
11 changes: 10 additions & 1 deletion apps/app/components/organisms/DefaultAside.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ const isLesson = computed(() => {
return !!route.meta?.lesson;
});
const isCreators = computed(() => {
return route.path.includes("/creators");
});
watch(isLesson, async () => {
refresh();
});
Expand Down Expand Up @@ -66,7 +70,12 @@ watch(isLesson, async () => {
</div>
</Transition>
<Transition name="slide-fade-reverse">
<div v-if="!isLesson">
<div v-if="!isLesson && isCreators">
<LeftMenuCreators />
</div>
</Transition>
<Transition name="slide-fade-reverse">
<div v-if="!isLesson && !isCreators">
<LeftMenuDefault />
</div>
</Transition>
Expand Down
102 changes: 102 additions & 0 deletions apps/app/pages/creators/images.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<script setup lang="ts">
const creatorsStore = useCreatorsStore();
const uploadStore = useUploadStore();
const loading = ref(true);
onMounted(async () => {
await creatorsStore.getImages();
loading.value = false;
});
function getSizePercentage(bytes: number) {
const tenGigabytes = 10737418240;
return Number((bytes * 100) / tenGigabytes).toFixed(2);
}
function onInput(event: Event) {
const allFiles = (event.target as HTMLInputElement).files;
if (!allFiles) return;
for (let i = 0; i < allFiles.length; ++i) {
const file = allFiles[i];
uploadFile(file);
}
}
async function uploadFile(file: File) {
loading.value = true;
const response = await creatorsStore.signUrl(file.type);
await uploadStore.uploadFileOnUrl(file, response.signedUrl.url);
await creatorsStore.addImage(response.signedUrl.fileName);
loading.value = false;
}
</script>

<template>
<div
class="container pt-4"
:class="{ 'overflow-hidden h-[calc(100%_-_56px)]': loading }"
>
<h1 class="text-4xl font-extrabold mb-4">Suas imagens</h1>
<div class="flex items-center gap-4 mb-8">
<MButton
variant="outline"
text="Fazer upload"
icon-left="cloud-arrow-up"
@click="($refs['creators_image'] as HTMLInputElement).click()"
/>
<input
ref="creators_image"
id="creators_image"
name="creators_image"
type="file"
accept="image/*"
multiple
class="hidden"
@input="onInput"
/>

<div class="space-y-[4px] w-full max-w-[240px] pt-2">
<div class="rounded-full bg-zinc-200 h-[4px]">
<div
class="w-full h-full rounded-full bg-emerald-500"
:style="`max-width: ${getSizePercentage(
creatorsStore.filesSize
)}%;`"
></div>
</div>
<div class="flex text-zinc-500 text-sm">
<div class="flex-1">
Usado:
<span class="text-zinc-950 font-medium">{{
$filters.bytesToSize(creatorsStore.filesSize)
}}</span>
de 10 GB
</div>
<div>{{ getSizePercentage(creatorsStore.filesSize) }} %</div>
</div>
</div>
</div>
<div
class="grid grid-cols-[repeat(auto-fill,_minmax(200px,_1fr))] gap-1 relative"
v-if="loading"
>
<CreatorsImageCard v-for="i in 30" :key="i" fileUrl="loading" />
<div
class="absolute top-0 left-0 w-full h-full bg-[linear-gradient(180deg,_rgba(255,_255,_255,_0.00)_0%,_#FFF_100%)] z-10"
></div>
</div>
<div
class="grid grid-cols-[repeat(auto-fill,_minmax(200px,_1fr))] gap-1"
v-else
>
<CreatorsImageCard
v-for="fileName in creatorsStore.images.reverse()"
:key="fileName"
:fileUrl="`https://menthor-content.s3.sa-east-1.amazonaws.com/${fileName}`"
/>
</div>
</div>
</template>
2 changes: 1 addition & 1 deletion apps/app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ useSeoMeta({
</div>
<h2 class="mb-4 text-lg font-bold">Recomendados para você</h2> -->
<div
class="mb-6 grid grid-cols-[repeat(auto-fill,_minmax(160px,_1fr))] sm:grid-cols-[repeat(auto-fill,_minmax(180px,_1fr))]"
class="mb-6 grid grid-cols-[repeat(auto-fill,_minmax(160px,_1fr))] sm:grid-cols-[repeat(auto-fill,_minmax(180px,_1fr))] gap-4 sm:gap-0"
>
<ContentNavigation v-slot="{ navigation }">
<NuxtLink
Expand Down
10 changes: 10 additions & 0 deletions apps/app/plugins/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ export default defineNuxtPlugin((nuxtApp) => {
};
return levels[value];
},
bytesToSize(bytes: number): string {
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
if (bytes === 0) return "n/a";
const i = Math.min(
Math.floor(Math.log(bytes) / Math.log(1024)),
sizes.length - 1
);
if (i === 0) return `${bytes} ${sizes[i]}`;
return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`;
},
};

app.config.globalProperties.$filters = filters;
Expand Down
4 changes: 4 additions & 0 deletions apps/app/plugins/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
faCheck,
faTerminal,
faCircleInfo,
faExternalLinkAlt,
faMoon,
faSun,
faEdit,
faHashtag,
faStar,
faLock,
faImage,
faClipboard,
faArrowRightFromBracket,
faArrowUp,
Expand Down Expand Up @@ -48,12 +50,14 @@ library.add(
faCheck,
faTerminal,
faCircleInfo,
faExternalLinkAlt,
faMoon,
faSun,
faEdit,
faHashtag,
faStar,
faLock,
faImage,
faClipboard,
faArrowRightFromBracket,
faArrowUp,
Expand Down
Loading

0 comments on commit c08c06a

Please sign in to comment.