From 6632f9bb0a407942e45543681d5508bc828edcf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=9C=D0=B0?= =?UTF-8?q?=D0=BB=D1=8E=D0=B3=D0=B8=D0=BD?= <d.malygin@iqdev.digital> Date: Fri, 13 Sep 2024 18:09:01 +0500 Subject: [PATCH] change components after primevue in process --- src/app/assets/icons/close-circle.svg | 2 +- src/app/assets/main.css | 4 + src/app/components.d.ts | 30 +- src/app/interfaces/environment.ts | 25 +- src/app/stores/data.ts | 42 +-- src/app/stores/interface.ts | 2 + .../entities/settings/DividerSettings.vue} | 0 .../settings/EntityPositionSettings.vue | 7 + .../entities/settings}/ImageMenu.vue | 0 src/components/entities/settings/TextMenu.vue | 81 +++++ src/modules/BaseSidebarMenu.vue | 92 ++--- src/modules/CropImageModal.vue | 8 +- src/modules/MenuHeader.vue | 29 +- src/modules/PageBackgroundMenu.vue | 2 +- src/modules/PageHeader.vue | 5 +- src/modules/entities/DividerItem.vue | 5 +- src/modules/entities/ImageItem.vue | 9 +- src/modules/entities/TextItem.vue | 19 +- src/modules/entities/menu/TextMenu.vue | 63 ---- src/output.css | 66 +++- src/pages/[uuid]/SheetPage.vue | 22 +- src/shared/BaseDrawer.vue | 85 ----- src/shared/BaseModal.vue | 89 ----- src/shared/Button.vue | 156 +++++++++ src/shared/{BaseDivider.vue => Divider.vue} | 0 src/shared/Drawer.vue | 160 +++++++++ src/shared/Modal.vue | 166 +++++++++ src/shared/ToggleSwitch.vue | 166 ++++++--- src/shared/Tree.vue | 320 ++++++++++++++++++ src/shared/icons/CloseCircle.vue | 2 +- src/shared/icons/ExitIcon.vue | 30 ++ src/shared/icons/HamgurgerMenu.vue | 2 +- src/shared/icons/HomeIcon.vue | 26 ++ src/shared/icons/NavigationIcon.vue | 30 ++ src/shared/icons/SettingsIcon.vue | 43 +++ src/shared/icons/VerticalArrowsIcon.vue | 34 ++ 36 files changed, 1356 insertions(+), 466 deletions(-) rename src/{modules/entities/menu/DividerMenu.vue => components/entities/settings/DividerSettings.vue} (100%) create mode 100644 src/components/entities/settings/EntityPositionSettings.vue rename src/{modules/entities/menu => components/entities/settings}/ImageMenu.vue (100%) create mode 100644 src/components/entities/settings/TextMenu.vue delete mode 100644 src/modules/entities/menu/TextMenu.vue delete mode 100644 src/shared/BaseDrawer.vue delete mode 100644 src/shared/BaseModal.vue create mode 100644 src/shared/Button.vue rename src/shared/{BaseDivider.vue => Divider.vue} (100%) create mode 100644 src/shared/Drawer.vue create mode 100644 src/shared/Modal.vue create mode 100644 src/shared/Tree.vue create mode 100644 src/shared/icons/ExitIcon.vue create mode 100644 src/shared/icons/HomeIcon.vue create mode 100644 src/shared/icons/NavigationIcon.vue create mode 100644 src/shared/icons/SettingsIcon.vue create mode 100644 src/shared/icons/VerticalArrowsIcon.vue diff --git a/src/app/assets/icons/close-circle.svg b/src/app/assets/icons/close-circle.svg index 6d3a6e8..22022e7 100644 --- a/src/app/assets/icons/close-circle.svg +++ b/src/app/assets/icons/close-circle.svg @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> -<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<svg width="40px" height="40px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM8.96963 8.96965C9.26252 8.67676 9.73739 8.67676 10.0303 8.96965L12 10.9393L13.9696 8.96967C14.2625 8.67678 14.7374 8.67678 15.0303 8.96967C15.3232 9.26256 15.3232 9.73744 15.0303 10.0303L13.0606 12L15.0303 13.9696C15.3232 14.2625 15.3232 14.7374 15.0303 15.0303C14.7374 15.3232 14.2625 15.3232 13.9696 15.0303L12 13.0607L10.0303 15.0303C9.73742 15.3232 9.26254 15.3232 8.96965 15.0303C8.67676 14.7374 8.67676 14.2625 8.96965 13.9697L10.9393 12L8.96963 10.0303C8.67673 9.73742 8.67673 9.26254 8.96963 8.96965Z" fill="#1C274C"/> </svg> \ No newline at end of file diff --git a/src/app/assets/main.css b/src/app/assets/main.css index b7736c7..0c447b6 100644 --- a/src/app/assets/main.css +++ b/src/app/assets/main.css @@ -137,6 +137,7 @@ } body { min-height: 100vh; + overflow-x: hidden; } #app { min-height: 100vh; @@ -154,12 +155,15 @@ body { padding: 0; margin: 0; border: none; + box-sizing: border-box; } *, *::before, *::after { box-sizing: border-box; + user-select: none; + color: white; } /* Links */ diff --git a/src/app/components.d.ts b/src/app/components.d.ts index 7908541..9d8258e 100644 --- a/src/app/components.d.ts +++ b/src/app/components.d.ts @@ -2,50 +2,60 @@ // @ts-nocheck // Generated by unplugin-vue-components // Read more: https://github.com/vuejs/core/pull/3399 -export {}; +export {} /* prettier-ignore */ declare module 'vue' { export interface GlobalComponents { App: typeof import('./App.vue')['default'] AuthorizationForm: typeof import('./../modules/authorization/AuthorizationForm.vue')['default'] - BaseDivider: typeof import('./../shared/BaseDivider.vue')['default'] BaseLoader: typeof import('./../shared/BaseLoader.vue')['default'] BaseSidebarMenu: typeof import('./../modules/BaseSidebarMenu.vue')['default'] + Button: typeof import('./../shared/Button.vue')['default'] + CloseCircle: typeof import('./../shared/icons/CloseCircle.vue')['default'] CreateEntityMenu: typeof import('./../components/CreateEntityMenu.vue')['default'] CropImageModal: typeof import('./../modules/CropImageModal.vue')['default'] DashedIcon: typeof import('./../shared/icons/DashedIcon.vue')['default'] - ToggleSwitch: typeof import('primevue/toggleswitch')['default'] - // Dialog: typeof import('primevue/dialog')['default'] - // Drawer: typeof import('primevue/drawer')['default'] - SpeedDial: typeof import('primevue/speeddial')['default'] - Tree: typeof import('primevue/tree')['default'] + Divider: typeof import('./../shared/Divider.vue')['default'] DividerItem: typeof import('./../modules/entities/DividerItem.vue')['default'] - DividerMenu: typeof import('./../modules/entities/menu/DividerMenu.vue')['default'] + DividerMenu: typeof import('./../modules/entities/settings/DividerMenu.vue')['default'] + DividerSettings: typeof import('./../components/entities/settings/DividerSettings.vue')['default'] DottedIcon: typeof import('./../shared/icons/DottedIcon.vue')['default'] + Drawer: typeof import('./../shared/Drawer.vue')['default'] EntitiesList: typeof import('./../modules/entities/EntitiesList.vue')['default'] EntityItem: typeof import('./../modules/entities/EntityItem.vue')['default'] + EntityPositionSettings: typeof import('./../components/entities/settings/EntityPositionSettings.vue')['default'] EntityTitle: typeof import('./../components/entities/share/EntityTitle.vue')['default'] + ExitIcon: typeof import('./../shared/icons/ExitIcon.vue')['default'] + HamgurgerMenu: typeof import('./../shared/icons/HamgurgerMenu.vue')['default'] + HomeIcon: typeof import('./../shared/icons/HomeIcon.vue')['default'] ImageItem: typeof import('./../modules/entities/ImageItem.vue')['default'] - ImageMenu: typeof import('./../modules/entities/menu/ImageMenu.vue')['default'] + ImageMenu: typeof import('./../components/entities/settings/ImageMenu.vue')['default'] ImagePositionMenu: typeof import('./../components/entities/image/ImagePositionMenu.vue')['default'] ImageSizeMenu: typeof import('./../components/entities/image/ImageSizeMenu.vue')['default'] ImageStateMenu: typeof import('./../components/entities/image/ImageStateMenu.vue')['default'] LogoAndLabel: typeof import('./../components/LogoAndLabel.vue')['default'] MenuHeader: typeof import('./../modules/MenuHeader.vue')['default'] + Modal: typeof import('./../shared/Modal.vue')['default'] + NavigationIcon: typeof import('./../shared/icons/NavigationIcon.vue')['default'] PageBackgroundMenu: typeof import('./../modules/PageBackgroundMenu.vue')['default'] PageHeader: typeof import('./../modules/PageHeader.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] + SettingsIcon: typeof import('./../shared/icons/SettingsIcon.vue')['default'] SheetPage: typeof import('./../pages/[uuid]/SheetPage.vue')['default'] SignIn: typeof import('./../pages/authorization/signIn.vue')['default'] SignUp: typeof import('./../pages/authorization/signUp.vue')['default'] SolidIcon: typeof import('./../shared/icons/SolidIcon.vue')['default'] + SpeedDial: typeof import('primevue/speeddial')['default'] TelegramSection: typeof import('./../modules/TelegramSection.vue')['default'] TextFontMenu: typeof import('./../components/entities/share/TextFontMenu.vue')['default'] TextItem: typeof import('./../modules/entities/TextItem.vue')['default'] - TextMenu: typeof import('./../modules/entities/menu/TextMenu.vue')['default'] + TextMenu: typeof import('./../components/entities/settings/TextMenu.vue')['default'] TextPositionMenu: typeof import('./../components/entities/text/TextPositionMenu.vue')['default'] TextStateMenu: typeof import('./../components/entities/text/TextStateMenu.vue')['default'] + ToggleSwitch: typeof import('./../shared/ToggleSwitch.vue')['default'] + Tree: typeof import('./../shared/Tree.vue')['default'] + VerticalArrowsIcon: typeof import('./../shared/icons/VerticalArrowsIcon.vue')['default'] } } diff --git a/src/app/interfaces/environment.ts b/src/app/interfaces/environment.ts index 0abd796..f468b7f 100644 --- a/src/app/interfaces/environment.ts +++ b/src/app/interfaces/environment.ts @@ -37,11 +37,20 @@ export interface IEntity { }[]; } -export type TColors = - | 'green-blue' - | 'red-yellow' - | 'darkBlue-pink-orange' - | 'pink-lightBlue-green' - | 'pink-red-orange' - | 'pink-purple' - | 'purple-pink'; +export type TTheme = + | 'white' + | 'slate' + | 'blue' + | 'sky' + | 'teal' + | 'lime' + | 'green' + | 'yellow' + | 'orange' + | 'pink' + | 'fuchsia' + | 'purple' + | 'indigo' + | 'rose' + | 'red' + | 'black'; diff --git a/src/app/stores/data.ts b/src/app/stores/data.ts index 6d30c22..ea60bfd 100644 --- a/src/app/stores/data.ts +++ b/src/app/stores/data.ts @@ -5,48 +5,30 @@ import cookies from '@/app/plugins/Cookie'; export const useDataStore = defineStore('dataStore', () => { const sheets = ref([ { - key: '0', - label: 'Ð›Ð¸Ñ‡Ð½Ð°Ñ Ð¶Ð¸Ð·Ð½ÑŒ', - data: '/0a49c3f4-57d2-4c82-be20-c7bab0abd623', - icon: 'pi pi-fw pi-inbox', - type: 'url', + text: 'Ð›Ð¸Ñ‡Ð½Ð°Ñ Ð¶Ð¸Ð·Ð½ÑŒ', + link: '/0a49c3f4-57d2-4c82-be20-c7bab0abd623', children: [ { - key: '0-0', - label: 'Девушка', - data: '/f22dabd2-029b-46ae-8580-a8291449a051', - icon: 'pi pi-fw pi-cog', - type: 'url', + text: 'Девушка', + link: '/f22dabd2-029b-46ae-8580-a8291449a051', children: [ { - key: '0-0-0', - label: 'Заморочки и проблемы и вÑÑ‘-вÑÑ‘-вÑÑ‘ моей любимой девушки', - icon: 'pi pi-fw pi-file', - data: '/83ad3c89-64a2-428d-995c-8008d40cec8a', - type: 'url' + text: 'Заморочки и проблемы и вÑÑ‘-вÑÑ‘-вÑÑ‘ моей любимой девушки', + link: '/83ad3c89-64a2-428d-995c-8008d40cec8a' }, { - key: '0-0-1', - label: 'Любимые цветы девушки', - icon: 'pi pi-fw pi-file', - data: '/(uuid of sheet)', - type: 'url' + text: 'Любимые цветы девушки', + link: '/(uuid of sheet)' } ] }, { - key: '0-1', - label: 'Работа', - data: '/81d8bc92-57cb-4ab2-89c2-63304bd0e5fb', - icon: 'pi pi-fw pi-home', - type: 'url', + text: 'Работа', + link: '/81d8bc92-57cb-4ab2-89c2-63304bd0e5fb', children: [ { - key: '0-1-0', - label: 'Pet-projects', - icon: 'pi pi-fw pi-file', - data: '/(uuid of sheet)', - type: 'url' + text: 'Pet-projects', + link: '/(uuid of sheet)' } ] } diff --git a/src/app/stores/interface.ts b/src/app/stores/interface.ts index c12fa15..34f2f4a 100644 --- a/src/app/stores/interface.ts +++ b/src/app/stores/interface.ts @@ -4,6 +4,7 @@ import { useWebsocketStore } from '@/app/stores/websocket'; export const useInterfaceStore = defineStore('interfaceStore', () => { const websocketStore = useWebsocketStore(); + const isDarkMode = ref<boolean>(true); const defaultPageBackground = ref<string>( 'https://t3.ftcdn.net/jpg/05/01/28/98/360_F_501289843_4ITbthNCydFQGgJmoZe4IQKchItBubqZ.jpg' ); @@ -44,6 +45,7 @@ export const useInterfaceStore = defineStore('interfaceStore', () => { pageBackground.value = url; } return { + isDarkMode, pageBackground, defaultPageBackground, isFetchedForBackground, diff --git a/src/modules/entities/menu/DividerMenu.vue b/src/components/entities/settings/DividerSettings.vue similarity index 100% rename from src/modules/entities/menu/DividerMenu.vue rename to src/components/entities/settings/DividerSettings.vue diff --git a/src/components/entities/settings/EntityPositionSettings.vue b/src/components/entities/settings/EntityPositionSettings.vue new file mode 100644 index 0000000..6177ca0 --- /dev/null +++ b/src/components/entities/settings/EntityPositionSettings.vue @@ -0,0 +1,7 @@ +<script setup lang="ts"></script> + +<template> + <MenuDial /> +</template> + +<style scoped></style> diff --git a/src/modules/entities/menu/ImageMenu.vue b/src/components/entities/settings/ImageMenu.vue similarity index 100% rename from src/modules/entities/menu/ImageMenu.vue rename to src/components/entities/settings/ImageMenu.vue diff --git a/src/components/entities/settings/TextMenu.vue b/src/components/entities/settings/TextMenu.vue new file mode 100644 index 0000000..1b054d4 --- /dev/null +++ b/src/components/entities/settings/TextMenu.vue @@ -0,0 +1,81 @@ +<script setup lang="ts"> +import { deleteEntity, editEntity } from '@/app/helpers'; +import type { IParagraph } from '@/app/interfaces/entities'; +import { useVModel } from '@vueuse/core'; +import type { TTheme } from '@/app/interfaces/environment'; +import cookies from '@/app/plugins/Cookie'; + +interface Props { + entityData: IParagraph; +} +const props = defineProps<Props>(); +const emit = defineEmits(['update:entityData']); +const entityData = useVModel(props, 'entityData', emit); +const isModal = ref<boolean>(false); + +const addTitle = () => { + editEntity({ ...entityData.value, title: 'Title', entity_title_position: 'center' }); + entityData.value = { ...entityData.value, title: 'Title', entity_title_position: 'center' }; +}; +const removeTitle = () => { + const newState = { ...entityData.value }; + newState.title = null; + editEntity({ ...newState }); + entityData.value = newState; +}; +const editPosition = (position: 'left' | 'center' | 'right') => { + entityData.value.entity_position = position; + editEntity({ ...entityData.value, entity_position: position }); +}; +const editTitlePosition = (position: 'left' | 'center' | 'right') => { + entityData.value.entity_title_position = position; + editEntity({ ...entityData.value, entity_title_position: position }); +}; +const changeFontSize = (newSize: '16' | '20' | '24' | '40' | '64') => { + entityData.value.font_size = newSize; + editEntity({ ...entityData.value, font_size: newSize }); +}; +const editParagraphWidth = (widthMode: 'full' | 'half') => { + entityData.value.paragraph_size = widthMode; + editEntity({ ...entityData.value, paragraph_size: widthMode }); +}; +const themeColor: TTheme = cookies.get('favorite_color'); +</script> + +<template> + <div + :style="`background-color: ${themeColor}`" + class="absolute left-2 top-0 transition-all select-none size-12 p-2 flex justify-center items-center rounded-full hover:brightness-75 cursor-pointer" + @click.prevent="isModal = true" + > + <SettingsIcon color="white" size="25" /> + </div> + <Modal v-model:isVisible="isModal" theme="black" + ><template #header>Edit paragraph</template> + <div> + <select id="" name="textSize"> + <option></option> + </select></div + ></Modal> + <!-- <div class="speedDial absolute left-2 top-0 transition-all select-none">--> + <!-- <TextStateMenu--> + <!-- :entityData="entityData"--> + <!-- @deleteEntity="deleteEntity"--> + <!-- @addTitle="addTitle"--> + <!-- @removeTitle="removeTitle"--> + <!-- />--> + <!-- </div>--> + <!-- <div class="speedDial h-12 absolute left-2 top-0 translate-y-full transition-all select-none">--> + <!-- <TextFontMenu :entityData="entityData" @changeFontSize="changeFontSize" />--> + <!-- </div>--> + <!-- <div class="speedDial absolute left-2 top-0 translate-y-24 transition-all select-none">--> + <!-- <TextPositionMenu--> + <!-- :entityData="entityData"--> + <!-- @editPosition="editPosition"--> + <!-- @editTitlePosition="editTitlePosition"--> + <!-- @editParagraphWidth="editParagraphWidth"--> + <!-- />--> + <!-- </div>--> +</template> + +<style scoped></style> diff --git a/src/modules/BaseSidebarMenu.vue b/src/modules/BaseSidebarMenu.vue index b46b63e..dd58ce5 100644 --- a/src/modules/BaseSidebarMenu.vue +++ b/src/modules/BaseSidebarMenu.vue @@ -1,65 +1,69 @@ <script setup lang="ts"> import { useDataStore } from '@/app/stores/data'; +import Tree from '@/shared/Tree.vue'; +import { useAuthorizationStore } from '@/app/stores/authorization'; +import HomeIcon from '@/shared/icons/HomeIcon.vue'; + +const authorizationStore = useAuthorizationStore(); const route = useRoute(); const dataStore = useDataStore(); -const emit = defineEmits(['closeMenu']); - -const sheets = ref(); -const expandedKeys = ref({}); - -const expandSheet = (sheet) => { - if (sheet.children && sheet.children.length) { - expandedKeys.value[sheet.key] = true; +const userNickName = computed(() => authorizationStore.userNickName); - for (let child of sheet.children) { - expandSheet(child); - } - } -}; -const expandAll = () => { - for (let sheet of sheets.value) { - expandSheet(sheet); - } - expandedKeys.value = { ...expandedKeys.value }; +const logout = () => { + authorizationStore.logout(); }; +const sheets = ref(); onMounted(() => { sheets.value = dataStore.sheets; - expandAll(); }); </script> <template> - <div class="flex flex-col h-full p-4"> - <MenuHeader @closeMenu="emit('closeMenu')" /> - <BaseDivider /> - <nav> + <div class="flex flex-col"> + <section class="flex items-center justify-between"> + <div> + <p class="text-xl w-48 overflow-ellipsis overflow-hidden text-nowrap"> + @{{ userNickName }} + </p> + </div> + <a + href="/settings" + class="pi pi-cog ml-auto mr-1 p-2 hover:cursor-pointer" + style="font-size: 2rem" + ></a> + <SettingsIcon + class="p-2 cursor-pointer hover:brightness-75 transition-all" + color="white" + size="50" + /> + <button @click.prevent="logout"> + <ExitIcon color="#f00" class="hover:brightness-75 transition-all" /> + </button> + </section> + <Divider class="mt-4" /> + <nav class="mt-4"> <h3 class="text-xl">Menu</h3> - <div style="margin-left: 58px" class="mt-4 -mb-2 select-none font-bold"> - <a v-if="route.path !== '/'" href="/" - ><i class="pi pi-home text-gray-400 pr-2"></i>Главное меню</a + <div class="mt-4 -mb-2 ml-4 select-none font-bold"> + <a v-if="route.path !== '/'" href="/" class="text-lg flex gap-4" + ><HomeIcon color="white" size="20" />Главное меню</a > <span v-else><i class="pi pi-home text-gray-400 pr-2"></i>Главное меню</span> </div> - <Tree - v-model:expandedKeys="expandedKeys" - :value="sheets" - pt:root:class="pl-0" - pt:sheetLabel:class="text-white" - > - <template #url="slotProps"> - <a - :href="slotProps.node.data" - :class="[ - 'block', - { - 'bg-sky-900 p-2 ml-0 -m-2 rounded-md': route.path === slotProps.node.data - } - ]" - >{{ slotProps.node.label }}</a - > - </template> + <Tree :expand="true" theme="black" :items="sheets"> + <!-- <template #url="slotProps">--> + <!-- <a--> + <!-- :href="slotProps.node.data"--> + <!-- :class="[--> + <!-- 'block',--> + <!-- {--> + <!-- 'bg-sky-900 p-2 ml-0 -m-2 rounded-md': route.path === slotProps.node.data--> + <!-- }--> + <!-- ]"--> + <!-- >{{ slotProps.node.label }}</a--> + <!-- >--> + <!-- </template>--> </Tree> </nav> </div> diff --git a/src/modules/CropImageModal.vue b/src/modules/CropImageModal.vue index 0f7b65b..1e4c5eb 100644 --- a/src/modules/CropImageModal.vue +++ b/src/modules/CropImageModal.vue @@ -95,7 +95,11 @@ const submitForm = () => { <!-- :draggable="false"--> <!-- :style="`width: ${modalWidth}%; position: relative`"--> <!-- >--> - <BaseModal v-model:isVisible="isVisible" :style="`width: ${modalWidth}%; position: relative`"> + <Modal + v-model:isVisible="isVisible" + :style="`width: ${modalWidth}%; position: relative`" + theme="black" + > <template #header> <div class="mx-auto select-none"> <i @@ -129,7 +133,7 @@ const submitForm = () => { @change="onCropperChange" ></Cropper> </div> - </BaseModal> + </Modal> <!-- </Dialog>--> </div> </template> diff --git a/src/modules/MenuHeader.vue b/src/modules/MenuHeader.vue index d47b701..b2e8700 100644 --- a/src/modules/MenuHeader.vue +++ b/src/modules/MenuHeader.vue @@ -1,35 +1,8 @@ -<script setup lang="ts"> -import { useAuthorizationStore } from '@/app/stores/authorization'; -import CloseCircle from '@/shared/icons/CloseCircle.vue'; - -const emit = defineEmits(['closeMenu']); -const authorizationStore = useAuthorizationStore(); -const userNickName = computed(() => authorizationStore.userNickName); - -const logout = () => { - authorizationStore.logout(); -}; -</script> +<script setup lang="ts"></script> <template> <section class="flex justify-between items-center mb-4"> <LogoAndLabel /> - <button @click="emit('closeMenu')"> - <CloseCircle color="red" size="30" /> - </button> - </section> - <section class="flex items-center justify-between"> - <div> - <p class="text-xl w-48 overflow-ellipsis overflow-hidden text-nowrap">@{{ userNickName }}</p> - </div> - <a - href="/settings" - class="pi pi-cog ml-auto mr-1 p-2 hover:cursor-pointer" - style="font-size: 2rem" - ></a> - <button @click.prevent="logout"> - <i class="pi pi-sign-out text-red-500 p-2" style="font-size: 1.5rem"></i> - </button> </section> </template> diff --git a/src/modules/PageBackgroundMenu.vue b/src/modules/PageBackgroundMenu.vue index c7c0be0..d120564 100644 --- a/src/modules/PageBackgroundMenu.vue +++ b/src/modules/PageBackgroundMenu.vue @@ -7,7 +7,7 @@ const emit = defineEmits(['uploadFile', 'setDefaultBackground']); </script> <template> - <section class="changeImageBlock absolute top-2 right-2 transition-all"> + <section class="changeImageBlock absolute top-2 right-6 transition-all"> <div class="bg-black p-2 mb-1 rounded-md hover:text-gray-300 transition-all select-none cursor-pointer" > diff --git a/src/modules/PageHeader.vue b/src/modules/PageHeader.vue index 967c7ad..7b5a0bf 100644 --- a/src/modules/PageHeader.vue +++ b/src/modules/PageHeader.vue @@ -1,5 +1,7 @@ <script setup lang="ts"> import { useVModel } from '@vueuse/core'; +import cookies from '@/app/plugins/Cookie'; +import type { TTheme } from '@/app/interfaces/environment'; interface Props { title: string; @@ -8,6 +10,7 @@ interface Props { const props = defineProps<Props>(); const emit = defineEmits(['update:isEditMode']); const isEditMode = useVModel(props, 'isEditMode', emit); +const themeColor: TTheme = cookies.get('favorite_color'); </script> <template> @@ -18,7 +21,7 @@ const isEditMode = useVModel(props, 'isEditMode', emit); @click.prevent="isEditMode = !isEditMode" > <span class="font-medium select-none">Edit mode</span> - <ToggleSwitch v-model="isEditMode" /> + <ToggleSwitch :isActive="isEditMode" :theme="themeColor" /> </button> </header> </template> diff --git a/src/modules/entities/DividerItem.vue b/src/modules/entities/DividerItem.vue index cd1ee2a..d8adc5d 100644 --- a/src/modules/entities/DividerItem.vue +++ b/src/modules/entities/DividerItem.vue @@ -10,8 +10,9 @@ defineProps<Props>(); <template> <section class="entityContainer relative px-16 py-6"> - <BaseDivider :type="entityData.divider_type" :height="entityData.divider_height" /> - <DividerMenu v-if="isEditMode" :entityData="entityData" /> + <Divider :type="entityData.divider_type" :height="entityData.divider_height" /> + <DividerSettings v-if="isEditMode" :entityData="entityData" /> + <EntityPositionSettings /> </section> </template> diff --git a/src/modules/entities/ImageItem.vue b/src/modules/entities/ImageItem.vue index 1d5fb07..3dce9b4 100644 --- a/src/modules/entities/ImageItem.vue +++ b/src/modules/entities/ImageItem.vue @@ -118,14 +118,7 @@ const openCropImageModal = () => (isModalCropImage.value = true); v-model:entityData="entityData" @openCropImageModal="openCropImageModal" /> - <div - v-if="!entityData?.title && entityData.image_height < 137" - class="aggregateHigh h-0 transition-all" - ></div> - <div - v-if="!entityData?.title && entityData.image_height >= 137 && entityData.image_height < 167" - class="aggregateShort h-0 transition-all" - ></div> + <EntityPositionSettings /> </div> </section> </template> diff --git a/src/modules/entities/TextItem.vue b/src/modules/entities/TextItem.vue index d14a5a9..3d51198 100644 --- a/src/modules/entities/TextItem.vue +++ b/src/modules/entities/TextItem.vue @@ -64,25 +64,8 @@ const { height: textareaHeight } = useElementSize(textarea); @input="triggerResize" /> </div> - <div - v-if="!entityData?.title && textareaHeight < 87 && isEditMode" - class="aggregateHigh transition-all h-0" - ></div> - <div - v-if=" - (!entityData?.title && textareaHeight >= 87 && textareaHeight < 132 && isEditMode) || - (entityData?.title && textareaHeight < 65 && isEditMode) - " - class="aggregateMedium transition-all h-0" - ></div> - <div - v-if=" - (!entityData?.title && textareaHeight >= 132 && textareaHeight < 167 && isEditMode) || - (entityData?.title && textareaHeight >= 65 && textareaHeight < 100 && isEditMode) - " - class="aggregateShort transition-all h-0" - ></div> <TextMenu v-if="isEditMode" v-model:entityData="entityData" /> + <EntityPositionSettings /> </div> </section> </template> diff --git a/src/modules/entities/menu/TextMenu.vue b/src/modules/entities/menu/TextMenu.vue deleted file mode 100644 index 91eaf4c..0000000 --- a/src/modules/entities/menu/TextMenu.vue +++ /dev/null @@ -1,63 +0,0 @@ -<script setup lang="ts"> -import { deleteEntity, editEntity } from '@/app/helpers'; -import type { IParagraph } from '@/app/interfaces/entities'; -import { useVModel } from '@vueuse/core'; - -interface Props { - entityData: IParagraph; -} -const props = defineProps<Props>(); -const emit = defineEmits(['update:entityData']); -const entityData = useVModel(props, 'entityData', emit); - -const addTitle = () => { - editEntity({ ...entityData.value, title: 'Title', entity_title_position: 'center' }); - entityData.value = { ...entityData.value, title: 'Title', entity_title_position: 'center' }; -}; -const removeTitle = () => { - const newState = { ...entityData.value }; - newState.title = null; - editEntity({ ...newState }); - entityData.value = newState; -}; -const editPosition = (position: 'left' | 'center' | 'right') => { - entityData.value.entity_position = position; - editEntity({ ...entityData.value, entity_position: position }); -}; -const editTitlePosition = (position: 'left' | 'center' | 'right') => { - entityData.value.entity_title_position = position; - editEntity({ ...entityData.value, entity_title_position: position }); -}; -const changeFontSize = (newSize: '16' | '20' | '24' | '40' | '64') => { - entityData.value.font_size = newSize; - editEntity({ ...entityData.value, font_size: newSize }); -}; -const editParagraphWidth = (widthMode: 'full' | 'half') => { - entityData.value.paragraph_size = widthMode; - editEntity({ ...entityData.value, paragraph_size: widthMode }); -}; -</script> - -<template> - <div class="speedDial absolute left-2 top-0 transition-all select-none"> - <TextStateMenu - :entityData="entityData" - @deleteEntity="deleteEntity" - @addTitle="addTitle" - @removeTitle="removeTitle" - /> - </div> - <div class="speedDial h-12 absolute left-2 top-0 translate-y-full transition-all select-none"> - <TextFontMenu :entityData="entityData" @changeFontSize="changeFontSize" /> - </div> - <div class="speedDial absolute left-2 top-0 translate-y-24 transition-all select-none"> - <TextPositionMenu - :entityData="entityData" - @editPosition="editPosition" - @editTitlePosition="editTitlePosition" - @editParagraphWidth="editParagraphWidth" - /> - </div> -</template> - -<style scoped></style> diff --git a/src/output.css b/src/output.css index a5cbb16..4c24ee2 100644 --- a/src/output.css +++ b/src/output.css @@ -628,10 +628,6 @@ video { left: 0.5rem; } -.right-2 { - right: 0.5rem; -} - .right-6 { right: 1.5rem; } @@ -718,6 +714,10 @@ video { margin-left: 0px; } +.ml-4 { + margin-left: 1rem; +} + .ml-auto { margin-left: auto; } @@ -762,6 +762,10 @@ video { display: grid; } +.hidden { + display: none; +} + .size-10 { width: 2.5rem; height: 2.5rem; @@ -1178,10 +1182,6 @@ video { padding-bottom: 1.5rem; } -.pl-0 { - padding-left: 0px; -} - .pl-1 { padding-left: 0.25rem; } @@ -1247,6 +1247,10 @@ video { font-weight: 600; } +.italic { + font-style: italic; +} + .leading-none { line-height: 1; } @@ -1255,6 +1259,11 @@ video { line-height: 1.5; } +.text-black { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); +} + .text-gray-400 { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); @@ -1265,11 +1274,6 @@ video { color: rgb(248 113 113 / var(--tw-text-opacity)); } -.text-red-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); -} - .text-white { --tw-text-opacity: 1; color: rgb(255 255 255 / var(--tw-text-opacity)); @@ -1291,6 +1295,14 @@ video { filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } +.transition { + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + .transition-all { transition-property: all; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); @@ -1301,11 +1313,39 @@ video { transition-duration: 300ms; } +.ease-in-out { + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); +} + +.ease-out { + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); +} + .hover\:cursor-pointer:hover { cursor: pointer; } +.hover\:bg-slate-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(51 65 85 / var(--tw-bg-opacity)); +} + +.hover\:bg-slate-800:hover { + --tw-bg-opacity: 1; + background-color: rgb(30 41 59 / var(--tw-bg-opacity)); +} + .hover\:text-gray-300:hover { --tw-text-opacity: 1; color: rgb(209 213 219 / var(--tw-text-opacity)); +} + +.hover\:brightness-75:hover { + --tw-brightness: brightness(.75); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + +.hover\:brightness-125:hover { + --tw-brightness: brightness(1.25); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } \ No newline at end of file diff --git a/src/pages/[uuid]/SheetPage.vue b/src/pages/[uuid]/SheetPage.vue index 2470a59..8f15594 100644 --- a/src/pages/[uuid]/SheetPage.vue +++ b/src/pages/[uuid]/SheetPage.vue @@ -6,10 +6,7 @@ import { useWebsocketStore } from '@/app/stores/websocket'; import type { IEntity } from '@/app/interfaces/environment'; import type { IImageMainInfo } from '@/app/interfaces'; import { createEntity, fetchForEntities, setDefaultPageBackground } from '@/app/helpers'; -import TelegramSection from '@/modules/TelegramSection.vue'; import cookies from '@/app/plugins/Cookie'; -import HamgurgerMenu from '@/shared/icons/HamgurgerMenu.vue'; -import BaseDrawer from '@/shared/BaseDrawer.vue'; const dataStore = useDataStore(); const interfaceStore = useInterfaceStore(); @@ -21,6 +18,7 @@ const entities = computed(() => dataStore.entities); const backgroundUrl = computed<string>(() => interfaceStore.pageBackground); const defaultBackgroundUrl = computed<string>(() => interfaceStore.defaultPageBackground); const isFetchedForBackground = computed(() => interfaceStore.isFetchedForBackground); +const isDarkMode = computed(() => interfaceStore.isDarkMode); // const pageTitle = computed(() => dataStore.currentPage.page_title); const isMenuVisible = ref<boolean>(false); @@ -82,14 +80,18 @@ const closeMenu = () => (isMenuVisible.value = false); <template> <PageHeader v-model:isEditMode="isEditMode" :title="'Home page'" /> <div class="fixed top-0 left-0 z-50"> - <button @click.prevent="isMenuVisible = !isMenuVisible"> + <button + class="px-4 py-2 text-white font-bold hover:bg-slate-800 transition-all rounded-md" + @click.prevent="isMenuVisible = !isMenuVisible" + > Menu - <HamgurgerMenu color="black" size="30" /> + <HamgurgerMenu color="white" size="40" /> </button> </div> - <BaseDrawer theme="dark" :isVisible="isMenuVisible"> + <Drawer v-model:isVisible="isMenuVisible" theme="black"> + <template #header><MenuHeader /></template> <BaseSidebarMenu class="relative z-50" @closeMenu="closeMenu" /> - </BaseDrawer> + </Drawer> <!-- <Drawer v-model:visible="isMenuVisible">--> <!-- <template #container="{ closeCallback }">--> <!-- <BaseSidebarMenu class="relative z-50" @closeMenu="closeCallback" />--> @@ -101,7 +103,11 @@ const closeMenu = () => (isMenuVisible.value = false); v-model:imageInfo="backgroundImageInfo" @saveImage="saveImage" /> - <main id="pageContainer" class="flex flex-col"> + <main + id="pageContainer" + class="flex flex-col" + :style="`background-color: ${isDarkMode ? 'black' : 'light'}`" + > <article style="min-height: 200px" class="backgroundContainer relative"> <img :src="backgroundUrl" diff --git a/src/shared/BaseDrawer.vue b/src/shared/BaseDrawer.vue deleted file mode 100644 index 7d8f93e..0000000 --- a/src/shared/BaseDrawer.vue +++ /dev/null @@ -1,85 +0,0 @@ -<script setup lang="ts"> -import { useVModel } from '@vueuse/core'; - -interface Props { - isVisible: boolean; - theme: 'light' | 'dark'; -} -const props = defineProps<Props>(); -const emit = defineEmits(['update:isVisible']); -const isVisible = useVModel(props, 'isVisible', emit); -</script> - -<template> - <article> - <section - :class="[ - 'drawerBackground', - { - openedDrawerBackground: isVisible - } - ]" - @click.prevent="isVisible = false" - ></section> - <section - :style="`color: ${theme === 'light' ? 'black' : 'white'}; background-color: ${theme === 'light' ? 'white' : 'black'}`" - :class="[ - 'drawer', - { - openedDrawer: isVisible - } - ]" - > - <header class="drawerHeader"> - <slot name="header" /> - <button class="buttonClose" @click.prevent="isVisible = false">Cls</button> - </header> - <slot /> - </section> - </article> -</template> - -<style scoped> -.drawerBackground { - position: absolute; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - background-color: rgba(0, 0, 0, 0.5); - z-index: -50; - opacity: 0; -} -.openedDrawerBackground { - z-index: 60; - opacity: 1; -} -.drawer { - position: absolute; - top: 0; - z-index: -50; - width: 400px; - height: 100vh; - padding: 20px; - transform: translateX(-100%); - transition: all ease-out 0.25s; - border-right: 2px solid gray; -} -.openedDrawer { - z-index: 9999; - transform: translateX(0); -} -.drawerHeader { - font-weight: bold; - font-size: 1.5rem; - padding-right: 50px; - margin-bottom: 20px; - min-height: 1rem; -} -.buttonClose { - position: absolute; - top: 20px; - right: 20px; - width: 30px; -} -</style> diff --git a/src/shared/BaseModal.vue b/src/shared/BaseModal.vue deleted file mode 100644 index d9a1b2d..0000000 --- a/src/shared/BaseModal.vue +++ /dev/null @@ -1,89 +0,0 @@ -<script setup lang="ts"> -import { useVModel } from '@vueuse/core'; -import CloseCircle from '@/shared/icons/CloseCircle.vue'; - -interface Props { - isVisible: boolean; - theme: 'light' | 'dark'; -} -const props = defineProps<Props>(); -const emit = defineEmits(['update:isVisible']); -const isVisible = useVModel(props, 'isVisible', emit); -</script> - -<template> - <article> - <section - :class="[ - 'modalBackground', - { - openedModalBackground: isVisible - } - ]" - ></section> - <section - :style="`color: ${theme === 'light' ? 'black' : 'white'}; background-color: ${theme === 'light' ? 'white' : 'black'}`" - :class="[ - 'modal', - { - openedModal: isVisible - } - ]" - > - <header class="modalHeader"> - <slot name="header" /> - <button class="buttonClose" @click.prevent="isVisible = false"> - <CloseCircle :color="theme === 'light' ? 'white' : 'black'" /> - </button> - </header> - <slot /> - </section> - </article> -</template> - -<style scoped> -.modalBackground { - position: absolute; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - background-color: rgba(0, 0, 0, 0.5); - z-index: -50; - opacity: 0; -} -.openedModalBackground { - z-index: 60; - opacity: 1; -} -.modal { - position: absolute; - top: 50%; - left: 50%; - z-index: -50; - padding: 20px; - border: 2px solid gray; - border-radius: 10px; - opacity: 0; - transform: translate(-50%, -50%) scale(0.5); - transition: all ease-in-out 0.2s; -} -.openedModal { - z-index: 9999; - opacity: 1; - transform: translate(-50%, -50%) scale(1); -} -.modalHeader { - font-weight: bold; - font-size: 1.5rem; - padding-right: 50px; - margin-bottom: 20px; - min-height: 1rem; -} -.buttonClose { - position: absolute; - top: 20px; - right: 20px; - width: 30px; -} -</style> diff --git a/src/shared/Button.vue b/src/shared/Button.vue new file mode 100644 index 0000000..904c8fb --- /dev/null +++ b/src/shared/Button.vue @@ -0,0 +1,156 @@ +<script setup lang="ts"> +import { computed } from 'vue' + +interface Props { + label?: string + iconPos?: 'left' | 'top' | 'right' | 'bottom' + textStyle?: 'bold' | 'italic' + border?: 'white' | 'black' + theme?: + | 'white' + | 'slate' + | 'blue' + | 'sky' + | 'teal' + | 'lime' + | 'green' + | 'yellow' + | 'orange' + | 'pink' + | 'fuchsia' + | 'purple' + | 'indigo' + | 'rose' + | 'red' + | 'black' +} +const props = defineProps<Props>() +const colorTheme = computed(() => { + if (!props?.theme) return '#0ea5e9' + switch (props?.theme) { + case 'white': + return '#ffffff' + case 'slate': + return '#64748b' + case 'blue': + return '#3b82f6' + case 'sky': + return '#0ea5e9' + case 'teal': + return '#14b8a6' + case 'lime': + return '#84cc16' + case 'green': + return '#22c55e' + case 'yellow': + return '#eab308' + case 'orange': + return '#f97316' + case 'pink': + return '#ec4899' + case 'fuchsia': + return '#d946ef' + case 'purple': + return '#a855f7' + case 'indigo': + return '#6366f1' + case 'rose': + return '#f43f5e' + case 'red': + return '#ef4444' + case 'black': + return '#000000' + } + return '#ffffff' +}) +const textColor = computed(() => { + if (!props.theme) return '#ffffff' + if (props.theme === 'white') return '#000000' + return '#ffffff' +}) +</script> + +<template> + <button + :class="[ + 'button', + { + 'flex-column': iconPos === 'top' || iconPos === 'bottom', + 'border-black': theme === 'white' || border === 'black', + 'border-white': border === 'white' + } + ]" + > + <span :style="`background-color: ${colorTheme}`" class="background"></span> + <span + :class="[ + 'icon', + { + 'order-2': iconPos === 'right' || iconPos === 'bottom' + } + ]" + > + <slot name="icon" /> + </span> + <span + :style="`color: ${textColor}`" + :class="[ + 'text', + { + bold: textStyle === 'bold', + italic: textStyle === 'italic' + } + ]" + >{{ label ?? 'Button' }}</span + > + </button> +</template> + +<style scoped> +.button { + position: relative; + border-radius: 5px; + display: flex; + align-items: center; + user-select: none; +} +.button:hover .background { + filter: brightness(90%); +} +.background { + width: 100%; + height: 100%; + position: absolute; + z-index: -1; + top: 0; + left: 0; + border-radius: 5px; + transition: filter 0.2s ease-in-out; +} +.icon { + display: flex; + align-items: center; + justify-content: center; +} +.text { + padding: 0.75rem 0.5rem; +} +.flex-column { + flex-direction: column; +} +.border-black { + border: 1px solid black; +} +.border-white { + border: 1px solid white; +} +.order-2 { + order: 2; +} +.bold { + font-weight: bold; +} +.italic { + font-style: italic; +} +</style> diff --git a/src/shared/BaseDivider.vue b/src/shared/Divider.vue similarity index 100% rename from src/shared/BaseDivider.vue rename to src/shared/Divider.vue diff --git a/src/shared/Drawer.vue b/src/shared/Drawer.vue new file mode 100644 index 0000000..50dfbf4 --- /dev/null +++ b/src/shared/Drawer.vue @@ -0,0 +1,160 @@ +<script setup lang="ts"> +import { useVModel } from '@vueuse/core'; +import { computed } from 'vue'; + +interface Props { + isVisible: boolean; + theme?: + | 'white' + | 'slate' + | 'blue' + | 'sky' + | 'teal' + | 'lime' + | 'green' + | 'yellow' + | 'orange' + | 'pink' + | 'fuchsia' + | 'purple' + | 'indigo' + | 'rose' + | 'red' + | 'black'; +} +const props = defineProps<Props>(); +const colorTheme = computed(() => { + if (!props?.theme) return '#0ea5e9'; + switch (props?.theme) { + case 'white': + return '#ffffff'; + case 'slate': + return '#64748b'; + case 'blue': + return '#3b82f6'; + case 'sky': + return '#0ea5e9'; + case 'teal': + return '#14b8a6'; + case 'lime': + return '#84cc16'; + case 'green': + return '#22c55e'; + case 'yellow': + return '#eab308'; + case 'orange': + return '#f97316'; + case 'pink': + return '#ec4899'; + case 'fuchsia': + return '#d946ef'; + case 'purple': + return '#a855f7'; + case 'indigo': + return '#6366f1'; + case 'rose': + return '#f43f5e'; + case 'red': + return '#ef4444'; + case 'black': + return '#000000'; + } + return '#ffffff'; +}); +const textColor = computed(() => { + if (!props.theme) return '#000000'; + if (props.theme === 'white') return '#000000'; + return '#ffffff'; +}); +const emit = defineEmits(['update:isVisible']); +const isVisible = useVModel(props, 'isVisible', emit); +</script> + +<template> + <article> + <section + :class="[ + 'drawerBackground', + { + openedDrawerBackground: isVisible + } + ]" + @click.prevent="isVisible = false" + ></section> + <section + :style="`color: ${textColor}; background-color: ${colorTheme}`" + :class="[ + 'drawer', + { + openedDrawer: isVisible + } + ]" + > + <header class="drawerHeader"> + <slot name="header" /> + <button class="buttonClose" @click.prevent="isVisible = false"> + <svg + width="40px" + height="40px" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM8.96963 8.96965C9.26252 8.67676 9.73739 8.67676 10.0303 8.96965L12 10.9393L13.9696 8.96967C14.2625 8.67678 14.7374 8.67678 15.0303 8.96967C15.3232 9.26256 15.3232 9.73744 15.0303 10.0303L13.0606 12L15.0303 13.9696C15.3232 14.2625 15.3232 14.7374 15.0303 15.0303C14.7374 15.3232 14.2625 15.3232 13.9696 15.0303L12 13.0607L10.0303 15.0303C9.73742 15.3232 9.26254 15.3232 8.96965 15.0303C8.67676 14.7374 8.67676 14.2625 8.96965 13.9697L10.9393 12L8.96963 10.0303C8.67673 9.73742 8.67673 9.26254 8.96963 8.96965Z" + :fill="textColor ?? '#1C274C'" + /> + </svg> + </button> + </header> + <slot /> + </section> + </article> +</template> + +<style scoped> +.drawerBackground { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.5); + z-index: -50; + opacity: 0; +} +.openedDrawerBackground { + z-index: 60; + opacity: 1; +} +.drawer { + position: fixed; + top: 0; + left: 0; + z-index: 9999; + width: 350px; + height: 100vh; + padding: 20px; + transform: translateX(-100%); + transition: transform ease-out 0.2s; + border-right: 2px solid gray; +} +.openedDrawer { + transform: translateX(0); +} +.drawerHeader { + font-weight: bold; + font-size: 1.5rem; + padding-right: 50px; + margin-bottom: 20px; + min-height: 1rem; +} +.buttonClose { + position: absolute; + top: 20px; + right: 20px; + width: 30px; +} +</style> diff --git a/src/shared/Modal.vue b/src/shared/Modal.vue new file mode 100644 index 0000000..a72aa73 --- /dev/null +++ b/src/shared/Modal.vue @@ -0,0 +1,166 @@ +<script setup lang="ts"> +import { useVModel } from '@vueuse/core'; +import { computed } from 'vue'; + +interface Props { + isVisible: boolean; + theme?: + | 'white' + | 'slate' + | 'blue' + | 'sky' + | 'teal' + | 'lime' + | 'green' + | 'yellow' + | 'orange' + | 'pink' + | 'fuchsia' + | 'purple' + | 'indigo' + | 'rose' + | 'red' + | 'black'; +} +const props = defineProps<Props>(); +const colorTheme = computed(() => { + if (!props?.theme) return '#0ea5e9'; + switch (props?.theme) { + case 'white': + return '#ffffff'; + case 'slate': + return '#64748b'; + case 'blue': + return '#3b82f6'; + case 'sky': + return '#0ea5e9'; + case 'teal': + return '#14b8a6'; + case 'lime': + return '#84cc16'; + case 'green': + return '#22c55e'; + case 'yellow': + return '#eab308'; + case 'orange': + return '#f97316'; + case 'pink': + return '#ec4899'; + case 'fuchsia': + return '#d946ef'; + case 'purple': + return '#a855f7'; + case 'indigo': + return '#6366f1'; + case 'rose': + return '#f43f5e'; + case 'red': + return '#ef4444'; + case 'black': + return '#000000'; + } + return '#0ea5e9'; +}); +const textColor = computed(() => { + if (!props.theme) return '#000000'; + if (props.theme === 'white') return '#000000'; + return '#ffffff'; +}); +const emit = defineEmits(['update:isVisible']); +const isVisible = useVModel(props, 'isVisible', emit); +</script> + +<template> + <article> + <section + :class="[ + 'modalBackground', + { + openedModalBackground: isVisible + } + ]" + ></section> + <section + :style="`color: ${textColor}; background-color: ${colorTheme}`" + :class="[ + 'modal', + { + openedModal: isVisible + } + ]" + > + <header class="modalHeader"> + <slot name="header" /> + <div class="buttonClose" @click.prevent="isVisible = false"> + <svg + width="40px" + height="40px" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM8.96963 8.96965C9.26252 8.67676 9.73739 8.67676 10.0303 8.96965L12 10.9393L13.9696 8.96967C14.2625 8.67678 14.7374 8.67678 15.0303 8.96967C15.3232 9.26256 15.3232 9.73744 15.0303 10.0303L13.0606 12L15.0303 13.9696C15.3232 14.2625 15.3232 14.7374 15.0303 15.0303C14.7374 15.3232 14.2625 15.3232 13.9696 15.0303L12 13.0607L10.0303 15.0303C9.73742 15.3232 9.26254 15.3232 8.96965 15.0303C8.67676 14.7374 8.67676 14.2625 8.96965 13.9697L10.9393 12L8.96963 10.0303C8.67673 9.73742 8.67673 9.26254 8.96963 8.96965Z" + :fill="textColor ?? '#1C274C'" + /> + </svg> + </div> + </header> + <slot /> + </section> + </article> +</template> + +<style scoped> +.modalBackground { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.5); + z-index: -50; + opacity: 0; +} +.openedModalBackground { + z-index: 60; + opacity: 1; +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: -50; + min-width: 250px; + min-height: 100px; + padding: 20px; + border: 2px solid gray; + border-radius: 10px; + opacity: 0; + transform: translate(-50%, -50%) scale(0.5); + transition: all ease-in-out 0.2s; + user-select: none; +} +.openedModal { + user-select: auto; + z-index: 9999; + opacity: 1; + transform: translate(-50%, -50%) scale(1); +} +.modalHeader { + font-weight: bold; + font-size: 1.5rem; + padding-right: 50px; + margin-bottom: 20px; + min-height: 1rem; +} +.buttonClose { + position: absolute; + top: 20px; + right: 20px; + width: 30px; + cursor: pointer; +} +</style> diff --git a/src/shared/ToggleSwitch.vue b/src/shared/ToggleSwitch.vue index e2b89cf..86ba7f3 100644 --- a/src/shared/ToggleSwitch.vue +++ b/src/shared/ToggleSwitch.vue @@ -1,87 +1,147 @@ <script setup lang="ts"> import { useVModel } from '@vueuse/core'; +import { computed } from 'vue'; interface Props { isActive: boolean; - size?: 'large' | 'extraLarge'; - color?: string; + size?: 'small' | 'large'; + theme?: + | 'white' + | 'slate' + | 'blue' + | 'sky' + | 'teal' + | 'lime' + | 'green' + | 'yellow' + | 'orange' + | 'pink' + | 'fuchsia' + | 'purple' + | 'indigo' + | 'rose' + | 'red'; } const props = defineProps<Props>(); const emit = defineEmits(['update:isActive']); const isActive = useVModel(props, 'isActive', emit); + +const colorTheme = computed(() => { + switch (props.theme) { + case 'white': + return '#ffffff'; + case 'slate': + return '#64748b'; + case 'blue': + return '#3b82f6'; + case 'sky': + return '#0ea5e9'; + case 'teal': + return '#14b8a6'; + case 'lime': + return '#84cc16'; + case 'green': + return '#22c55e'; + case 'yellow': + return '#eab308'; + case 'orange': + return '#f97316'; + case 'pink': + return '#ec4899'; + case 'fuchsia': + return '#d946ef'; + case 'purple': + return '#a855f7'; + case 'indigo': + return '#6366f1'; + case 'rose': + return '#f43f5e'; + case 'red': + return '#ef4444'; + } + return '#0ea5e9'; +}); +const sizes = computed(() => { + if (!props?.size) + return { + containerWidth: 35, + containerHeight: 21, + padding: 3, + borderRadius: 11, + circleSize: 15, + transformXCircle: 14 + }; + switch (props.size) { + case 'small': + return { + containerWidth: 30, + containerHeight: 18, + padding: 2, + borderRadius: 9, + circleSize: 14, + transformXCircle: 12 + }; + case 'large': + return { + containerWidth: 40, + containerHeight: 24, + padding: 3, + borderRadius: 12, + circleSize: 18, + transformXCircle: 14 + }; + } + return ''; +}); </script> <template> <button - :style="`background-color: ${color ?? '#0ea5e9'}`" - :class="[ - 'switcher', - { - largeSwitcher: size === 'large', - extraLargeSwitcher: size === 'extraLarge', - activeSwitcher: isActive - } - ]" + :style="`min-width: ${sizes.containerWidth}px; min-height: ${sizes.containerHeight}px; border-radius: ${sizes.borderRadius}px; padding: ${sizes.padding}px;`" + class="switcher" @click.prevent="isActive = !isActive" > - <div + <span + :style="`background-color: ${colorTheme ?? '#0ea5e9'}; border-radius: ${sizes.borderRadius}px;`" :class="[ - 'switcherCircle', + 'activeBackground', { - largeSwitcherCircle: size === 'large', - extraLargeSwitcherCircle: size === 'extraLarge', - activeSwitcherCircle: isActive + inactiveBackground: !isActive } ]" - ></div> + ></span> + <span + :style="`width: ${sizes.circleSize}px; height: ${sizes.circleSize}px; transform: translateX(${isActive ? sizes.transformXCircle : 0}px);`" + class="switcherCircle" + ></span> </button> </template> <style scoped> .switcher { - display: flex; - justify-content: start; - width: 30px; - height: 18px; - padding: 2px; - border-radius: 9px; + position: relative; cursor: pointer; - transition: all 0.2s ease-in-out; -} -.switcher:hover { - filter: brightness(90%); } -.activeSwitcher { - justify-content: end; - background-color: black !important; +.activeBackground { + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + transition: background-color 0.2s ease-in-out; } -.largeSwitcher { - width: 35px; - height: 21px; - border-radius: 11px; +.inactiveBackground { + background-color: rgba(187, 197, 204, 0.66) !important; + transition: background-color 0.2s ease-in-out; } -.extraLargeSwitcher { - width: 40px; - height: 24px; - border-radius: 12px; +.switcher:hover .inactiveBackground { + filter: brightness(90%); } .switcherCircle { - width: 14px; - height: 14px; + display: block; background-color: white; border-radius: 50%; - float: left; - transition: all 0.2s ease-in-out; -} -.activeSwitcherCircle { - float: right; -} -.largeSwitcherCircle { - width: 17px; - height: 17px; -} -.extraLargeSwitcherCircle { - width: 20px; - height: 20px; + transition: transform 0.2s ease-in-out; } </style> diff --git a/src/shared/Tree.vue b/src/shared/Tree.vue new file mode 100644 index 0000000..cc4d736 --- /dev/null +++ b/src/shared/Tree.vue @@ -0,0 +1,320 @@ +<script setup lang="ts"> +import { computed, ref } from 'vue'; + +interface Props { + items?: { + text: string; + link?: string; + color?: string; + children?: { + text: string; + link?: string; + color?: string; + children?: { + text: string; + link?: string; + color?: string; + }[]; + }[]; + }[]; + maxWidth?: number; + expand?: boolean; + theme?: + | 'white' + | 'slate' + | 'blue' + | 'sky' + | 'teal' + | 'lime' + | 'green' + | 'yellow' + | 'orange' + | 'pink' + | 'fuchsia' + | 'purple' + | 'indigo' + | 'rose' + | 'red' + | 'black'; +} +const props = defineProps<Props>(); +const items = computed(() => props.items); +const colorTheme = computed(() => { + if (!props?.theme) return '#ffffff'; + switch (props?.theme) { + case 'white': + return '#ffffff'; + case 'slate': + return '#64748b'; + case 'blue': + return '#3b82f6'; + case 'sky': + return '#0ea5e9'; + case 'teal': + return '#14b8a6'; + case 'lime': + return '#84cc16'; + case 'green': + return '#22c55e'; + case 'yellow': + return '#eab308'; + case 'orange': + return '#f97316'; + case 'pink': + return '#ec4899'; + case 'fuchsia': + return '#d946ef'; + case 'purple': + return '#a855f7'; + case 'indigo': + return '#6366f1'; + case 'rose': + return '#f43f5e'; + case 'red': + return '#ef4444'; + case 'black': + return '#000000'; + } + return '#ffffff'; +}); +const textColor = computed(() => { + if (!props.theme) return '#000000'; + if (props.theme === 'white') return '#000000'; + return '#ffffff'; +}); + +const state = ref([]); +const setInitialState = () => { + if (!props?.items) return; + for (let item of props.items) { + state.value.push({ + isOpen: props?.expand ?? false, + text: item.text + }); + if (item.children) { + for (let child of item.children) { + state.value.push({ + isOpen: props?.expand ?? false, + text: child.text + }); + console.log('child', child); + if (child.children) { + for (let grandChild of child.children) { + state.value.push({ + isOpen: props?.expand ?? false, + text: grandChild.text + }); + } + } + } + } + } +}; +watch([items], () => { + if (items.value) setInitialState(); +}); +const toggleIsOpen = (item) => + state.value.map((itemState) => { + if (itemState.text === item.text) itemState.isOpen = !itemState.isOpen; + }); +</script> + +<template> + <ul + :style="`background-color: ${colorTheme ?? 'white'}; max-width: ${maxWidth ?? 300}px`" + class="tree" + > + <li + v-for="item of items" + :key="item.text" + :class="[ + 'item flex', + { + openItem: state.find((itemState) => itemState.text === item.text && itemState.isOpen) + } + ]" + > + <svg + v-if="item.children" + :class="[ + 'openButton', + { + openButtonOpened: state.find( + (itemState) => itemState.text === item.text && itemState.isOpen + ) + } + ]" + width="25px" + height="25px" + viewBox="0 -0.5 28 28" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sketch="http://www.bohemiancoding.com/sketch/ns" + @click.prevent="toggleIsOpen(item)" + > + <g + id="Page-1" + stroke="none" + stroke-width="1" + fill="none" + fill-rule="evenodd" + sketch:type="MSPage" + > + <g + id="Icon-Set-Filled" + sketch:type="MSLayerGroup" + transform="translate(-156.000000, -623.000000)" + :fill="textColor ?? '#000000'" + > + <path + id="open" + d="M183,647.998 L157,647.998 C156.448,647.998 156,648.446 156,648.999 C156,649.552 156.448,650 157,650 L183,650 C183.552,650 184,649.552 184,648.999 C184,648.446 183.552,647.998 183,647.998 L183,647.998 Z M158.014,645.995 L182.018,645.995 C184.375,645.995 184.296,644.608 183.628,643.574 L171.44,624.555 C170.882,623.771 169.22,623.703 168.56,624.555 L156.372,643.574 C155.768,644.703 155.687,645.995 158.014,645.995 L158.014,645.995 Z" + sketch:type="MSShapeGroup" + ></path> + </g> + </g> + </svg> + <div + :class="[ + 'content', + { + openContent: state.find((itemState) => itemState.text === item.text && itemState.isOpen) + } + ]" + > + <a :href="item.link" class="text">{{ item.text }}</a> + <div class="children"> + <div v-for="child of item.children" :key="child.text" class="flex item"> + <svg + v-if="child.children" + :class="[ + 'openButton', + { + openButtonOpened: state.find( + (itemState) => itemState.text === child.text && itemState.isOpen + ) + } + ]" + width="25px" + height="25px" + viewBox="0 -0.5 28 28" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sketch="http://www.bohemiancoding.com/sketch/ns" + @click.prevent="toggleIsOpen(child)" + > + <g + id="Page-1" + stroke="none" + stroke-width="1" + fill="none" + fill-rule="evenodd" + sketch:type="MSPage" + > + <g + id="Icon-Set-Filled" + sketch:type="MSLayerGroup" + transform="translate(-156.000000, -623.000000)" + :fill="textColor ?? '#000000'" + > + <path + id="open" + d="M183,647.998 L157,647.998 C156.448,647.998 156,648.446 156,648.999 C156,649.552 156.448,650 157,650 L183,650 C183.552,650 184,649.552 184,648.999 C184,648.446 183.552,647.998 183,647.998 L183,647.998 Z M158.014,645.995 L182.018,645.995 C184.375,645.995 184.296,644.608 183.628,643.574 L171.44,624.555 C170.882,623.771 169.22,623.703 168.56,624.555 L156.372,643.574 C155.768,644.703 155.687,645.995 158.014,645.995 L158.014,645.995 Z" + sketch:type="MSShapeGroup" + ></path> + </g> + </g> + </svg> + <div + :class="[ + 'content', + { + openContent: state.find( + (itemState) => itemState.text === child.text && itemState.isOpen + ) + } + ]" + > + <a :href="child.link" class="text">{{ child.text }}</a> + <div class="children"> + <div v-for="grandChild of child.children" :key="grandChild.text" class="flex item"> + <div + :class="[ + 'content', + { + openContent: state.find( + (itemState) => itemState.text === grandChild.text && itemState.isOpen + ) + } + ]" + > + <p :href="grandChild.link" class="text">{{ grandChild.text }}</p> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </li> + </ul> +</template> + +<style scoped> +.tree { + padding: 15px 25px 15px 15px; +} +.item { + position: relative; +} +.content { + width: 100%; + padding-left: 25px; + position: relative; + overflow: hidden; + transition: all 0.3s ease; + background-color: v-bind(colorTheme); +} +.text { + display: block; + position: relative; + padding: 4px 0 4px 5px; + z-index: 3; + color: v-bind(textColor); + background-color: v-bind(colorTheme); + word-break: break-word; +} +.openButton { + position: absolute; + z-index: 3; + top: 5px; + left: 0; + cursor: pointer; + padding: 5px; + margin: -5px -5px -5px 0; + transition: transform 0.3s ease; +} +.openButtonOpened { + transform: rotate(180deg); +} +.children { + width: 100%; + padding-left: 10px; + opacity: 0; + max-height: 0; + transform: translateY(-100%); + transition: all 0.3s ease; +} +.openContent > .children { + transform: translateY(0); + opacity: 1; + max-height: 1000px; +} +.flex { + display: flex; + align-items: start; + justify-content: end; +} +</style> diff --git a/src/shared/icons/CloseCircle.vue b/src/shared/icons/CloseCircle.vue index 688ad16..e288723 100644 --- a/src/shared/icons/CloseCircle.vue +++ b/src/shared/icons/CloseCircle.vue @@ -18,7 +18,7 @@ defineProps<Props>(); fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM8.96963 8.96965C9.26252 8.67676 9.73739 8.67676 10.0303 8.96965L12 10.9393L13.9696 8.96967C14.2625 8.67678 14.7374 8.67678 15.0303 8.96967C15.3232 9.26256 15.3232 9.73744 15.0303 10.0303L13.0606 12L15.0303 13.9696C15.3232 14.2625 15.3232 14.7374 15.0303 15.0303C14.7374 15.3232 14.2625 15.3232 13.9696 15.0303L12 13.0607L10.0303 15.0303C9.73742 15.3232 9.26254 15.3232 8.96965 15.0303C8.67676 14.7374 8.67676 14.2625 8.96965 13.9697L10.9393 12L8.96963 10.0303C8.67673 9.73742 8.67673 9.26254 8.96963 8.96965Z" - fill="#1C274C" + :fill="color ?? '#1C274C'" /> </svg> </template> diff --git a/src/shared/icons/ExitIcon.vue b/src/shared/icons/ExitIcon.vue new file mode 100644 index 0000000..ffff729 --- /dev/null +++ b/src/shared/icons/ExitIcon.vue @@ -0,0 +1,30 @@ +<script setup lang="ts"> +interface Props { + color?: string; + size?: string | number; +} +defineProps<Props>(); +</script> + +<template> + <svg + :width="`${size ?? 40}px`" + :height="`${size ?? 40}px`" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M9.70725 2.4087C9 3.03569 9 4.18259 9 6.4764V17.5236C9 19.8174 9 20.9643 9.70725 21.5913C10.4145 22.2183 11.4955 22.0297 13.6576 21.6526L15.9864 21.2465C18.3809 20.8288 19.5781 20.62 20.2891 19.7417C21 18.8635 21 17.5933 21 15.0529V8.94711C21 6.40671 21 5.13652 20.2891 4.25826C19.5781 3.37999 18.3809 3.17118 15.9864 2.75354L13.6576 2.34736C11.4955 1.97026 10.4145 1.78171 9.70725 2.4087ZM12 10.1686C12.4142 10.1686 12.75 10.52 12.75 10.9535V13.0465C12.75 13.48 12.4142 13.8314 12 13.8314C11.5858 13.8314 11.25 13.48 11.25 13.0465V10.9535C11.25 10.52 11.5858 10.1686 12 10.1686Z" + :fill="color ?? '#1C274C'" + /> + <path + d="M7.54717 4.5C5.48889 4.503 4.41599 4.54826 3.73223 5.23202C3 5.96425 3 7.14276 3 9.49979V14.4998C3 16.8568 3 18.0353 3.73223 18.7676C4.41599 19.4513 5.48889 19.4966 7.54717 19.4996C7.49985 18.8763 7.49992 18.1557 7.50001 17.3768V6.6227C7.49992 5.84388 7.49985 5.1233 7.54717 4.5Z" + :fill="color ?? '#1C274C'" + /> + </svg> +</template> + +<style scoped></style> diff --git a/src/shared/icons/HamgurgerMenu.vue b/src/shared/icons/HamgurgerMenu.vue index bc67560..bdbe96a 100644 --- a/src/shared/icons/HamgurgerMenu.vue +++ b/src/shared/icons/HamgurgerMenu.vue @@ -18,7 +18,7 @@ defineProps<Props>(); fill-rule="evenodd" clip-rule="evenodd" d="M3.46447 20.5355C4.92893 22 7.28595 22 12 22C16.714 22 19.0711 22 20.5355 20.5355C22 19.0711 22 16.714 22 12C22 7.28595 22 4.92893 20.5355 3.46447C19.0711 2 16.714 2 12 2C7.28595 2 4.92893 2 3.46447 3.46447C2 4.92893 2 7.28595 2 12C2 16.714 2 19.0711 3.46447 20.5355ZM18.75 16C18.75 16.4142 18.4142 16.75 18 16.75H6C5.58579 16.75 5.25 16.4142 5.25 16C5.25 15.5858 5.58579 15.25 6 15.25H18C18.4142 15.25 18.75 15.5858 18.75 16ZM18 12.75C18.4142 12.75 18.75 12.4142 18.75 12C18.75 11.5858 18.4142 11.25 18 11.25H6C5.58579 11.25 5.25 11.5858 5.25 12C5.25 12.4142 5.58579 12.75 6 12.75H18ZM18.75 8C18.75 8.41421 18.4142 8.75 18 8.75H6C5.58579 8.75 5.25 8.41421 5.25 8C5.25 7.58579 5.58579 7.25 6 7.25H18C18.4142 7.25 18.75 7.58579 18.75 8Z" - fill="#1C274C" + :fill="color ?? '#1C274C'" /> </svg> </template> diff --git a/src/shared/icons/HomeIcon.vue b/src/shared/icons/HomeIcon.vue new file mode 100644 index 0000000..50dabe0 --- /dev/null +++ b/src/shared/icons/HomeIcon.vue @@ -0,0 +1,26 @@ +<script setup lang="ts"> +interface Props { + color?: string; + size?: string | number; +} +defineProps<Props>(); +</script> + +<template> + <svg + :width="`${size ?? 40}px`" + :height="`${size ?? 40}px`" + viewBox="0 0 16 16" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M8 0L0 6V8H1V15H4V10H7V15H15V8H16V6L14 4.5V1H11V2.25L8 0ZM9 10H12V13H9V10Z" + :fill="color ?? '#000000'" + /> + </svg> +</template> + +<style scoped></style> diff --git a/src/shared/icons/NavigationIcon.vue b/src/shared/icons/NavigationIcon.vue new file mode 100644 index 0000000..fcd6ccf --- /dev/null +++ b/src/shared/icons/NavigationIcon.vue @@ -0,0 +1,30 @@ +<script setup lang="ts"> +interface Props { + color?: string; + size?: string | number; +} +defineProps<Props>(); +</script> + +<template> + <svg + :width="`${size ?? 40}px`" + :height="`${size ?? 40}px`" + viewBox="0 0 512 512" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + > + <title>navigation-filled</title> + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="icon" :fill="color ?? '#000000'" transform="translate(42.666667, 42.666667)"> + <path + id="Combined-Shape" + d="M213.333333,3.55271368e-14 C331.15408,3.55271368e-14 426.666667,95.5125867 426.666667,213.333333 C426.666667,331.15408 331.15408,426.666667 213.333333,426.666667 C95.5125867,426.666667 3.55271368e-14,331.15408 3.55271368e-14,213.333333 C3.55271368e-14,95.5125867 95.5125867,3.55271368e-14 213.333333,3.55271368e-14 Z M234.666667,341.333333 L192,341.333333 L192,384 L234.666667,384 L234.666667,341.333333 Z M320,106.666667 L181.333333,181.333333 L106.666667,320 L245.333333,245.333333 L320,106.666667 Z M213.333333,192 C225.115408,192 234.666667,201.551259 234.666667,213.333333 C234.666667,225.115408 225.115408,234.666667 213.333333,234.666667 C201.551259,234.666667 192,225.115408 192,213.333333 C192,201.551259 201.551259,192 213.333333,192 Z M384,192 L341.333333,192 L341.333333,234.666667 L384,234.666667 L384,192 Z M85.3333333,192 L42.6666667,192 L42.6666667,234.666667 L85.3333333,234.666667 L85.3333333,192 Z M234.666667,42.6666667 L192,42.6666667 L192,85.3333333 L234.666667,85.3333333 L234.666667,42.6666667 Z" + ></path> + </g> + </g> + </svg> +</template> + +<style scoped></style> diff --git a/src/shared/icons/SettingsIcon.vue b/src/shared/icons/SettingsIcon.vue new file mode 100644 index 0000000..41b9327 --- /dev/null +++ b/src/shared/icons/SettingsIcon.vue @@ -0,0 +1,43 @@ +<script setup lang="ts"> +interface Props { + color?: string; + size?: string | number; +} +defineProps<Props>(); +</script> + +<template> + <svg + :width="`${size ?? 40}px`" + :height="`${size ?? 40}px`" + viewBox="0 0 30 30" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sketch="http://www.bohemiancoding.com/sketch/ns" + > + <g + id="Page-1" + stroke="none" + stroke-width="1" + fill="none" + fill-rule="evenodd" + sketch:type="MSPage" + > + <g + id="Icon-Set-Filled" + sketch:type="MSLayerGroup" + transform="translate(-103.000000, -362.000000)" + :fill="color ?? '#000000'" + > + <path + id="settings" + d="M118,382 C115.261,382 113.042,379.762 113.042,377 C113.042,374.238 115.261,372 118,372 C120.739,372 122.959,374.238 122.959,377 C122.959,379.762 120.739,382 118,382 L118,382 Z M132.008,380.536 L129.685,379.184 C129.815,378.474 129.901,377.749 129.901,377 C129.901,376.252 129.815,375.526 129.685,374.816 L132.008,373.464 C132.957,372.912 133.281,371.688 132.733,370.732 L130.75,367.268 C130.203,366.312 128.989,365.983 128.041,366.536 L125.694,367.901 C124.598,366.961 123.352,366.192 121.967,365.697 L121.967,364 C121.967,362.896 121.079,362 119.983,362 L116.017,362 C114.921,362 114.033,362.896 114.033,364 L114.033,365.697 C112.648,366.192 111.402,366.961 110.306,367.901 L107.959,366.536 C107.011,365.983 105.797,366.312 105.25,367.268 L103.267,370.732 C102.719,371.688 103.044,372.912 103.992,373.464 L106.315,374.816 C106.185,375.526 106.099,376.252 106.099,377 C106.099,377.749 106.185,378.474 106.315,379.184 L103.992,380.536 C103.044,381.088 102.719,382.312 103.267,383.268 L105.25,386.732 C105.797,387.688 107.011,388.017 107.959,387.464 L110.306,386.099 C111.402,387.039 112.648,387.809 114.033,388.303 L114.033,390 C114.033,391.104 114.921,392 116.017,392 L119.983,392 C121.079,392 121.967,391.104 121.967,390 L121.967,388.303 C123.352,387.809 124.598,387.039 125.694,386.099 L128.041,387.464 C128.989,388.017 130.203,387.688 130.75,386.732 L132.733,383.268 C133.281,382.312 132.957,381.088 132.008,380.536 L132.008,380.536 Z M118,374 C116.357,374 115.025,375.344 115.025,377 C115.025,378.657 116.357,380 118,380 C119.643,380 120.975,378.657 120.975,377 C120.975,375.344 119.643,374 118,374 L118,374 Z" + sketch:type="MSShapeGroup" + ></path> + </g> + </g> + </svg> +</template> + +<style scoped></style> diff --git a/src/shared/icons/VerticalArrowsIcon.vue b/src/shared/icons/VerticalArrowsIcon.vue new file mode 100644 index 0000000..07ca726 --- /dev/null +++ b/src/shared/icons/VerticalArrowsIcon.vue @@ -0,0 +1,34 @@ +<script setup lang="ts"> +interface Props { + color?: string; + size?: string | number; +} +defineProps<Props>(); +</script> + +<template> + <svg + id="Capa_1" + :width="`${size ?? 40}px`" + :height="`${size ?? 40}px`" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + viewBox="0 0 349.455 349.455" + xml:space="preserve" + > + <path + :style="`fill: ${color ?? '#231f20'}`" + d="M248.263,240.135c-1.407-1.407-3.314-2.197-5.304-2.197c-1.989,0-3.896,0.79-5.304,2.197 + l-45.429,45.429l0.001-221.673l45.428,45.429c1.407,1.407,3.314,2.197,5.304,2.197c1.989,0,3.896-0.79,5.304-2.197l14.143-14.143 + c1.406-1.406,2.196-3.314,2.196-5.303c0-1.989-0.79-3.897-2.196-5.303L180.032,2.197C178.625,0.79,176.717,0,174.728,0 + c-1.989,0-3.896,0.79-5.304,2.197L87.049,84.573c-1.406,1.407-2.196,3.314-2.196,5.303c0,1.989,0.79,3.897,2.197,5.304 + l14.143,14.142c1.464,1.464,3.384,2.196,5.303,2.196c1.919,0,3.839-0.732,5.304-2.197l45.429-45.43l-0.001,221.673l-45.428-45.429 + c-1.407-1.407-3.314-2.197-5.304-2.197c-1.989,0-3.896,0.79-5.304,2.197l-14.143,14.143c-1.406,1.406-2.196,3.314-2.196,5.303 + c0,1.989,0.79,3.897,2.196,5.303l82.374,82.374c1.465,1.464,3.385,2.197,5.304,2.197c1.919,0,3.839-0.733,5.304-2.197l82.375-82.375 + c1.406-1.406,2.196-3.314,2.196-5.303c0-1.989-0.79-3.897-2.196-5.303L248.263,240.135z" + /> + </svg> +</template> + +<style scoped></style> -- GitLab