Skip to content

Commit

Permalink
Fix Searchbox overflowing when displaying long name #992
Browse files Browse the repository at this point in the history
  • Loading branch information
Polleps authored and joepio committed Oct 23, 2024
1 parent 2f695e5 commit 0b29a2a
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 53 deletions.
1 change: 1 addition & 0 deletions browser/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This changelog covers all five packages, as they are (for now) updated as a whol

- [#981](https://github.com/atomicdata-dev/atomic-server/issues/981) Fix bug where the service worker would not update cache with updated code.
- [#989](https://github.com/atomicdata-dev/atomic-server/issues/989) Added an edit button to the resource selector inputs.
- [#992](https://github.com/atomicdata-dev/atomic-server/issues/992) Fix Searchbox overflowing when displaying long names.

### @tomic/cli

Expand Down
5 changes: 4 additions & 1 deletion browser/data-browser/src/components/Collapse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ const GridCollapser = styled.div<GridCollapserProps>`
display: grid;
grid-template-rows: ${({ open }) => (open ? '1fr' : '0fr')};
grid-template-columns: 100%;
transition: grid-template-rows ${() => ANIMATION_DURATION()}ms ease-in-out;
transition:
grid-template-rows ${() => ANIMATION_DURATION()}ms ease-in-out,
// In some cases, a margin is added. This needs to animate as well.
margin-top ${() => ANIMATION_DURATION()}ms ease-in-out;
@media (prefers-reduced-motion) {
transition: unset;
Expand Down
27 changes: 15 additions & 12 deletions browser/data-browser/src/components/Containers.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import { styled } from 'styled-components';
import { css, styled } from 'styled-components';
import { LAYOUT_CONTAINER } from '../helpers/containers';

/** Centered column */
export const ContainerNarrow = styled.div`
width: min(100%, ${props => props.theme.containerWidth}rem);
const common = css`
margin: auto;
padding: ${props => props.theme.margin}rem;
// Extra space for the navbar below
padding: ${p => p.theme.size()};
container: ${LAYOUT_CONTAINER} / inline-size;
padding-bottom: 10rem;
`;

/** Centered column */
export const ContainerNarrow = styled.div`
width: min(100%, ${p => p.theme.containerWidth}rem);
${common}
`;

export const ContainerWide = styled.div`
width: min(100%, ${props => props.theme.containerWidthWide});
margin: auto;
padding: ${props => props.theme.margin}rem;
// Extra space for the navbar below
padding-bottom: 10rem;
width: min(100%, ${p => p.theme.containerWidthWide});
${common}
`;

/** Full-page wrapper */
export const ContainerFull = styled.div`
padding: ${props => props.theme.margin}rem;
container: ${LAYOUT_CONTAINER} / inline-size;
padding: ${p => p.theme.size()};
padding-bottom: 10rem;
`;
19 changes: 11 additions & 8 deletions browser/data-browser/src/components/Dialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { useDialog } from './useDialog';
import { useControlLock } from '../../hooks/useControlLock';
import { useDialogGlobalContext } from './DialogGlobalContextProvider';
import { DIALOG_CONTENT_CONTAINER } from '../../helpers/containers';

export interface InternalDialogProps {
show: boolean;
Expand Down Expand Up @@ -216,16 +217,19 @@ const DialogContentSlot = styled(Slot)`
overflow-y: visible;
/* The main section should leave room for the footer */
max-height: calc(80vh - 8rem);
padding-bottom: ${({ theme }) => theme.margin}rem;
padding-bottom: ${p => p.theme.size()};
// Position the scrollbar against the side of the dialog without any spacing inbetween.
// This also fixes ugly horizontal shadow cutoff.
margin-inline: -${p => p.theme.margin}rem;
padding-inline: ${p => p.theme.margin}rem;
margin-inline: -${p => p.theme.size()};
padding-inline: ${p => p.theme.size()};
container: ${DIALOG_CONTENT_CONTAINER} / inline-size;
scrollbar-gutter: stable;
`;

const DialogActionsSlot = styled(Slot)`
display: flex;
gap: ${p => p.theme.margin}rem;
gap: ${p => p.theme.size()};
align-items: center;
justify-content: flex-end;
border-top: 1px solid ${props => props.theme.colors.bg2};
Expand All @@ -238,7 +242,7 @@ const StyledInnerDialog = styled.div`
grid-template-rows: 1fr auto auto;
gap: 1rem;
grid-template-areas: 'title close' 'content content' 'actions actions';
max-block-size: calc(100vh - ${p => p.theme.margin}rem * 2);
max-block-size: calc(100vh - ${p => p.theme.size()} * 2);
`;

const fadeInForground = keyframes`
Expand All @@ -264,18 +268,17 @@ const fadeInBackground = keyframes`
`;

const StyledDialog = styled.dialog<{ $width?: CSS.Property.Width }>`
--animation-speed: 500ms;
--dialog-width: min(90vw, ${p => p.$width ?? '60ch'});
${VAR_DIALOG_INNER_WIDTH}: calc(
var(--dialog-width) - 2 * ${p => p.theme.margin}rem
var(--dialog-width) - 2 * ${p => p.theme.size()}
);
box-sizing: border-box;
inset: 0px;
position: relative;
z-index: ${p => p.theme.zIndex.dialog};
padding: ${props => props.theme.margin}rem;
padding: ${p => p.theme.size()};
color: ${props => props.theme.colors.text};
background-color: ${props => props.theme.colors.bg};
border-radius: ${props => props.theme.radius};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function SelectedFileLayout({
}: PropsWithChildren<SelectedFileLayoutProps>): React.JSX.Element {
return (
<Wrapper>
<Row>
<Row center>
<Title>{title}</Title>
{!disabled && (
<IconButton title='clear' onClick={onClear}>
Expand All @@ -35,7 +35,8 @@ export function SelectedFileLayout({
}

const Title = styled.span`
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
`;

const Wrapper = styled.div`
Expand Down
5 changes: 5 additions & 0 deletions browser/data-browser/src/components/forms/InputStyles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ export const FieldStyled = styled.div`
margin-bottom: ${props => props.theme.size()};
border: none;
background-color: none;
// Removes default 1px margin on fieldset.
&:is(fieldset) {
margin-inline: 0;
}
`;

export const LabelWrapper = styled.div`
Expand Down
7 changes: 1 addition & 6 deletions browser/data-browser/src/components/forms/ResourceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,6 @@ export function ResourceForm({
<Button
title={'show / hide advanced form fields'}
clean
style={{
display: 'flex',
marginBottom: '1rem',
alignItems: 'center',
}}
onClick={() => setShowAdvanced(!showAdvanced)}
>
<Row as='strong' gap='0.4rem' center>
Expand Down Expand Up @@ -309,5 +304,5 @@ export function ResourceForm({
}

const StyledCollapse = styled(Collapse)`
max-width: 70ch;
margin-top: ${p => (p.open ? '1rem' : '0')};
`;
13 changes: 11 additions & 2 deletions browser/data-browser/src/components/forms/SearchBox/SearchBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
useRef,
useState,
} from 'react';
import { styled } from 'styled-components';
import { css, styled } from 'styled-components';
import { removeCachedSearchResults, useResource, useStore } from '@tomic/react';
import { DropdownPortalContext } from '../../Dropdown/dropdownContext';
import * as RadixPopover from '@radix-ui/react-popover';
Expand Down Expand Up @@ -163,6 +163,7 @@ export function SearchBox({
<TriggerButtonWrapper
disabled={!!disabled}
className={className}
open={open}
invalid={!!visualError}
>
{prefix}
Expand Down Expand Up @@ -259,10 +260,14 @@ const TriggerButton = styled.button<{ $empty: boolean }>`
const TriggerButtonWrapper = styled.div<{
invalid: boolean;
disabled: boolean;
open: boolean;
}>`
${SB_HIGHLIGHT.define(p =>
p.invalid ? p.theme.colors.alert : p.theme.colors.main,
)}
max-width: 100cqw;
display: flex;
position: relative;
border: 1px solid ${props => props.theme.colors.bg2};
Expand All @@ -284,7 +289,11 @@ const TriggerButtonWrapper = styled.div<{
&:focus-visible {
border-color: transparent;
box-shadow: 0 0 0 2px ${SB_HIGHLIGHT.var()};
z-index: 1000;
${p =>
!p.open &&
css`
z-index: 1000;
`}
}
`;

Expand Down
2 changes: 2 additions & 0 deletions browser/data-browser/src/helpers/containers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const MAIN_CONTAINER = 'main';
export const ALL_PROPS_CONTAINER = 'all-props';
export const CARD_CONTAINER = 'card';
export const LAYOUT_CONTAINER = 'layout-container';
export const DIALOG_CONTENT_CONTAINER = 'dialog-content';
14 changes: 6 additions & 8 deletions browser/data-browser/src/hooks/useFile.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { properties, Resource, useNumber, useString } from '@tomic/react';
import { Resource, server, useNumber, useString } from '@tomic/react';
import { useCallback } from 'react';

export function useFileInfo(resource: Resource) {
const [downloadUrl] = useString(resource, properties.file.downloadUrl);
const [mimeType] = useString(resource, properties.file.mimetype);

const [bytes] = useNumber(resource, properties.file.filesize);
const [downloadUrl] = useString(resource, server.properties.downloadUrl);
const [mimeType] = useString(resource, server.properties.mimetype);
const [bytes] = useNumber(resource, server.properties.filesize);

const downloadFile = useCallback(() => {
window.open(downloadUrl);
}, [downloadUrl]);

if (
downloadUrl === undefined ||
mimeType === undefined ||
bytes === undefined
!resource.loading &&
(downloadUrl === undefined || mimeType === undefined || bytes === undefined)
) {
throw new Error('File resource is missing properties');
}
Expand Down
3 changes: 3 additions & 0 deletions browser/data-browser/src/styling.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ export const GlobalStyle = createGlobalStyle`
line-height: 1.5em;
word-wrap: break-word;
overflow-wrap: anywhere;
// Prevents weird scrollbars appearing for a split second when opening a dialog
overflow: hidden;
margin: 0;
/** Pretty dark mode transition */
transition: background-color .2s ease, border-color .2s ease, color .2s ease;
Expand Down
36 changes: 22 additions & 14 deletions browser/react/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
Resource,
Datatype,
datatypeFromUrl,
urls,
truncateUrl,
JSONValue,
valToBoolean,
Expand All @@ -28,6 +27,8 @@ import {
proxyResource,
type Core,
ResourceEvents,
core,
server,
} from '@tomic/lib';
import { useDebouncedCallback } from './index.js';

Expand Down Expand Up @@ -216,6 +217,7 @@ export function useValue(
commitDebounce = 100,
handleValidationError,
} = opts;

const [val, set] = useState<JSONValue>(resource.get(propertyURL));
const [prevResourceReference, setPrevResourceReference] = useState(resource);

Expand Down Expand Up @@ -267,24 +269,30 @@ export function useValue(
[resource, handleValidationError, store, validate, saveResource],
);

useEffect(() => {
return resource.on(ResourceEvents.LocalChange, (prop, value) => {
if (prop === propertyURL) {
set(value);
}
});
}, [resource, propertyURL]);

// Update value when resource changes.
if (resource !== prevResourceReference) {
let localVal: JSONValue | undefined;

try {
set(resource.get(propertyURL));
localVal = resource.get(propertyURL);
set(localVal);
} catch (e) {
store.notifyError(e);
}

setPrevResourceReference(resource);
}

useEffect(() => {
return resource.on(ResourceEvents.LocalChange, (prop, value) => {
if (prop === propertyURL) {
set(value);
}
});
}, [resource, propertyURL]);
// We changed the value but we don't want to wait a whole react cycle to return the new value so we return the value here directly.
return [localVal, validateAndSet];
}

return [val, validateAndSet];
}
Expand Down Expand Up @@ -351,15 +359,15 @@ export function useTitle(
truncateLength = 40,
opts: useValueOptions = titleHookOpts,
): [string, SetValue<string>] {
const [name, setName] = useString(resource, urls.properties.name, opts);
const [name, setName] = useString(resource, core.properties.name, opts);
const [shortname, setShortname] = useString(
resource,
urls.properties.shortname,
core.properties.shortname,
opts,
);
const [filename, setFileName] = useString(
resource,
urls.properties.file.filename,
server.properties.filename,
opts,
);

Expand All @@ -379,7 +387,7 @@ export function useTitle(
return [filename, setFileName];
}

const subject = resource?.getSubject();
const subject = resource?.subject;

if (typeof subject === 'string' && subject.length > 0) {
return [truncateUrl(subject, truncateLength), setName];
Expand Down

0 comments on commit 0b29a2a

Please sign in to comment.