Skip to content

Commit

Permalink
📑 Downloads combined with project (#355)
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanc1 authored Apr 5, 2024
1 parent 6f97346 commit 1e769a0
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 86 deletions.
6 changes: 6 additions & 0 deletions .changeset/grumpy-crews-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@myst-theme/frontmatter': patch
'@myst-theme/site': patch
---

Improve the downloads
32 changes: 12 additions & 20 deletions packages/frontmatter/src/downloads.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export async function triggerBlobDownload(blob: Blob, filename: string) {
return true;
}

const ICON_CLASS = 'self-center flex-none inline-block mr-3';

export function Download({
url,
filename,
Expand All @@ -79,30 +81,25 @@ export function Download({
}) {
if (!filename) {
const icon = internal ? (
<DocumentIcon
width="1.25rem"
height="1.25rem"
className="items-center inline-block mr-2"
aria-hidden="true"
/>
<DocumentIcon width="1.25rem" height="1.25rem" className={ICON_CLASS} aria-hidden="true" />
) : (
<ArrowTopRightOnSquareIcon
width="1.25rem"
height="1.25rem"
className="items-center inline-block mr-2"
className={ICON_CLASS}
aria-hidden="true"
/>
);
return (
<a
className={classNames(className, 'flex')}
className={classNames(className, 'flex no-underline')}
href={url}
target={!internal ? '_blank' : undefined}
rel={!internal ? 'noreferrer noopener' : undefined}
>
<span className="sr-only">Visit URL {title ?? ''}</span>
{icon}
{title ?? url}
<span className="w-max max-w-[200px] self-center">{title ?? url}</span>
</a>
);
}
Expand All @@ -114,17 +111,17 @@ export function Download({
[url, filename],
);
return (
<a className={classNames(className, 'flex')} href={url} onClick={clickDownload}>
<a className={classNames(className, 'flex no-underline')} href={url} onClick={clickDownload}>
<span className="sr-only">
Download{format ? ` as ${format}` : ''} {title ?? ''}
</span>
<DocumentArrowDownIcon
width="1.25rem"
height="1.25rem"
className="items-center inline-block mr-2"
className={ICON_CLASS}
aria-hidden="true"
/>
{title ?? filename}
<span className="w-max max-w-[200px] self-center">{title ?? filename}</span>
</a>
);
}
Expand All @@ -133,16 +130,11 @@ export function DownloadsDropdown({ exports }: HasExports) {
if (!exports || exports.length === 0) return null;
return (
<Menu as="div" className="relative flex inline-block mx-1 grow-0">
<Menu.Button className="relative">
<Menu.Button className="relative ml-2 -mr-1">
<span className="sr-only">Downloads</span>
<ArrowDownTrayIcon
width="1.25rem"
height="1.25rem"
className="ml-2 -mr-1"
aria-hidden="true"
/>
<ArrowDownTrayIcon width="1.25rem" height="1.25rem" aria-hidden="true" />
</Menu.Button>
<Menu.Items className="absolute overflow-hidden bg-white rounded-sm shadow-lg -right-1 dark:bg-slate-800 ring-1 ring-black ring-opacity-5 focus:outline-none">
<Menu.Items className="absolute z-10 overflow-hidden bg-white rounded-sm shadow-lg -right-1 dark:bg-slate-800 ring-1 ring-black ring-opacity-5 focus:outline-none">
{exports.map((exp, index) => (
<Menu.Item key={index}>
<Download
Expand Down
25 changes: 22 additions & 3 deletions packages/site/src/pages/Article.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { ReferencesProvider } from '@myst-theme/providers';
import { ReferencesProvider, useProjectManifest } from '@myst-theme/providers';
import {
Bibliography,
ContentBlocks,
Expand All @@ -22,6 +22,24 @@ import {
} from '@myst-theme/jupyter';
import { FrontmatterBlock } from '@myst-theme/frontmatter';
import { extractKnownParts } from '../utils.js';
import type { SiteAction } from 'myst-config';

/**
* Combines the project downloads and the export options
*/
function combineDownloads(
siteDownloads: SiteAction[] | undefined,
pageFrontmatter: PageLoader['frontmatter'],
) {
if (pageFrontmatter.downloads) {
return pageFrontmatter.downloads;
}
// No downloads on the page, combine the exports if they exist
if (siteDownloads) {
return [...(pageFrontmatter.exports ?? []), ...siteDownloads];
}
return pageFrontmatter.exports;
}

export const ArticlePage = React.memo(function ({
article,
Expand All @@ -32,10 +50,11 @@ export const ArticlePage = React.memo(function ({
hide_all_footer_links?: boolean;
hideKeywords?: boolean;
}) {
const manifest = useProjectManifest();
const compute = useComputeOptions();

const { hide_title_block, hide_footer_links } = (article.frontmatter as any)?.options ?? {};

const downloads = combineDownloads(manifest?.downloads, article.frontmatter);
const tree = copyNode(article.mdast);
const keywords = article.frontmatter?.keywords ?? [];
const parts = extractKnownParts(tree);
Expand All @@ -50,7 +69,7 @@ export const ArticlePage = React.memo(function ({
{!hide_title_block && (
<FrontmatterBlock
kind={article.kind}
frontmatter={article.frontmatter}
frontmatter={{ ...article.frontmatter, downloads }}
className="pt-5 mb-8"
/>
)}
Expand Down
4 changes: 2 additions & 2 deletions themes/article/app/components/ArticlePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function ArticlePage({ article }: { article: PageLoader }) {
<ArrowLeftIcon
width="1rem"
height="1rem"
className="self-center transition-transform group-hover:-translate-x-1 shrink-0"
className="self-center flex-none transition-transform group-hover:-translate-x-1"
/>
<span>Back to Article</span>
</Link>
Expand All @@ -84,7 +84,7 @@ export function ArticlePage({ article }: { article: PageLoader }) {
<DocumentArrowDownIcon
width="1rem"
height="1rem"
className="self-center transition-transform group-hover:-translate-x-1 shrink-0"
className="self-center flex-none transition-transform group-hover:-translate-x-1"
/>
<span>Download {article.kind}</span>
</a>
Expand Down
69 changes: 8 additions & 61 deletions themes/article/app/components/Downloads.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
import {
DocumentArrowDownIcon,
ArrowTopRightOnSquareIcon,
DocumentIcon,
} from '@heroicons/react/24/outline';
import { useSiteManifest } from '@myst-theme/providers';
import { triggerDirectDownload } from '@myst-theme/frontmatter';
import { Link } from '@remix-run/react';
import { SiteAction as DownloadsItem } from 'myst-config';
import { useCallback, useState } from 'react';
import { Download } from '@myst-theme/frontmatter';

function formatToTitle(format?: string) {
if (!format) return 'File';
Expand All @@ -28,65 +20,20 @@ export function DownloadLinksArea() {
const site = useSiteManifest();
const project = site?.projects?.[0];
const downloads = project?.downloads ?? project?.exports ?? [];

const [downloading, setDownloading] = useState<Record<string, boolean>>({});

const handleDownload = useCallback(
async (e: React.MouseEvent<HTMLAnchorElement>, item: DownloadsItem & { filename: string }) => {
e.preventDefault();
e.stopPropagation();

if (downloading[item.url]) return;
setDownloading({ ...downloading, [item.url]: true });

await triggerDirectDownload(item.url, item.filename);

setDownloading({ ...downloading, [item.url]: false });
},
[downloading],
);

if (downloads.length === 0) return null;

return (
<div className="col-margin mt-3 mx-5 lg:m-0 lg:w-[300px]">
<div className="flex flex-wrap gap-2 lg:flex-col w-fit lg:mx-auto">
{downloads.map((item) => {
if ((item as DownloadsItem).internal && !item.filename) {
return (
<Link key={item.url} to={item.url} className="no-underline">
<DocumentIcon width="1.5rem" height="1.5rem" className="inline h-5 pr-2" />
<span className="align-middle">{(item as DownloadsItem).title}</span>
</Link>
);
}

const externalLinkNotDownload = !item.filename;
const icon = externalLinkNotDownload ? (
<ArrowTopRightOnSquareIcon width="1.5rem" height="1.5rem" className="inline h-5 pr-2" />
) : (
<DocumentArrowDownIcon width="1.5rem" height="1.5rem" className="inline h-5 pr-2" />
);

return (
<a
key={item.url}
href={item.url}
className="inline-block mr-2 no-underline lg:mr-0 lg:block"
download={item.filename ? item.filename : undefined}
target={externalLinkNotDownload ? '_blank' : undefined}
rel={externalLinkNotDownload ? 'noreferrer noopener' : undefined}
onClick={
item.filename
? (e) => handleDownload(e, item as DownloadsItem & { filename: string })
: undefined
}
>
{icon}
<span className="align-middle">
{(item as DownloadsItem).title ?? `Download ${formatToTitle(item.format)}`}
</span>
</a>
<Download
url={item.url}
format={item.format}
filename={item.filename}
title={(item as any).title ?? formatToTitle(item.format)}
internal={(item as any).internal}
/>
);
})}
</div>
Expand Down

0 comments on commit 1e769a0

Please sign in to comment.