Changes
8 changed files (+172/-0)
-
-
@@ -34,6 +34,7 @@ .renderedImages=${args.renderedImages || {}}.panSpeed=${args.panSpeed || 500} .zoomSpeed=${args.zoomSpeed || 500} zoom-margin=${args.zoomMargin || 50} link=${args.link || "https://figma.com"} ></figspec-file-viewer> `;
-
-
-
@@ -166,6 +166,14 @@ <div class="view">${super.render()}</div>`; } getMetadata() { return { fileName: this.documentNode!.name, timestamp: this.documentNode!.lastModified, link: this.link, }; } connectedCallback() { super.connectedCallback();
-
-
-
@@ -26,6 +26,7 @@ font-family: sans-serif;" .nodes=${args.nodes} rendered-image=${args.renderedImage || ""} link=${args.link || "https://figma.com"} .panSpeed=${args.panSpeed || 500} .zoomSpeed=${args.zoomSpeed || 500} zoom-margin=${args.zoomMargin || 50}
-
-
-
@@ -126,6 +126,14 @@ return super.error;} } getMetadata() { return { fileName: this.nodes!.name, timestamp: this.nodes!.lastModified, link: this.link, }; } connectedCallback() { super.connectedCallback();
-
-
-
@@ -0,0 +1,69 @@import { css, html } from "lit-element"; import { FigmaIcon } from "../Icons"; import { fromNow } from "./utils"; export const styles = css` .figma-footer { flex: 0; min-height: 48px; padding: 0 16px; text-decoration: none; display: flex; flex-direction: row; justify-content: start; align-items: center; background-color: #fff; overflow-x: auto; cursor: pointer; font-size: 12px; color: rgba(0, 0, 0, 0.8); } .figma-footer--icon { margin-right: 12px; } .figma-footer--title { font-weight: 600; margin-right: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .figma-footer--timestamp { white-space: nowrap; overflow: hidden; } `; export const Footer = (metadata?: { link: string; timestamp: Date | string; fileName: string; }) => { if (!metadata) { return null; } const { link, timestamp, fileName } = metadata; return html`<a class="figma-footer" target="_blank" rel="noopener" title="Open in Figma" href="${link}" > <span class="figma-footer--icon"> ${FigmaIcon()} </span> <span class="figma-footer--title"> ${fileName} </span> <span title="Last time edited: ${new Date(timestamp).toUTCString()}" class="figma-footer--timestamp" > Edited ${fromNow(timestamp)} </span> </a>`; };
-
-
-
@@ -0,0 +1,52 @@const SECOND = 1000; const MINUTE = 60 * SECOND; const HOUR = 60 * MINUTE; const DAY = 24 * HOUR; const WEEK = 7 * DAY; const MONTH = 30 * DAY; const YEAR = 365 * DAY; const intervals = [ { gte: YEAR, divisor: YEAR, unit: "year" }, { gte: MONTH, divisor: MONTH, unit: "month" }, { gte: WEEK, divisor: WEEK, unit: "week" }, { gte: DAY, divisor: DAY, unit: "day" }, { gte: HOUR, divisor: HOUR, unit: "hour" }, { gte: MINUTE, divisor: MINUTE, unit: "minute" }, { gte: 30 * SECOND, divisor: SECOND, unit: "seconds" }, { gte: 0, divisor: 1, text: "just now" }, ]; const getTime = (targetDate: Date | number | string) => { const date = typeof targetDate === "object" ? (targetDate as Date) : new Date(targetDate); return date.getTime(); }; /** * Receives two dates to compare and returns "time ago" based on them * example: 4 weeks ago * * Heavily inspired by https://stackoverflow.com/a/67338038/938822 */ export const fromNow = ( date: Date | number | string, nowDate: Date | number | string = Date.now(), rft = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" }) ) => { const now = getTime(nowDate); const diff = now - getTime(date); const diffAbs = Math.abs(diff); for (const interval of intervals) { if (diffAbs >= interval.gte) { const x = Math.round(Math.abs(diff) / interval.divisor); const isInFuture = diff < 0; const intervalUnit = interval.unit as Intl.RelativeTimeFormatUnit; return intervalUnit ? rft.format(isInFuture ? x : -x, intervalUnit) : interval.text; } } };
-
-
-
@@ -27,3 +27,15 @@ <path d="M1 1L28 0.999999" stroke="#B3B3B3" stroke-width="2"/><path d="M0 27L28 27" stroke="#B3B3B3" stroke-width="2"/> </svg> `; export const FigmaIcon = () => svg` <svg title="figma logo" width="11" height="16" viewBox="0 0 12 17" xmlns="http://www.w3.org/2000/svg"> <path d="M5.5 1.5h-2c-1.105 0-2 .895-2 2 0 1.105.895 2 2 2h2v-4zm-5 2c0 1.043.533 1.963 1.341 2.5C1.033 6.537.5 7.457.5 8.5c0 1.043.533 1.963 1.341 2.5C1.033 11.537.5 12.457.5 13.5c0 1.657 1.343 3 3 3 1.657 0 3-1.343 3-3V10.736c.53.475 1.232.764 2 .764 1.657 0 3-1.343 3-3 0-1.043-.533-1.963-1.341-2.5.808-.537 1.341-1.457 1.341-2.5 0-1.657-1.343-3-3-3h-5c-1.657 0-3 1.343-3 3zm1 5c0-1.105.895-2 2-2h2v4h-2c-1.105 0-2-.895-2-2zm0 5c0-1.105.895-2 2-2h2v2c0 1.105-.895 2-2 2-1.105 0-2-.895-2-2zm7-3c-1.105 0-2-.895-2-2 0-1.105.895-2 2-2 1.105 0 2 .895 2 2 0 1.105-.895 2-2 2zm0-5h-2v-4h2c1.105 0 2 .895 2 2 0 1.105-.895 2-2 2z" fill-rule="evenodd" fill-opacity="1" fill="#000" stroke="none" ></path> </svg> `;
-
-
-
@@ -19,6 +19,7 @@ import * as InspectorView from "./InspectorView/InspectorView";import type { FigmaNode } from "./InspectorView/utils"; import * as ErrorMessage from "./ErrorMessage"; import * as Node from "./Node"; import * as FigmaFooter from "./Footer/Footer"; interface Margin { top: number;
-
@@ -29,6 +30,7 @@ }export interface IViewer { zoomMargin: number; link: string; /** * A record of rendered images.
-
@@ -42,6 +44,9 @@__updateTree(node: Figma.Node): void; __updateEffectMargins(): void; resetZoom(): void; getMetadata(): | { fileName: string; timestamp: Date | string; link: string } | undefined; } export const ViewerMixin = <T extends Constructor<LitElement>>(
-
@@ -54,6 +59,12 @@ attribute: "zoom-margin",}) zoomMargin: number = 50; @property({ type: String, attribute: "link", }) link: string = ""; static get styles() { // @ts-ignore const styles = super.styles;
-
@@ -116,12 +127,15 @@ top: 0;left: 0; width: 100%; height: 100%; display: flex; flex-direction: column-reverse; } .canvas { position: absolute; top: 50%; left: 50%; flex: 1; } .rendered-image {
-
@@ -144,6 +158,7 @@ Node.styles,ErrorMessage.styles, DistanceGuide.styles, InspectorView.styles, FigmaFooter.styles, ]); }
-
@@ -313,8 +328,14 @@ ${InspectorView.View({node: this.selectedNode as FigmaNode, onClose: this.deselectNode, })} ${FigmaFooter.Footer(this.getMetadata())} </div> `; } // implemented in FileViewer/FrameViewer getMetadata() { return undefined; } connectedCallback() {
-