From 4cd809bd0c94836532f58a2ec6aa131694cce10d Mon Sep 17 00:00:00 2001 From: Corentin Thomasset Date: Sat, 17 Dec 2022 01:30:02 +0100 Subject: [PATCH] feat(tools): added favorite tool handling --- src/components/FavoriteButton.vue | 40 +++++++++++++++++++++++ src/components/MenuIconItem.vue | 4 +-- src/components/SearchBar.vue | 6 ++-- src/components/SearchBarItem.vue | 4 +-- src/components/ToolCard.vue | 31 ++++++++++-------- src/pages/Home.page.vue | 53 +++++++++++++++++++++++++++++-- src/tools/index.ts | 10 +----- src/tools/tool.ts | 21 ++---------- src/tools/tools.store.ts | 44 +++++++++++++++++++++++++ src/tools/tools.types.ts | 19 +++++++++++ 10 files changed, 181 insertions(+), 51 deletions(-) create mode 100644 src/components/FavoriteButton.vue create mode 100644 src/tools/tools.store.ts create mode 100644 src/tools/tools.types.ts diff --git a/src/components/FavoriteButton.vue b/src/components/FavoriteButton.vue new file mode 100644 index 00000000..26791f3a --- /dev/null +++ b/src/components/FavoriteButton.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/components/MenuIconItem.vue b/src/components/MenuIconItem.vue index 0909e567..a08fe241 100644 --- a/src/components/MenuIconItem.vue +++ b/src/components/MenuIconItem.vue @@ -6,11 +6,11 @@ diff --git a/src/components/SearchBarItem.vue b/src/components/SearchBarItem.vue index d81606a6..ca792686 100644 --- a/src/components/SearchBarItem.vue +++ b/src/components/SearchBarItem.vue @@ -1,8 +1,8 @@ diff --git a/src/components/ToolCard.vue b/src/components/ToolCard.vue index 926c5e94..79586f81 100644 --- a/src/components/ToolCard.vue +++ b/src/components/ToolCard.vue @@ -3,17 +3,21 @@ - - New - + + + New + + + + {{ tool.name }} @@ -29,11 +33,12 @@ diff --git a/src/pages/Home.page.vue b/src/pages/Home.page.vue index 88086ee4..4c80494a 100644 --- a/src/pages/Home.page.vue +++ b/src/pages/Home.page.vue @@ -1,10 +1,12 @@ @@ -32,8 +34,34 @@ useHead({ title: 'IT Tools - Handy online tools for developers' }); - - + + + +
+ Your favorite tools + + + + + +
+
+ +
+ Newest tools + + + + + +
+ + All the tools + + + + + @@ -43,4 +71,23 @@ useHead({ title: 'IT Tools - Handy online tools for developers' }); .home-page { padding-top: 50px; } + +::v-deep(.n-grid) { + margin-bottom: 12px; +} + +.height-enter-active, +.height-leave-active { + transition: all 0.5s ease-in-out; + overflow: hidden; + max-height: 500px; +} + +.height-enter-from, +.height-leave-to { + max-height: 42px; + overflow: hidden; + opacity: 0; + margin-bottom: 0; +} diff --git a/src/tools/index.ts b/src/tools/index.ts index 60ad21d0..38975f61 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,5 +1,4 @@ import { LockOpen } from '@vicons/tabler'; -import type { ToolCategory } from './tool'; import { tool as chmodCalculator } from './chmod-calculator'; import { tool as mimeTypes } from './mime-types'; @@ -36,16 +35,15 @@ import { tool as tokenGenerator } from './token-generator'; import { tool as urlEncoder } from './url-encoder'; import { tool as urlParser } from './url-parser'; import { tool as uuidGenerator } from './uuid-generator'; +import type { ToolCategory } from './tools.types'; export const toolsByCategory: ToolCategory[] = [ { name: 'Crypto', - icon: LockOpen, components: [tokenGenerator, hashText, bcrypt, uuidGenerator, cypher, bip39, hmacGenerator], }, { name: 'Converter', - icon: LockOpen, components: [ dateTimeConverter, baseConverter, @@ -58,7 +56,6 @@ export const toolsByCategory: ToolCategory[] = [ }, { name: 'Web', - icon: LockOpen, components: [ urlEncoder, htmlEntities, @@ -72,27 +69,22 @@ export const toolsByCategory: ToolCategory[] = [ }, { name: 'Images', - icon: LockOpen, components: [qrCodeGenerator, svgPlaceholderGenerator], }, { name: 'Development', - icon: LockOpen, components: [gitMemo, randomPortGenerator, crontabGenerator, jsonViewer, sqlPrettify, chmodCalculator], }, { name: 'Math', - icon: LockOpen, components: [mathEvaluator, etaCalculator], }, { name: 'Measurement', - icon: LockOpen, components: [chronometer], }, { name: 'Text', - icon: LockOpen, components: [loremIpsumGenerator, textStatistics], }, ]; diff --git a/src/tools/tool.ts b/src/tools/tool.ts index b2ebf497..8289aa33 100644 --- a/src/tools/tool.ts +++ b/src/tools/tool.ts @@ -1,27 +1,10 @@ import { config } from '@/config'; -import type { Component } from 'vue'; - -export interface ITool { - name: string; - path: string; - description: string; - keywords: string[]; - component: () => Promise; - icon: Component; - redirectFrom?: string[]; - isNew: boolean; -} - -export interface ToolCategory { - name: string; - icon: Component; - components: ITool[]; -} +import type { Tool } from './tools.types'; type WithOptional = Omit & Partial>; export function defineTool( - tool: WithOptional, + tool: WithOptional, { newTools }: { newTools: string[] } = { newTools: config.tools.newTools }, ) { const isNew = newTools.includes(tool.name); diff --git a/src/tools/tools.store.ts b/src/tools/tools.store.ts new file mode 100644 index 00000000..2b0826c1 --- /dev/null +++ b/src/tools/tools.store.ts @@ -0,0 +1,44 @@ +import { get, useStorage, type MaybeRef } from '@vueuse/core'; +import { defineStore } from 'pinia'; +import type { Ref } from 'vue'; +import { toolsWithCategory } from './index'; +import type { Tool, ToolWithCategory } from './tools.types'; + +export const useToolStore = defineStore('tools', { + state: () => ({ + favoriteToolsName: useStorage('favoriteToolsName', []) as Ref, + }), + getters: { + favoriteTools(state) { + return state.favoriteToolsName + .map((favoriteName) => toolsWithCategory.find(({ name }) => name === favoriteName)) + .filter(Boolean) as ToolWithCategory[]; // cast because .filter(Boolean) does not remove undefined from type + }, + + notFavoriteTools(state): ToolWithCategory[] { + return toolsWithCategory.filter((tool) => !state.favoriteToolsName.includes(tool.name)); + }, + + tools(): ToolWithCategory[] { + return toolsWithCategory; + }, + + newTools(): ToolWithCategory[] { + return this.tools.filter(({ isNew }) => isNew); + }, + }, + + actions: { + addToolToFavorites({ tool }: { tool: MaybeRef }) { + this.favoriteToolsName.push(get(tool).name); + }, + + removeToolFromFavorites({ tool }: { tool: MaybeRef }) { + this.favoriteToolsName = this.favoriteToolsName.filter((name) => get(tool).name !== name); + }, + + isToolFavorite({ tool }: { tool: MaybeRef }) { + return this.favoriteToolsName.includes(get(tool).name); + }, + }, +}); diff --git a/src/tools/tools.types.ts b/src/tools/tools.types.ts new file mode 100644 index 00000000..5630a12e --- /dev/null +++ b/src/tools/tools.types.ts @@ -0,0 +1,19 @@ +import type { Component } from 'vue'; + +export type Tool = { + name: string; + path: string; + description: string; + keywords: string[]; + component: () => Promise; + icon: Component; + redirectFrom?: string[]; + isNew: boolean; +}; + +export type ToolCategory = { + name: string; + components: Tool[]; +}; + +export type ToolWithCategory = Tool & { category: string };