mirror of
https://github.com/antfu-collective/icones.git
synced 2026-01-09 07:40:49 +08:00
feat: settings page
This commit is contained in:
parent
555cebe06e
commit
846e782d2b
1
src/components.d.ts
vendored
1
src/components.d.ts
vendored
@ -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']
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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..."
|
||||
>
|
||||
|
||||
49
src/components/SettingsCollectionsList.vue
Normal file
49
src/components/SettingsCollectionsList.vue
Normal 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>
|
||||
@ -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
48
src/pages/settings.vue
Normal 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>
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user