Skip to content

Commit

Permalink
Merge pull request #225 from eecs485staff/pdf
Browse files Browse the repository at this point in the history
[PDF] Automatic PDF Generation
  • Loading branch information
seshrs authored Dec 23, 2022
2 parents e4785cb + f125b04 commit d890268
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 6 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/upload-develop-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ jobs:
with:
ruby-version: '3.0'
bundler-cache: true
cache-version: 0 # Increment this number if you need to re-download cached gems

- name: ⬢ Setup Node
uses: actions/setup-node@v1
with:
node-version: '16'
cache: 'npm'

- name: ⚙️ Install dependencies
run: |
Expand All @@ -47,6 +49,14 @@ jobs:
sed -i "\$ s/\$/ (develop preview build: $(date '+%Y-%m-%d') ($(git rev-parse HEAD)))/" VERSION
./script/ci-site-preview-build "https://preview.sesh.rs" "/previews/$REPO/develop-preview"
# Use `build-primer-spec-action` to generate PDFs of each page.
# Docs: https://github.com/seshrs/build-primer-spec-action
- name: 👷‍♀️ Build the rest of the Primer Spec site
uses: seshrs/build-primer-spec-action@main # TODO: Change this to v1 after releasing the new version of build-primer-spec-action
with:
build_jekyll_site: 'false'
configure_github_pages: 'false'

# Upload the site to Primer Spec Preview and comment on the PR.
# The Primer Spec Preview secret is stored as an encrypted repo or
# organization secret named `PRIMER_SPEC_PREVIEW_SECRET`.
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/upload-pr-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ jobs:
with:
ruby-version: '3.0'
bundler-cache: true
cache-version: 0 # Increment this number if you need to re-download cached gems

- name: ⬢ Setup Node
uses: actions/setup-node@v1
with:
node-version: '16'
cache: 'npm'

- name: ⚙️ Install dependencies
run: |
Expand All @@ -42,6 +44,14 @@ jobs:
sed -i "\$ s/\$/ (PR preview build: $(date '+%Y-%m-%d'))/" VERSION
./script/ci-site-preview-build "https://preview.sesh.rs" "/previews/$REPO/$PR_NUMBER"
# Use `build-primer-spec-action` to generate PDFs of each page.
# Docs: https://github.com/seshrs/build-primer-spec-action
- name: 👷‍♀️ Build the rest of the Primer Spec site
uses: seshrs/build-primer-spec-action@main # TODO: Change this to v1 after releasing the new version of build-primer-spec-action
with:
build_jekyll_site: 'false'
configure_github_pages: 'false'

# Upload the site to Primer Spec Preview and comment on the PR.
# The Primer Spec Preview secret is stored as an encrypted repo or
# organization secret named `PRIMER_SPEC_PREVIEW_SECRET`.
Expand Down
8 changes: 8 additions & 0 deletions _layouts/spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@
-->
<script>
window.PrimerSpecConfig = {
{%- comment -%}
!! STOP !!
The `pdfPath` flag is set by seshrs/build-primer-spec-action
after the PDF for this page has been built.
Do not change this code without also updating build-primer-spec-action.
{%- endcomment %}
pdfPath: null, // @managed by build-primer-spec-action
siteQualifiedBaseUrl: '{{ site.url }}{{ site.baseurl }}/',
hideSidebarOnLoad: {{ page.hideSidebarOnLoad | default: false }},
disableSidebar: {{ page.disableSidebar | default: false }},
defaultSubthemeName: '{{ site.primerSpec.defaultSubthemeName | default: "default" }}',
Expand Down
8 changes: 8 additions & 0 deletions _sass/spec/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,18 @@ $INFO_BORDER_COLOR: rgba(4, 66, 137, 0.2);
&-left {
position: absolute;
left: 1em;
.primer-spec-topbar-button {
display: inline;
padding-right: 2em;
}
}
&-right {
position: absolute;
right: 1em;
.primer-spec-topbar-button {
display: inline;
padding-left: 2em;
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions src_js/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export default {
BUILD_MODE: process.env.BUILD_MODE,

// From window.PrimerSpecConfig
PDF_PATH: window.PrimerSpecConfig.pdfPath || null,
SITE_QUALIFIED_BASE_URL: window.PrimerSpecConfig.siteQualifiedBaseUrl || '/',
HIDE_SIDEBAR_ON_LOAD: getHideSidebarOnLoad(),
DISABLE_SIDEBAR: window.PrimerSpecConfig.disableSidebar || false,
INIT_SUBTHEME_NAME,
Expand Down
30 changes: 26 additions & 4 deletions src_js/components/Topbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { h } from 'preact';
import { useLayoutEffect, useRef } from 'preact/hooks';
import clsx from 'clsx';
import IconType from './common/IconType';
import InlineButton from './common/InlineButton';
import InlineButton, { InlineLinkButton } from './common/InlineButton';
import Config from '../Config';

type PropsType = {
isSmallScreen: boolean;
Expand Down Expand Up @@ -35,7 +36,7 @@ export default function Topbar(props: PropsType): h.JSX.Element {
let sidebar_toggle = null;
if (props.showSidebarToggle) {
sidebar_toggle = props.sidebarShown ? null : (
<div class={`primer-spec-sidebar-toggle-fixed primer-spec-float-left`}>
<div class={`primer-spec-topbar-button primer-spec-float-left`}>
<InlineButton
icon={IconType.SIDEBAR}
onClick={props.onToggleSidebar}
Expand All @@ -45,10 +46,28 @@ export default function Topbar(props: PropsType): h.JSX.Element {
);
}

let downloadPdfButton = null;
if (
Config.PDF_PATH != null &&
(!props.isSmallScreen || (props.isSmallScreen && props.settingsShown))
) {
const href = Config.SITE_QUALIFIED_BASE_URL + Config.PDF_PATH;
downloadPdfButton = (
<div class="primer-spec-topbar-button">
<InlineLinkButton
icon={IconType.DOWNLOAD}
href={href}
download
ariaLabel="Download this page as a PDF file"
/>
</div>
);
}

let settings_toggle = null;
if (props.showSettingsToggle) {
settings_toggle = (
<div class="primer-spec-settings-toggle primer-spec-float-right">
<div class="primer-spec-topbar-button">
<InlineButton
icon={props.settingsShown ? IconType.CLOSE : IconType.SETTINGS}
onClick={props.onToggleSettings}
Expand Down Expand Up @@ -78,7 +97,10 @@ export default function Topbar(props: PropsType): h.JSX.Element {
)}
>
{sidebar_toggle}
{settings_toggle}
<div class="primer-spec-float-right">
{downloadPdfButton}
{settings_toggle}
</div>
</header>
);
}
1 change: 1 addition & 0 deletions src_js/components/common/IconType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ enum IconType {
SETTINGS = 'fas fa-cog',
SIDEBAR = 'fas fa-bars',
EXTERNAL_LINK = 'fas fa-external-link-alt',
DOWNLOAD = 'fas fa-file-download',
}
export default IconType;
36 changes: 34 additions & 2 deletions src_js/components/common/InlineButton.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { h } from 'preact';
import IconType from './IconType';
import { Hoverable } from './Hoverable';
import { openExternalLink } from './openExternalLink';

export type PropsType = {
export type InlineButtonPropsType = {
icon: IconType;
floatRight?: boolean;
onClick?: () => void;
ariaLabel?: string;
};

export default function InlineButton(props: PropsType): h.JSX.Element {
export default function InlineButton(
props: InlineButtonPropsType,
): h.JSX.Element {
return (
<Hoverable floatRight={props.floatRight}>
<button
Expand All @@ -29,3 +32,32 @@ export default function InlineButton(props: PropsType): h.JSX.Element {
</Hoverable>
);
}

export type InlineLinkButtonPropsType = {
icon: IconType;
floatRight?: boolean;
href: string;
download?: string | boolean;
ariaLabel?: string;
};

export function InlineLinkButton(
props: InlineLinkButtonPropsType,
): h.JSX.Element {
return (
<Hoverable floatRight={props.floatRight}>
<a
class="btn-link primer-spec-hoverable no-print tooltipped tooltipped-no-delay tooltipped-w"
role="button"
href={props.href}
onClick={(event) => {
event.preventDefault();
openExternalLink({ url: props.href, download: props.download });
}}
aria-label={props.ariaLabel}
>
<i class={props.icon} />
</a>
</Hoverable>
);
}
35 changes: 35 additions & 0 deletions src_js/components/common/openExternalLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export function openExternalLink(props: {
url: string;
download?: string | boolean;
}): void {
const { url, download } = props;

try {
sanityCheckUrl(url);
} catch (e) {
console.error('Blocking attempt to open external link. Error:', e);
return;
}

const anchor = document.createElement('a');
anchor.href = url;
if (download != null && download !== false) {
// Use the original filename by not specifying one here.
anchor.download = typeof download === 'boolean' ? '' : download;
}
anchor.style.display = 'none';
document.body.appendChild(anchor);
anchor.click();
setTimeout(
() => {
document.body.removeChild(anchor);
},
2000, // 2 seconds
);
}

function sanityCheckUrl(url: string): void {
if (!url.startsWith('https://') && !url.startsWith('/')) {
throw new Error(`Expected HTTPS external link, received: ${url}`);
}
}
2 changes: 2 additions & 0 deletions src_js/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Need to declare that the window object may have a PrimerSpecConfig.
// eslint-disable-next-line no-var
declare var PrimerSpecConfig: {
pdfPath?: string | null;
siteQualifiedBaseUrl?: string;
hideSidebarOnLoad?: boolean;
disableSidebar?: boolean;
defaultSubthemeName?: string;
Expand Down

0 comments on commit d890268

Please sign in to comment.