Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions nx2/blocks/browse/browse-api.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { daFetch, DA_ORIGIN } from '../../utils/daFetch.js';

/**
* Folder listing for the given fullpath.
* @param {string} fullpath
* @returns {Promise<
* | { items: unknown[]; permissions?: unknown }
* | { error: string; status: number }
* >}
* @returns {Promise<unknown[] | { error: string; status: number }>}
*/
export async function listFolder(fullpath) {
let response;
Expand All @@ -20,8 +18,10 @@ export async function listFolder(fullpath) {
}
try {
const payload = await response.json();
const items = Array.isArray(payload) ? payload : payload?.items ?? [];
return { items, permissions: response.permissions };
if (!Array.isArray(payload)) {
return { error: 'Invalid list response', status: response.status };
}
return payload;
} catch {
return { error: 'Invalid response body', status: response.status };
}
Expand Down
28 changes: 25 additions & 3 deletions nx2/blocks/browse/browse.css
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
:host {
display: block;
--browse-sheet-max-width: 1024px;

/* Fill the .browse wrapper; max-height none drops a fixed sheet cap */
display: flex;
flex-direction: column;
box-sizing: border-box;
min-height: 12rem;
flex: 1 1 auto;
height: 100%;
min-height: 0;
max-height: none;
min-width: 0;
padding: var(--s2-spacing-200) var(--s2-spacing-300);
overflow: hidden;
font-family: var(--s2-font-family);
font-size: var(--s2-body-size-s);
line-height: var(--s2-body-line-height);
color: var(--s2-gray-800);
background-color: var(--s2-gray-25);
overscroll-behavior: contain;

nx-browse-list {
display: flex;
flex-direction: column;
flex: 1 1 auto;
flex-grow: 1;
min-height: 0;
min-width: 0;
}

.browse-hint {
padding: var(--s2-spacing-200);
border-radius: var(--s2-corner-radius-300);
Expand Down Expand Up @@ -42,7 +60,11 @@
}

.browse-header {
margin: 0 0 var(--s2-spacing-300);
flex-shrink: 0;
box-sizing: border-box;
width: 100%;
max-width: var(--browse-sheet-max-width);
margin: 0 auto var(--s2-spacing-300);
}

.browse-title-bar {
Expand Down
45 changes: 35 additions & 10 deletions nx2/blocks/browse/browse.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { LitElement, html, nothing } from 'da-lit';
import { loadStyle, hashChange } from '../../utils/utils.js';
import { listFolder } from './browse-api.js';
import { contextToPathContext } from './utils.js';
import {
contextToPathContext,
entryTypeFromExtension,
isFolder,
RESOURCE_TYPE,
} from './utils.js';
import '../shared/breadcrumb/breadcrumb.js';
import './list/list.js';

const styles = await loadStyle(import.meta.url);

const documentLayoutStyles = await loadStyle(
new URL('overrides.css', import.meta.url).href,
);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, documentLayoutStyles];

class NxBrowse extends LitElement {
static properties = {
_items: { state: true },
Expand All @@ -25,7 +35,6 @@ class NxBrowse extends LitElement {
connectedCallback() {
super.connectedCallback();
this.shadowRoot.adoptedStyleSheets = [styles];
document.body.style.overflow = 'hidden';
this._unsubscribeHash = hashChange.subscribe((hashState) => {
if (!this._explicitContext) {
this._context = hashState;
Expand All @@ -39,7 +48,6 @@ class NxBrowse extends LitElement {

disconnectedCallback() {
this._unsubscribeHash?.();
document.body.style.overflow = '';
super.disconnectedCallback();
}

Expand All @@ -56,23 +64,40 @@ class NxBrowse extends LitElement {
return;
}

const result = await listFolder(ctx.fullpath);
const { fullpath } = ctx;

const result = await listFolder(fullpath);

if ('error' in result) {
this._items = undefined;
this._listError = result.error;
} else {
this._listError = undefined;
this._items = result.items;
this._items = result;
}
this.requestUpdate();
}

_onBrowseOpenFolder(event) {
const { pathKey } = event.detail;
if (!pathKey) {
_onBrowseActivate(event) {
const { pathKey, item } = event.detail || {};
if (entryTypeFromExtension(item.ext) === RESOURCE_TYPE.document) {
const url = new URL(window.location.href);
url.pathname = '/canvas';
url.hash = `#/${item.path.slice(1, -(item.ext.length + 1))}`;
Comment thread
kozmaadrian marked this conversation as resolved.
window.location.assign(url.href);
return;
}
window.location.hash = `#/${pathKey}`;
if (entryTypeFromExtension(item.ext) === RESOURCE_TYPE.sheet) {
const url = new URL(window.location.href);
url.pathname = '/sheet';
url.search = '';
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sheet is opened in the sheet editor using the default da-nx version.

url.hash = `#/${item.path.slice(1, -(item.ext.length + 1))}`;
window.open(url.href, '_blank', 'noopener,noreferrer');
return;
}
if (item && isFolder(item)) {
window.location.hash = `#/${pathKey}`;
}
}

render() {
Expand Down Expand Up @@ -121,7 +146,7 @@ class NxBrowse extends LitElement {
<nx-browse-list
.items=${this._items}
.currentPathKey=${currentPathKey}
@nx-browse-open-folder=${this._onBrowseOpenFolder}
@nx-browse-activate=${this._onBrowseActivate}
></nx-browse-list>
`;
}
Expand Down
66 changes: 66 additions & 0 deletions nx2/blocks/browse/list/format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const TIME_FORMAT_OPTIONS = { hour: 'numeric', minute: '2-digit' };

function parseTimestamp(timestampRaw) {
if (timestampRaw == null || timestampRaw === '') return null;
const parsedDate = new Date(timestampRaw);
return Number.isNaN(parsedDate.getTime()) ? null : parsedDate;
}

function formatAbsolute(dateInstant, referenceNow = new Date()) {
const timeSegment = dateInstant.toLocaleTimeString(undefined, TIME_FORMAT_OPTIONS);
if (dateInstant.getFullYear() === referenceNow.getFullYear()) {
const dateSegment = dateInstant.toLocaleDateString(undefined, {
month: 'short',
day: 'numeric',
});
return `${dateSegment}, ${timeSegment}`;
}
const dateSegment = dateInstant.toLocaleDateString(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
});
return `${dateSegment}, ${timeSegment}`;
}

function formatRelative(dateInstant, referenceNow = new Date()) {
const elapsedMilliseconds = referenceNow - dateInstant;
const relativeTimeFormatter = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' });
const eventCalendarDay = dateInstant.toDateString();
const referenceCalendarDay = referenceNow.toDateString();

let displayLabel;
if (eventCalendarDay === referenceCalendarDay) {
const elapsedSeconds = Math.floor(elapsedMilliseconds / 1000);
if (elapsedSeconds < 60) displayLabel = relativeTimeFormatter.format(0, 'second');
else {
const elapsedMinutes = Math.floor(elapsedSeconds / 60);
if (elapsedMinutes < 60) displayLabel = relativeTimeFormatter.format(-elapsedMinutes, 'minute');
else {
const elapsedHours = Math.floor(elapsedMinutes / 60);
displayLabel = relativeTimeFormatter.format(-elapsedHours, 'hour');
}
}
} else {
const referenceYesterday = new Date(referenceNow);
referenceYesterday.setDate(referenceYesterday.getDate() - 1);
if (eventCalendarDay === referenceYesterday.toDateString()) {
const relativeDayPhrase = relativeTimeFormatter.format(-1, 'day');
const timeSegment = dateInstant.toLocaleTimeString(undefined, TIME_FORMAT_OPTIONS);
displayLabel = `${relativeDayPhrase}, ${timeSegment}`;
} else {
displayLabel = formatAbsolute(dateInstant, referenceNow);
}
}

return displayLabel;
}

export function formatColumnLastModified(lastModified) {
const lastModifiedDate = parseTimestamp(lastModified);
if (!lastModifiedDate) return { label: null };
return {
label: formatRelative(lastModifiedDate),
title: `Last modified on ${formatAbsolute(lastModifiedDate)}`,
};
}
Loading
Loading