Skip to content

Commit

Permalink
feat: add EditSnippetView, ShowSnippetView + responsive + routes and …
Browse files Browse the repository at this point in the history
…some minors fix
  • Loading branch information
FlorianBx committed Nov 22, 2023
1 parent 12aaa6e commit 4c8f35d
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 150 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@firebase/auth": "^1.4.0",
"@headlessui/vue": "^1.7.16",
"@heroicons/vue": "^2.0.18",
"@vueuse/core": "^10.6.1",
"firebase": "^10.6.0",
"pinia": "^2.1.7",
"prismjs": "^1.29.0",
Expand Down
32 changes: 32 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions src/assets/icons/CopyIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<svg
width="20"
height="20"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1 9.50006C1 10.3285 1.67157 11.0001 2.5 11.0001H4L4 10.0001H2.5C2.22386 10.0001 2 9.7762 2 9.50006L2 2.50006C2 2.22392 2.22386 2.00006 2.5 2.00006L9.5 2.00006C9.77614 2.00006 10 2.22392 10 2.50006V4.00002H5.5C4.67158 4.00002 4 4.67159 4 5.50002V12.5C4 13.3284 4.67158 14 5.5 14H12.5C13.3284 14 14 13.3284 14 12.5V5.50002C14 4.67159 13.3284 4.00002 12.5 4.00002H11V2.50006C11 1.67163 10.3284 1.00006 9.5 1.00006H2.5C1.67157 1.00006 1 1.67163 1 2.50006V9.50006ZM5 5.50002C5 5.22388 5.22386 5.00002 5.5 5.00002H12.5C12.7761 5.00002 13 5.22388 13 5.50002V12.5C13 12.7762 12.7761 13 12.5 13H5.5C5.22386 13 5 12.7762 5 12.5V5.50002Z"
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
></path>
</svg>
</template>
16 changes: 16 additions & 0 deletions src/assets/icons/PencilIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<svg
width="25"
height="25"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.8536 1.14645C11.6583 0.951184 11.3417 0.951184 11.1465 1.14645L3.71455 8.57836C3.62459 8.66832 3.55263 8.77461 3.50251 8.89155L2.04044 12.303C1.9599 12.491 2.00189 12.709 2.14646 12.8536C2.29103 12.9981 2.50905 13.0401 2.69697 12.9596L6.10847 11.4975C6.2254 11.4474 6.3317 11.3754 6.42166 11.2855L13.8536 3.85355C14.0488 3.65829 14.0488 3.34171 13.8536 3.14645L11.8536 1.14645ZM4.42166 9.28547L11.5 2.20711L12.7929 3.5L5.71455 10.5784L4.21924 11.2192L3.78081 10.7808L4.42166 9.28547Z"
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
></path>
</svg>
</template>
23 changes: 23 additions & 0 deletions src/components/LoadingCircle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<div class="loader"></div>
</template>

<style scoped>
.loader {
border: 4px solid transparent;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 0.7s cubic-bezier(0.42, 0, 0.58, 1) infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
26 changes: 16 additions & 10 deletions src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import { createRouter, createWebHistory } from "vue-router";
import { useAuthStore } from "../store/authStore";
import Home from "../views/HomeView.vue";
import Login from "../views/LoginView.vue";
import Register from "../views/RegisterView.vue";
import ShowSnippet from "../views/SnippetView.vue";
import CreateSnippet from "../views/CreateSnippetView.vue";
import HomeView from "../views/HomeView.vue";
import LoginView from "../views/LoginView.vue";
import RegisterView from "../views/RegisterView.vue";
import EditSnippetView from "../views/EditSnippetView.vue";
import ShowSnippetView from "../views/ShowSnippetView.vue";
import CreateSnippetView from "../views/CreateSnippetView.vue";

const routes = [
{ path: "/", component: Home },
{ path: "/login", component: Login, meta: { requiresAuth: false } },
{ path: "/register", component: Register, meta: { requiresAuth: false } },
{ path: "/", component: HomeView },
{ path: "/login", component: LoginView, meta: { requiresAuth: false } },
{ path: "/register", component: RegisterView, meta: { requiresAuth: false } },
{
path: "/snippet/:id",
component: ShowSnippet,
component: ShowSnippetView,
meta: { requiresAuth: false },
},
{
path: "/edit/:id",
component: EditSnippetView,
meta: { requiresAuth: true },
},
{
path: "/create-snippet",
component: CreateSnippet,
component: CreateSnippetView,
meta: { requiresAuth: true },
},
];
Expand Down
89 changes: 62 additions & 27 deletions src/views/EditSnippetView.vue
Original file line number Diff line number Diff line change
@@ -1,72 +1,107 @@
<script setup lang="ts">
import { reactive } from "vue";
import InputForText from "../components/InputForText.vue.ts";
import InputForRichText from "../components/InputForRichText.vue.ts";
import { useFormData } from "../composables/useFormData.ts";
import { onMounted, reactive } from "vue";
import InputForText from "../components/InputForText.vue";
import InputForRichText from "../components/InputForRichText.vue";
import { useAuthStore } from "../store/authStore";
import { useUpdateSnippet } from "../composables/useUpdateSnippet";
import { useGetSnippets } from "../composables/useGetSnippets";
import { useRouter } from "vue-router";
const authStore = useAuthStore();
const router = useRouter();
const date = new Date();
const id = router.currentRoute.value.params.id;
const { snippet, fetchSnippetById } = useGetSnippets();
const snippetData = reactive({
name: "",
id: id as string,
title: "",
description: "",
tag: "",
code: "",
language: "",
tags: "",
createdAt: date.toISOString(),
updatedAt: date.toISOString(),
authorId: authStore.idToken,
visibility: true,
});
const { formData, handleUpdateData } = useFormData(snippetData);
const fillSnippetData = () => {
if (snippet.value) {
snippetData.title = snippet.value.title;
snippetData.description = snippet.value.description;
snippetData.code = snippet.value.code;
snippetData.language = snippet.value.language;
snippetData.createdAt = snippet.value.createdAt;
snippetData.tags = snippet.value.tags;
}
};
const { updateSnippet } = useUpdateSnippet();
const handleSubmit = (event: Event) => {
event.preventDefault();
updateSnippet(snippetData);
router.push(`/snippet/${id}`);
};
onMounted(async () => {
if (!authStore.isLoggedIn) {
router.push("/login");
}
await fetchSnippetById(id.toString());
fillSnippetData();
});
</script>

<template>
<div class="flex min-h-full sm:mt-20 flex-1 flex-col justify-center">
<div class="px-4 sm:px-0 sm:mx-auto sm:w-full sm:max-w-[720px]">
<div
class="flex min-h-full sm:mt-20 flex-1 flex-col items-center justify-center"
>
<div class="px-4 max-w-full sm:px-0 sm:mx-auto sm:w-full sm:max-w-[720px]">
<div
class="bg-background px-6 py-12 sm:rounded-xl sm:px-12 shadow-neumorphic"
>
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<h3
class="pb-11 text-center text-2xl font-bold leading-9 tracking-tight text-primary"
>
Create Snippet
EDIT Snippet: {{ snippetData.title }}
</h3>
</div>
<form class="space-y-6" action="#" method="POST">
<form class="space-y-6">
<div>
<InputForText
label="Snippet Name"
required
:data="formData.name"
@update:data="(value: string) => handleUpdateData(value, 'name')"
/>
<InputForText v-model="snippetData.title" label="Title" required />
</div>

<div>
<InputForText
v-model="snippetData.description"
label="Description"
:data="formData.description"
@update:data="
(value: string) => handleUpdateData(value, 'description')
"
/>
</div>
<div>
<InputForText v-model="snippetData.tags" label="Tag" required />
</div>
<div>
<InputForText
label="Tag"
:data="formData.tag"
v-model="snippetData.language"
label="Language"
required
@update:data="(value: string) => handleUpdateData(value, 'tag')"
/>
</div>
<div>
<InputForRichText
v-model="snippetData.code"
label="Code"
:data="formData.code"
required
@update:data="(value: string) => handleUpdateData(value, 'code')"
/>
</div>

<div>
<button
type="submit"
class="flex w-full justify-center text-base rounded-md shadow-neumorphic hover:shadow-inner-neumorphic bg-button px-3 py-3 font-semibold leading-6 text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-secondary"
@click="handleSubmit"
>
Save
</button>
Expand Down
7 changes: 5 additions & 2 deletions src/views/HomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import SearchBar from "../components/SearchBar.vue";
import LayoutSlot from "../components/LayoutSlot.vue";
import useFilter from "../composables/useFilter";
import { useGetSnippets } from "../composables/useGetSnippets.ts";
import LoadingCircle from "../components/LoadingCircle.vue";
const { snippets, fetchSnippets, isLoading, error } = useGetSnippets();
const { filteredSnippets } = useFilter(snippets);
Expand All @@ -15,13 +16,15 @@ onMounted(() => {
</script>

<template>
<div v-show="isLoading">Loading...</div>
<div v-show="error" class="text-red-300">{{ error }}</div>
<div class="w-full">
<div class="w-full justify-center">
<LayoutSlot>
<div class="flex justify-center w-full pb-6">
<SearchBar />
</div>
<div v-show="isLoading" class="flex justify-center w-full">
<LoadingCircle />
</div>
<section
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 gap-y-8"
>
Expand Down
Loading

0 comments on commit 4c8f35d

Please sign in to comment.