feat: settings page

This commit is contained in:
Anthony Fu 2023-03-18 21:59:48 +01:00
parent 555cebe06e
commit 846e782d2b
8 changed files with 173 additions and 20 deletions

1
src/components.d.ts vendored
View File

@ -34,6 +34,7 @@ declare module '@vue/runtime-core' {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SearchElectron: typeof import('./components/electron/SearchElectron.vue')['default']
SettingsCollectionsList: typeof import('./components/SettingsCollectionsList.vue')['default']
WithNavbar: typeof import('./components/WithNavbar.vue')['default']
}
}

View File

@ -132,6 +132,13 @@ const favorited = computed(() => isFavoritedCollection(props.collection.id))
<div flex="~ gap3" text-xl items-center>
<DarkSwitcher />
<RouterLink
icon-button
i-carbon-settings
title="Settings"
to="/settings"
/>
<button
v-if="collection.id !== 'all'"
icon-button

View File

@ -1,10 +1,16 @@
<script lang="ts">
import { getSearchResults, isDark } from '../store'
export default defineComponent(() => ({
...getSearchResults(),
isDark,
}))
export default defineComponent(() => {
const route = useRoute()
return {
...getSearchResults(),
isDark,
showNav: computed(() => !route.path.startsWith('/collection')),
isHomepage: computed(() => route.path === '/'),
}
})
</script>
<template>
@ -12,25 +18,25 @@ export default defineComponent(() => ({
class="dragging"
flex="~ gap4 none"
p4 relative bg-base z-10 border="b base" text-xl
:class="$route.path !== '/' ? 'md:hidden' : ''"
:class="showNav ? '' : 'md:hidden'"
>
<!-- In Collections -->
<template v-if="$route.path !== '/'">
<div
<template v-if="!isHomepage">
<RouterLink
class="non-dragging"
icon-button flex-none
i-carbon:arrow-left
@click="$router.replace('/')"
to="/"
/>
</template>
<!-- Homepage Only -->
<template v-else>
<RouterLink
<template v-if="showNav">
<!-- <RouterLink
class="non-dragging"
i-carbon:search icon-button flex-none
to="/collection/all"
/>
/> -->
<div flex-auto />
<h1
absolute top-0 left-0 right-0 bottom-0 flex items-center justify-center
@ -43,17 +49,24 @@ export default defineComponent(() => ({
i-carbon-logo-github icon-button flex-none
href="https://github.com/antfu/icones"
target="_blank"
title="GitHub"
/>
<RouterLink
class="non-dragging"
i-carbon-settings icon-button flex-none
to="/settings"
title="Settings"
/>
<DarkSwitcher flex-none />
</template>
<!-- Searching -->
<div v-if="collection" class="flex">
<form action="/collection/all" role="search" method="get" @submit.prevent>
<div v-if="collection" class="flex w-full">
<form action="/collection/all" role="search" method="get" class="w-full" @submit.prevent>
<input
v-model="search"
aria-label="Search"
class="color-base text-base outline-none py-2 px-4 flex-auto m-0 w-full bg-transparent"
class="color-base text-base outline-none px-4 flex-auto m-0 w-full bg-transparent"
name="s"
placeholder="Search..."
>

View File

@ -0,0 +1,49 @@
<script setup lang="ts">
import type { CollectionMeta } from '../data'
import { isInstalled } from '../data'
import { isElectron } from '../env'
import { isExcludedCategory, isExcludedCollection, isFavoritedCollection, toggleExcludedCollection, toggleFavoriteCollection } from '../store'
defineProps<{
collections: CollectionMeta[]
}>()
</script>
<template>
<div>
<div
v-for="c, idx of collections" :key="c.id" flex="~ gap-2" py1 px2 items-center
border="b l r base"
:class="idx === 0 ? 'border-t' : ''"
>
<RouterLink
:to="`/collection/${c.id}`"
flex-auto
:class="isExcludedCollection(c) ? 'op25 line-through' : ''"
>
{{ c.name }}
</RouterLink>
<div />
<div
v-if="isInstalled(c.id) && !isElectron"
icon-button class="!op50"
i-carbon-cloud-auditing
title="Cached in browser"
/>
<button
v-if="!isExcludedCollection(c)"
icon-button
:class="isFavoritedCollection(c.id) ? 'i-carbon:star-filled text-yellow' : 'i-carbon:star'"
title="Toggle Favorite"
@click="toggleFavoriteCollection(c.id)"
/>
<button
v-if="!isExcludedCategory(c.category)"
icon-button
:class="isExcludedCollection(c) ? 'i-carbon:view-off text-rose' : 'i-carbon:view'"
title="Toggle Visible"
@click="toggleExcludedCollection(c.id)"
/>
</div>
</div>
</template>

View File

@ -2,7 +2,7 @@ import type { IconifyJSON } from 'iconify-icon'
import { notNullish } from '@antfu/utils'
import { addCollection } from 'iconify-icon'
import { AsyncFzf } from 'fzf'
import { favoritedCollectionIds, inProgress, isFavoritedCollection, isRecentCollection, progressMessage, recentCollectionIds, sortAlphabetically } from '../store'
import { favoritedCollectionIds, inProgress, isExcludedCollection, isFavoritedCollection, isRecentCollection, progressMessage, recentCollectionIds, sortAlphabetically } from '../store'
import { isLocalMode, staticPath } from '../env'
import { loadCollection, saveCollection } from '../store/indexedDB'
import infoJSON from './collections-info.json'
@ -35,6 +35,7 @@ const loadedMeta = ref<CollectionMeta[]>([])
const installed = ref<string[]>([])
export const collections = infoJSON.map(c => Object.freeze(c as any as CollectionInfo))
export const enabledCollections = computed(() => collections.filter(c => !isExcludedCollection(c)))
export const categories = Array.from(new Set(collections.map(i => i.category).filter(notNullish)))
export const isSearchOpen = ref(false)
@ -46,11 +47,11 @@ const fzf = new AsyncFzf(collections, {
selector: v => `${v.name} ${v.id} ${v.category} ${v.author}`,
})
export const filteredCollections = ref<CollectionInfo[]>(collections)
export const filteredCollections = ref<CollectionInfo[]>(enabledCollections.value)
watch(categorySearch, (q) => {
watch([categorySearch, enabledCollections], ([q]) => {
if (!q) {
filteredCollections.value = collections
filteredCollections.value = enabledCollections.value
}
else {
fzf.find(q).then((result) => {

48
src/pages/settings.vue Normal file
View File

@ -0,0 +1,48 @@
<script setup lang="ts">
import type { PresentType } from '../data'
import { categories, collections } from '../data'
import { isExcludedCategory, toggleExcludedCategory } from '../store'
const categorizedCollections = computed(() => categories.map(category => ({
name: category,
type: 'normal' as PresentType,
collections: collections.filter(collection => collection.category === category),
})))
</script>
<template>
<WithNavbar>
<div p4>
<!-- <h1 text-xl>
Features
</h1>
<input id="toggle-dark-mode" v-model="darkMode" type="checkbox"> -->
<h1 text-xl>
Collections
</h1>
<p op50 mb5>
Manage collections to be listed in the home page and search results.
</p>
<div flex="~ gap-4" w-full of-auto>
<div v-for="c of categorizedCollections" :key="c.name">
<div flex py1 px2>
<h1 font-bold op75 flex-auto>
{{ c.name }}
</h1>
<button
icon-button
:class="isExcludedCategory(c.name) ? 'i-carbon:view-off text-red' : 'i-carbon:view'"
title="Toggle Visible"
@click="toggleExcludedCategory(c.name)"
/>
</div>
<SettingsCollectionsList :collections="c.collections" w-70 />
</div>
</div>
</div>
</WithNavbar>
</template>

View File

@ -10,7 +10,7 @@ import {
} from '../data'
import { useSearch } from '../hooks'
import { isLocalMode } from '../env'
import { recentIconIds } from './localstorage'
import { isExcludedCollection, recentIconIds } from './localstorage'
const currentCollectionId = ref('')
const loaded = ref(false)
@ -66,7 +66,11 @@ export async function setCurrentCollection(id: string) {
collection.value = {
id: 'all',
name: 'All',
icons: meta.flatMap(c => c.icons.map(i => `${c.id}:${i}`)),
icons: meta.flatMap((c) => {
if (isExcludedCollection(c))
return []
return c.icons.map(i => `${c.id}:${i}`)
}),
}
loaded.value = true
}

View File

@ -1,3 +1,4 @@
import type { CollectionInfo } from '../data'
import type { IdCase } from '../utils/case'
import { idCases } from '../utils/case'
@ -19,6 +20,11 @@ export const activeMode = useStorage<ActiveMode>('active-mode', 'normal')
export const preferredCase = useStorage<IdCase>('icones-preferfed-case', 'iconify')
export const sortAlphabetically = useStorage('icones-alpha-sort-collections', false)
export const excludedCollectionIds = useStorage<string[]>('icones-excluded-collections', [])
export const excludedCategories = useStorage<string[]>('icones-excluded-categories', [
'Archive / Unmaintained',
])
export function getTransformedId(icon: string) {
return idCases[preferredCase.value]?.(icon) || icon
}
@ -27,6 +33,14 @@ export function isFavoritedCollection(id: string) {
return favoritedCollectionIds.value.includes(id)
}
export function isExcludedCollection(collection: CollectionInfo) {
return excludedCollectionIds.value.includes(collection.id) || excludedCategories.value.includes(collection.category || '')
}
export function isExcludedCategory(category: string | undefined) {
return category && excludedCategories.value.includes(category)
}
export function isRecentCollection(id: string) {
return recentCollectionIds.value.includes(id)
}
@ -59,6 +73,22 @@ export function toggleFavoriteCollection(id: string) {
favoritedCollectionIds.value.push(id)
}
export function toggleExcludedCollection(id: string) {
const index = excludedCollectionIds.value.indexOf(id)
if (index >= 0)
excludedCollectionIds.value.splice(index, 1)
else
excludedCollectionIds.value.push(id)
}
export function toggleExcludedCategory(category: string) {
const index = excludedCategories.value.indexOf(category)
if (index >= 0)
excludedCategories.value.splice(index, 1)
else
excludedCategories.value.push(category)
}
export function addToBag(id: string) {
if (!bags.value.includes(id))
bags.value.push(id)