diff --git a/.example.env b/.example.env new file mode 100644 index 0000000..18a6400 --- /dev/null +++ b/.example.env @@ -0,0 +1 @@ +VITE_API=http://localhost:9999/v1 diff --git a/.gitignore b/.gitignore index 8ee54e8..57991ff 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,6 @@ coverage *.sw? *.tsbuildinfo + +# Environment variables +.env diff --git a/src/App.vue b/src/App.vue index b2ce63b..5196026 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,14 +1,29 @@ - + + + + + + + + + diff --git a/src/assets/logo.svg b/src/assets/logo.svg deleted file mode 100644 index 7565660..0000000 --- a/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/components/CategoriesTable.vue b/src/components/CategoriesTable.vue new file mode 100644 index 0000000..400e257 --- /dev/null +++ b/src/components/CategoriesTable.vue @@ -0,0 +1,45 @@ + + + + + + + + + + diff --git a/src/components/FooterBar.vue b/src/components/FooterBar.vue new file mode 100644 index 0000000..1fcf571 --- /dev/null +++ b/src/components/FooterBar.vue @@ -0,0 +1,10 @@ + + + + + {{ new Date().getFullYear() }} — SnippetsManager + + + diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue index 37eba2a..4235435 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -1,51 +1,61 @@ - - - + + + + /> - - Logout - - + + Disconnect + diff --git a/src/components/ThemeSwitch.vue b/src/components/ThemeSwitch.vue new file mode 100644 index 0000000..8c8b49f --- /dev/null +++ b/src/components/ThemeSwitch.vue @@ -0,0 +1,15 @@ + + + + + + + diff --git a/src/composables/api.ts b/src/composables/api.ts new file mode 100644 index 0000000..d6f06c0 --- /dev/null +++ b/src/composables/api.ts @@ -0,0 +1,5 @@ +export function useApi() { + const url = import.meta.env.VITE_API as string + + return { url } +} diff --git a/src/composables/cookies.ts b/src/composables/cookies.ts new file mode 100644 index 0000000..586ae0e --- /dev/null +++ b/src/composables/cookies.ts @@ -0,0 +1,21 @@ +export function useCookie() { + const getCookie = (name: string): string | null => { + const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')) + return match ? match[2] : null + } + + const setCookie = ( + name: string, + value: string, + days: number = 365, + httpOnly: boolean = false + ) => { + const date = new Date() + date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000) + const expires = 'expires=' + date.toUTCString() + const httpOnlyFlag = httpOnly ? '; HttpOnly; Secure' : '' + document.cookie = `${name}=${value}; ${expires}; path=/${httpOnlyFlag}` + } + + return { getCookie, setCookie } +} diff --git a/src/router/index.ts b/src/router/index.ts index bf98301..6bf6aeb 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -8,6 +8,16 @@ const router = createRouter({ path: '/', name: 'home', component: HomeView + }, + { + path: '/categories', + name: 'categories', + component: () => import('../views/CategoriesView.vue') + }, + { + path: '/login', + name: 'login', + component: () => import('../views/LoginView.vue') } ] }) diff --git a/src/stores/auth.ts b/src/stores/auth.ts new file mode 100644 index 0000000..42a3ebb --- /dev/null +++ b/src/stores/auth.ts @@ -0,0 +1,21 @@ +import { useApi } from '@/composables/api' +import { defineStore } from 'pinia' + +interface LoginFields { + email: string + password: string +} + +export const useAuthStore = defineStore('auth', async () => { + const api = useApi() + + const postLogin = async (credentials: LoginFields) => { + const loginPromise = await fetch(`${api.url}/session/login`, { + method: 'POST', + body: JSON.stringify(credentials) + }) + return await loginPromise.json() + } + + return { postLogin } +}) diff --git a/src/stores/settings.ts b/src/stores/settings.ts index 9e36cde..b4f766b 100644 --- a/src/stores/settings.ts +++ b/src/stores/settings.ts @@ -1,31 +1,22 @@ import { ref } from 'vue' import { defineStore } from 'pinia' +import { useCookie } from '@/composables/cookies' export const useSettingsStore = defineStore('settings', () => { - const getCookie = (name: string): string | null => { - const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')) - return match ? match[2] : null - } + const cookie = useCookie() - const setCookie = (name: string, value: string, days: number = 365) => { - const date = new Date() - date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000) - const expires = 'expires=' + date.toUTCString() - document.cookie = `${name}=${value}; ${expires}; path=/` - } - - const darkModeCookie = getCookie('darkModeEnabled') + const darkModeCookie = cookie.getCookie('darkModeEnabled') const darkModeEnabled = ref( darkModeCookie !== null ? darkModeCookie === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches ) - if (darkModeCookie === null) setCookie('darkModeEnabled', darkModeEnabled.value.toString()) + if (darkModeCookie === null) cookie.setCookie('darkModeEnabled', darkModeEnabled.value.toString()) function switchDarkMode() { darkModeEnabled.value = !darkModeEnabled.value - setCookie('darkModeEnabled', darkModeEnabled.value.toString()) + cookie.setCookie('darkModeEnabled', darkModeEnabled.value.toString()) } return { darkModeEnabled, switchDarkMode } diff --git a/src/views/CategoriesView.vue b/src/views/CategoriesView.vue new file mode 100644 index 0000000..efa7912 --- /dev/null +++ b/src/views/CategoriesView.vue @@ -0,0 +1,11 @@ + + + + + Categories + Create category + + + diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 89ae62c..3a8bbad 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -1,7 +1,5 @@ - + - + Dashboard diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue new file mode 100644 index 0000000..33de376 --- /dev/null +++ b/src/views/LoginView.vue @@ -0,0 +1,49 @@ + + + + + SnippetsManager + + Login + Enter your credentials to log in. + + + + + + Reset password + + + + Log in + Create account + + + + +