Sort sidebar content by count

This commit is contained in:
Sam Becker 2025-03-23 16:57:55 -05:00
parent 7c3db85600
commit cdc83758b2
13 changed files with 93 additions and 98 deletions

View File

@ -4,7 +4,7 @@ import {
} from '@/photo';
import PhotosEmptyState from '@/photo/PhotosEmptyState';
import { Metadata } from 'next/types';
import { getPhotoSidebarData } from '@/photo/data';
import { getDataForCategories } from '@/category/data';
import { getPhotos, getPhotosMeta } from '@/photo/db/query';
import { cache } from 'react';
import PhotoGridPage from '@/photo/PhotoGridPage';
@ -28,8 +28,8 @@ export default async function GridPage() {
cameras,
lenses,
tags,
simulations,
recipes,
simulations,
focalLengths,
] = await Promise.all([
getPhotosCached()
@ -37,7 +37,7 @@ export default async function GridPage() {
getPhotosMeta()
.then(({ count }) => count)
.catch(() => 0),
...getPhotoSidebarData(),
...getDataForCategories(),
]);
return (

View File

@ -8,7 +8,7 @@ import { Metadata } from 'next/types';
import { cache } from 'react';
import { getPhotos, getPhotosMeta } from '@/photo/db/query';
import { GRID_HOMEPAGE_ENABLED } from '@/app/config';
import { getPhotoSidebarData } from '@/photo/data';
import { getDataForCategories } from '@/category/data';
import PhotoGridPage from '@/photo/PhotoGridPage';
import PhotoFeedPage from '@/photo/PhotoFeedPage';
@ -34,8 +34,8 @@ export default async function HomePage() {
cameras,
lenses,
tags,
simulations,
recipes,
simulations,
focalLengths,
] = await Promise.all([
getPhotosCached()
@ -44,7 +44,7 @@ export default async function HomePage() {
.then(({ count }) => count)
.catch(() => 0),
...(GRID_HOMEPAGE_ENABLED
? getPhotoSidebarData()
? getDataForCategories()
: [[], [], [], [], [], [], []]),
]);
@ -58,8 +58,8 @@ export default async function HomePage() {
cameras,
lenses,
tags,
simulations,
recipes,
simulations,
focalLengths,
}}
/>

View File

@ -7,7 +7,7 @@ import { photoQuantityText } from '@/photo';
import EditButton from '@/admin/EditButton';
import { pathForAdminRecipeEdit } from '@/app/paths';
import { clsx } from 'clsx/lite';
import { formatRecipe, Recipes, sortRecipesWithCount } from '@/recipe';
import { formatRecipe, Recipes, sortRecipes } from '@/recipe';
import AdminRecipeBadge from './AdminRecipeBadge';
export default function AdminRecipeTable({
@ -17,7 +17,7 @@ export default function AdminRecipeTable({
}) {
return (
<AdminTable>
{sortRecipesWithCount(recipes).map(({ recipe, count }) =>
{sortRecipes(recipes).map(({ recipe, count }) =>
<Fragment key={recipe}>
<div className="pr-2 col-span-2">
<AdminRecipeBadge {...{ recipe, count }} />

View File

@ -4,7 +4,7 @@ import AdminTable from '@/admin/AdminTable';
import { Fragment } from 'react';
import DeleteFormButton from '@/admin/DeleteFormButton';
import { photoQuantityText } from '@/photo';
import { Tags, formatTag, sortTagsObject } from '@/tag';
import { Tags, formatTag, sortTags } from '@/tag';
import EditButton from '@/admin/EditButton';
import { pathForAdminTagEdit } from '@/app/paths';
import { clsx } from 'clsx/lite';
@ -17,7 +17,7 @@ export default function AdminTagTable({
}) {
return (
<AdminTable>
{sortTagsObject(tags).map(({ tag, count }) =>
{sortTags(tags).map(({ tag, count }) =>
<Fragment key={tag}>
<div className="pr-2 col-span-2">
<AdminTagBadge {...{ tag, count }} />

View File

@ -1,20 +1,8 @@
import CommandKClient from '@/components/cmdk/CommandKClient';
import {
getPhotosMetaCached,
getUniqueCamerasCached,
getUniqueFilmSimulationsCached,
getUniqueLensesCached,
getUniqueRecipesCached,
getUniqueTagsCached,
} from '@/photo/cache';
import { getPhotosMetaCached } from '@/photo/cache';
import { photoQuantityText } from '@/photo';
import {
ADMIN_DEBUG_TOOLS_ENABLED,
SHOW_FILM_SIMULATIONS,
SHOW_RECIPES,
} from './config';
import { getUniqueFocalLengths } from '@/photo/db/query';
import { sortCategoryByCount } from '@/category';
import { ADMIN_DEBUG_TOOLS_ENABLED } from './config';
import { getDataForCategories } from '@/category/data';
export default async function CommandK() {
const [
@ -29,25 +17,16 @@ export default async function CommandK() {
getPhotosMetaCached()
.then(({ count }) => count)
.catch(() => 0),
getUniqueCamerasCached().catch(() => []),
getUniqueLensesCached().catch(() => []),
getUniqueTagsCached().catch(() => []),
SHOW_RECIPES
? getUniqueRecipesCached().catch(() => [])
: [],
SHOW_FILM_SIMULATIONS
? getUniqueFilmSimulationsCached().catch(() => [])
: [],
getUniqueFocalLengths().catch(() => []),
...getDataForCategories(),
]);
return <CommandKClient
cameras={cameras.sort(sortCategoryByCount)}
lenses={lenses.sort(sortCategoryByCount)}
tags={tags.sort(sortCategoryByCount)}
simulations={filmSimulations.sort(sortCategoryByCount)}
recipes={recipes.sort(sortCategoryByCount)}
focalLengths={focalLengths.sort(sortCategoryByCount)}
cameras={cameras}
lenses={lenses}
tags={tags}
simulations={filmSimulations}
recipes={recipes}
focalLengths={focalLengths}
showDebugTools={ADMIN_DEBUG_TOOLS_ENABLED}
footer={photoQuantityText(count, false)}
/>;

45
src/category/data.ts Normal file
View File

@ -0,0 +1,45 @@
import {
getUniqueCameras,
getUniqueFilmSimulations,
getUniqueFocalLengths,
getUniqueLenses,
getUniqueRecipes,
getUniqueTags,
} from '@/photo/db/query';
import {
SHOW_FILM_SIMULATIONS,
SHOW_FOCAL_LENGTHS,
SHOW_LENSES,
SHOW_RECIPES,
} from '@/app/config';
import { sortTagsByCount } from '@/tag';
import { sortCategoriesByCount } from '@/category';
export const getDataForCategories = () => [
getUniqueCameras()
.then(sortCategoriesByCount)
.catch(() => []),
SHOW_LENSES
? getUniqueLenses()
.then(sortCategoriesByCount)
.catch(() => [])
: [],
getUniqueTags()
.then(sortTagsByCount)
.catch(() => []),
SHOW_RECIPES
? getUniqueRecipes()
.then(sortCategoriesByCount)
.catch(() => [])
: [],
SHOW_FILM_SIMULATIONS
? getUniqueFilmSimulations()
.then(sortCategoriesByCount)
.catch(() => [])
: [],
SHOW_FOCAL_LENGTHS
? getUniqueFocalLengths()
.then(sortCategoriesByCount)
.catch(() => [])
: [],
] as const;

View File

@ -71,3 +71,7 @@ export const sortCategoryByCount = (
a: { count: number },
b: { count: number },
) => b.count - a.count;
export const sortCategoriesByCount = <T extends { count: number }>(
categories: T[],
) => categories.sort(sortCategoryByCount);

View File

@ -24,7 +24,7 @@ import IconFilmSimulation from '@/components/icons/IconFilmSimulation';
import IconLens from '@/components/icons/IconLens';
import PhotoLens from '@/lens/PhotoLens';
import IconFocalLength from '@/components/icons/IconFocalLength';
import { PhotoSetCategories, sortCategoryByCount } from '@/category';
import { PhotoSetCategories } from '@/category';
import PhotoFocalLength from '@/focal/PhotoFocalLength';
export default function PhotoGridSidebar({
@ -57,7 +57,6 @@ export default function PhotoGridSidebar({
className="translate-x-[0.5px]"
/>}
items={cameras
.sort(sortCategoryByCount)
.map(({ cameraKey, camera, count }) =>
<PhotoCamera
key={cameraKey}
@ -78,7 +77,6 @@ export default function PhotoGridSidebar({
title="Lenses"
icon={<IconLens size={15} />}
items={lenses
.sort(sortCategoryByCount)
.map(({ lensKey, lens, count }) =>
<PhotoLens
key={lensKey}
@ -145,7 +143,6 @@ export default function PhotoGridSidebar({
className="translate-x-[-1px]"
/>}
items={recipes
.sort(sortCategoryByCount)
.map(({ recipe, count }) =>
<PhotoRecipe
key={recipe}
@ -165,7 +162,6 @@ export default function PhotoGridSidebar({
title="Films"
icon={<IconFilmSimulation size={15} />}
items={simulations
.sort(sortCategoryByCount)
.map(({ simulation, count }) =>
<PhotoFilmSimulation
key={simulation}

View File

@ -21,7 +21,7 @@ import DownloadButton from '@/components/DownloadButton';
import PhotoCamera from '../camera/PhotoCamera';
import { cameraFromPhoto } from '@/camera';
import PhotoFilmSimulation from '@/simulation/PhotoFilmSimulation';
import { sortTags } from '@/tag';
import { sortTagsArray } from '@/tag';
import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid';
import PhotoLink from './PhotoLink';
import {
@ -124,7 +124,7 @@ export default function PhotoLarge({
refTriggers,
});
const tags = sortTags(photo.tags, primaryTag);
const tags = sortTagsArray(photo.tags, primaryTag);
const camera = cameraFromPhoto(photo);
const lens = lensFromPhoto(photo);

View File

@ -1,41 +0,0 @@
import {
getUniqueCamerasCached,
getUniqueFilmSimulationsCached,
getUniqueFocalLengthsCached,
getUniqueLensesCached,
getUniqueRecipesCached,
getUniqueTagsCached,
} from '@/photo/cache';
import {
getUniqueCameras,
getUniqueFilmSimulations,
getUniqueFocalLengths,
getUniqueLenses,
getUniqueRecipes,
getUniqueTags,
} from '@/photo/db/query';
import {
SHOW_FILM_SIMULATIONS,
SHOW_FOCAL_LENGTHS,
SHOW_LENSES,
SHOW_RECIPES,
} from '@/app/config';
import { sortTagsObject } from '@/tag';
export const getPhotoSidebarData = () => [
getUniqueCameras().catch(() => []),
SHOW_LENSES ? getUniqueLenses().catch(() => []) : [],
getUniqueTags().then(sortTagsObject).catch(() => []),
SHOW_FILM_SIMULATIONS ? getUniqueFilmSimulations().catch(() => []) : [],
SHOW_RECIPES ? getUniqueRecipes().catch(() => []) : [],
SHOW_FOCAL_LENGTHS ? getUniqueFocalLengths().catch(() => []) : [],
] as const;
export const getPhotoSidebarDataCached = () => [
getUniqueCamerasCached(),
SHOW_LENSES ? getUniqueLensesCached() : [],
getUniqueTagsCached().then(sortTagsObject),
SHOW_FILM_SIMULATIONS ? getUniqueFilmSimulationsCached() : [],
SHOW_RECIPES ? getUniqueRecipesCached() : [],
SHOW_FOCAL_LENGTHS ? getUniqueFocalLengthsCached() : [],
] as const;

View File

@ -143,11 +143,11 @@ export const getPhotoWithRecipeFromPhotos = (
? preferredPhoto
: photos.find(photoHasRecipe);
export const sortRecipesWithCount = (recipes: Recipes = []) =>
export const sortRecipes = (recipes: Recipes = []) =>
recipes.sort((a, b) => a.recipe.localeCompare(b.recipe));
export const convertRecipesForForm = (recipes: Recipes = []) =>
sortRecipesWithCount(recipes)
sortRecipes(recipes)
.map(({ recipe, count }) => ({
value: recipe,
annotation: formatCount(count),

View File

@ -22,6 +22,10 @@ export type FilmSimulationWithCount = {
export type FilmSimulations = FilmSimulationWithCount[]
export const sortFilmSimulations = (
simulations: FilmSimulations,
) => simulations.sort(sortFilmSimulationsWithCount);
export const sortFilmSimulationsWithCount = (
a: FilmSimulationWithCount,
b: FilmSimulationWithCount,

View File

@ -50,25 +50,33 @@ export const titleForTag = (
export const shareTextForTag = (tag: string) =>
isTagFavs(tag) ? 'Favorite photos' : `Photos tagged '${formatTag(tag)}'`;
export const sortTags = (
export const sortTagsArray = (
tags: string[],
tagToExclude?: string,
) => tags
.filter(tag => tag !== tagToExclude)
.sort((a, b) => isTagFavs(a) ? -1 : a.localeCompare(b));
export const sortTagsObject = (
export const sortTags = (
tags: Tags,
tagToHide?: string,
tagToExclude?: string,
) => tags
.filter(({ tag }) => tag!== tagToHide)
.filter(({ tag }) => tag!== tagToExclude)
.sort(({ tag: a }, { tag: b }) => isTagFavs(a) ? -1 : a.localeCompare(b));
export const sortTagsByCount = (
tags: Tags,
tagToExclude?: string,
) => tags
.filter(({ tag }) => tag !== tagToExclude)
.sort(({ tag: tagA, count: a }, { count: b }) =>
isTagFavs(tagA) ? -1 : b - a);
export const sortTagsWithoutFavs = (tags: string[]) =>
sortTags(tags, TAG_FAVS);
sortTagsArray(tags, TAG_FAVS);
export const sortTagsObjectWithoutFavs = (tags: Tags) =>
sortTagsObject(tags, TAG_FAVS);
sortTags(tags, TAG_FAVS);
export const descriptionForTaggedPhotos = (
photos: Photo[] = [],