Commit 9a96cc51 authored by Wohlgemuth, Jason's avatar Wohlgemuth, Jason
Browse files

feat: Refine Labels code; nowrap label text

parent d781a371
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ const { items } = Astro.props;
        font-size: 0.9rem;
        margin: 0 2px;
        padding: 1px 5px 0px 5px;
        white-space: nowrap;
        &:hover {
            color: red;
        }
+62 −67
Original line number Diff line number Diff line
import { ChartNoAxesCombined, SquareX } from 'lucide-react';
import { alphabetically, negate, removeItem } from '@/lib/utils';
import { useEffect, useState } from 'react';
import { type CSSProperties } from 'react';
import Fuse from 'fuse.js';
//
// Utility functions
//
const alphabetically = (a, b) => a.localeCompare(b);
const formatScoreText = value => value ? `Relevancy = ${(1.0 - value).toFixed(4)}` : '';
const getParameters = key => {
    const search = window.location.search;
    const params = new URLSearchParams(search);
    return params?.getAll(key) || [];
};
const negate = fn => {
    const inner = (...args) => !fn.apply(this, args);
    return inner;
};
const removeItem = (arr, value) => {
    const index = arr.indexOf(value);
    if (index > -1) {
        arr.splice(index, 1);
    }
    return arr;
};
const search = items => {
    const searchParameters = getParameters('search');
    const options = {
        includeScore: true,
        isCaseSensitive: true,
        useExtendedSearch: false,
        keys: [

const SEARCH_KEYS = [
    'meta.identifier',
    'meta.media.caption',
    'meta.technology',
@@ -45,11 +21,16 @@ const search = items => {
    'contact.email',
    'contact.organization',
    'contact.affiliation',
        ],
];
const getParameters = key => {
    const search = window.location.search;
    const params = new URLSearchParams(search);
    return params?.getAll(key) || [];
};
    const fuse = new Fuse(items, options);
    const results = fuse.search(searchParameters.join(' '));
    return results;
const hasSelectedKeywords = item => {
    const keywords = item.meta?.keywords;
    const isSelectedKeyword = value => keywords.map(x => x.toLowerCase()).includes(value.toLowerCase());
    return getParameters('q').every(isSelectedKeyword);
};
const updateLocation = (value, key) => {
    return () => {
@@ -64,7 +45,7 @@ const updateLocation = (value, key) => {
        window.location.href = location;
    };
};
const Details = ({ items }) => {
const Details = ({ items = [] }) => {
    const count = items.length;
    const [visibleItems, setVisibleItems] = useState(count);
    useEffect(() => {
@@ -77,17 +58,23 @@ const Details = ({ items }) => {
        </div>
    );
};
const Labels = () => {
const Labels = ({ item = { meta: { identifier: '', keywords: [] } } }) => {
    const isItemLabel = Boolean(item?.meta?.identifier.length > 0);
    const queryParameters = getParameters('q');
    const searchParameters = getParameters('search');
    const labels = [...searchParameters, ...queryParameters];
    const margin = isItemLabel ? '20px 0px' : '10px 10px 10px 20px';
    const style : CSSProperties = { margin, display: 'flex', flexDirection: 'row' };
    const onClick = keyword => updateLocation(keyword, searchParameters.length > 0 ? 'search' : 'q');
    const isSelectedKeyword = value => queryParameters.map(x => x.toLowerCase()).includes(value.toLowerCase());
    const labels = isItemLabel
        ? item?.meta?.keywords.filter(negate(isSelectedKeyword)).sort(alphabetically)
        : [...searchParameters, ...queryParameters];
    return (
        <div className="label-container" style={{ display: 'flex', flexDirection: 'row', margin: '20px 0px' }}>
        <div className="label-container" style={style}>
            {
                labels.map(keyword => (
                    <div className="label" onClick={updateLocation(keyword, searchParameters.length > 0 ? 'search' : 'q')}>
                        <SquareX style={{ display: 'inline-block', marginTop: '-2px' }} />
                        {' '}
                    <div className="label" onClick={onClick(keyword)}>
                        {isItemLabel ? '' : <X />}
                        {keyword}
                    </div>
                ))
@@ -95,15 +82,28 @@ const Labels = () => {
        </div>
    );
};
const X = () => {
    const style = {
        display: 'inline-block',
        marginTop: '-2px',
        marginRight: '4px',
    };
    return <SquareX style={style} />;
};
export default ({ items }) => {
    const queryParameters = getParameters('q');
    const search = items => {
        const searchParameters = getParameters('search');
    const isSelectedKeyword = value => queryParameters.map(x => x.toLowerCase()).includes(value.toLowerCase());
    const hasSelectedKeywords = item => {
        const keywords = item.meta?.keywords;
        const isSelectedKeyword = value => keywords.map(x => x.toLowerCase()).includes(value.toLowerCase());
        return getParameters('q').every(isSelectedKeyword);
        const options = {
            includeScore: true,
            isCaseSensitive: true,
            useExtendedSearch: false,
            keys: SEARCH_KEYS,
        };
        const fuse = new Fuse(items, options);
        const results = fuse.search(searchParameters.join(' '));
        return results;
    };
    const formatScoreText = value => value ? `Relevancy = ${(1.0 - value).toFixed(4)}` : '';
    const html = item => {
        return (
            <div className="item-container">
@@ -113,13 +113,7 @@ export default ({ items }) => {
                    </h4>
                    {item?.score && <span className="search-score">{formatScoreText(item?.score)}</span>}
                </div>
                <div className="label-container" style={{ display: 'flex', flexDirection: 'row', margin: '10px 10px 10px 20px' }}>
                    {
                        item.meta?.keywords.filter(negate(isSelectedKeyword)).sort(alphabetically).map(keyword => (
                            <div className="label" onClick={updateLocation(keyword, 'q')}>{keyword}</div>
                        ))
                    }
                </div>
                <Labels item={item} />
                <p>{ item?.sections?.mission }</p>
            </div>
        );
@@ -130,9 +124,10 @@ export default ({ items }) => {
            <Labels />
            <div style={{ height: '10px' }}></div>
            {
                searchParameters.length > 0
                getParameters('search').length > 0
                    // @ts-expect-error Only objects can use spread
                    ? search(items).map(({ item, score }) => ({ ...item, score })).map(html)
                    : queryParameters.length > 0
                    : getParameters('q').length > 0
                        ? items.filter(hasSelectedKeywords).map(html)
                        : items.map(html)
            }
+39 −0
Original line number Diff line number Diff line
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';

/**
 * Compares two strings and returns a negative, zero, or positive value
 * indicating the result of the comparison. This is the same as the
 * `String.prototype.localeCompare()` method.
 *
 * @param {string} a The first string
 * @param {string} b The second string
 * @returns {number} A negative, zero, or positive value indicating the result
 * of the comparison.
 */
export function alphabetically(a, b) {
    return a.localeCompare(b);
}
// Used by shadcn/ui components
export function cn(...inputs : ClassValue[]) {
    return twMerge(clsx(inputs));
}
/**
 * Returns a new function that negates the result of the given function.
 * 
 * @param {Function} fn - The function whose result is to be negated.
 * @returns {Function} A new function that returns the negated result of `fn`.
 */

export function negate(fn) {
    const inner = (...args) => !fn.apply(this, args);
    return inner;
};
/**
 * Removes the given value from the given array in-place
 * 
 * @param {any[]} arr The array to modify
 * @param {any} value The value to remove
 * @returns The modified array
 */
export function removeItem(arr, value) {
    const index = arr.indexOf(value);
    if (index > -1) {
        arr.splice(index, 1);
    }
    return arr;
};
+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ const items = [...projects];
<Layout title="Research Activity Index">
    <Header
        title="Research Activity Index"
        subtitle="A catalog of research projects and organizations at ORNL"
        subtitle="A catalog of research at ORNL"
    />
    <main>
        <article>