From c748f8c8971c0892f8afca467909294a327cbbf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Vassbotn=20R=C3=B8yne-Helgesen?= Date: Thu, 19 Oct 2023 22:19:07 +0200 Subject: [PATCH 1/7] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Add=20workflows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/FUNDING.yml | 3 ++ .github/ISSUE_TEMPLATE/bug_report.md | 38 ++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++ .github/dependabot.yml | 13 +++++ .github/labeler.yml | 28 ++++++++++ .github/workflows/auto-assign.yml | 19 +++++++ .github/workflows/check.yml | 64 +++++++++++++++++++++++ .github/workflows/label.yml | 15 ++++++ .github/workflows/publish.yml | 52 ++++++++++++++++++ 9 files changed, 252 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/dependabot.yml create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/auto-assign.yml create mode 100644 .github/workflows/check.yml create mode 100644 .github/workflows/label.yml create mode 100644 .github/workflows/publish.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..cec71c3 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: phun-ky diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..8a9aadc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'problems: bug' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..adfbd4e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: 'npm' # See documentation for possible values + directory: '/' # Location of package manifests + schedule: + interval: 'weekly' + commit-message: + prefix: 'chore: 🤖 ' diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..257e936 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,28 @@ +'section: workflows': + - .github/workflows/** +'section: repo': + - '*' +'experience: developer': + - 'dev' + - '.eslintignore' + - '.eslintrc.json' + - '.gitignore' + - '.npmrc' + - '.prettierrc' + - 'tslint.json' + - '.stylintrc' + - '.postcssrc.cjs' + - '.postcssrc.js' +'context: github': + - .github/** +'context: docker': + - Dockerfile +'context: npm': + - '.npmrc' +'context: rollup': + - 'rollup.config.js' + - 'rollup.*.config.js' +'mindless: docs': + - '**/*.md' +'mindless: dependencies': + - 'package-lock.json' diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml new file mode 100644 index 0000000..25b971f --- /dev/null +++ b/.github/workflows/auto-assign.yml @@ -0,0 +1,19 @@ +name: Auto Assign +on: + issues: + types: [opened] + pull_request: + types: [opened] +jobs: + run: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - name: 'Auto-assign issue' + uses: pozil/auto-assign-issue@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + assignees: phun-ky + numOfAssignee: 1 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..31faef7 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,64 @@ +# This is a basic workflow to help you get started with Actions + +name: Checks + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "main" branch + push: + branches: [ "main" ] + paths: + - 'src' + - 'package.json' + - 'package-lock.json' + - 'rollup.config.js' + - 'tsconfig.json' + - '.npmrc' + pull_request: + branches: [ "main" ] + types: [opened, synchronize] # Workflow triggering events + paths: + - 'src' + - 'package.json' + - 'package-lock.json' + - 'rollup.config.js' + - 'tsconfig.json' + - '.npmrc' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "check" + check: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Checkout all branches and tags + - name: Setup Node.js environment + uses: actions/setup-node@v2.5.2 + with: + node-version: 18 + - name: Install dependencies + run: | # Install and link dependencies + npm i + - name: Build # Build all packages + run: npm run build + notify: + name: Notify failed check + needs: check + if: failure() && github.event.pull_request == null + runs-on: ubuntu-latest + steps: + - uses: jayqi/failed-build-issue-action@v1 + with: + github-token: ${{ secrets.GH_TOKEN }} + + diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml new file mode 100644 index 0000000..f4ca32d --- /dev/null +++ b/.github/workflows/label.yml @@ -0,0 +1,15 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v4 + with: + sync-labels: true + dot: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..6a3dfb5 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,52 @@ +# This is a basic workflow to help you get started with Actions + +name: Publish + +# Controls when the workflow will run +on: + pull_request: + types: [closed] + branches: [ "main" ] + paths: + - 'src/**' + - 'api/**' + - 'public/**' + workflow_dispatch: +jobs: + publish: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Checkout all branches and tags + token: ${{ secrets.GH_TOKEN }} + - name: Setup Node.js environment + uses: actions/setup-node@v2.5.2 + with: + node-version: 18 + - name: Install dependencies + run: | # Install and link dependencies + npm i + - name: "Release" # Interesting step + run: | + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor}}@users.noreply.github.com" + npm run release + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ secrets.GH_TOKEN }} + notify: + name: Notify failed build + needs: publish + if: failure() && github.event.pull_request == null + runs-on: ubuntu-latest + steps: + - uses: jayqi/failed-build-issue-action@v1 + with: + github-token: ${{ secrets.GH_TOKEN }} + From 4830749edc282001b1735600e81dcd3467785c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Vassbotn=20R=C3=B8yne-Helgesen?= Date: Thu, 19 Oct 2023 22:19:28 +0200 Subject: [PATCH 2/7] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Add=20new=20logo=20?= =?UTF-8?q?for=20package=20use?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/logo-frameport-colored-package.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/logo-frameport-colored-package.svg b/public/logo-frameport-colored-package.svg index 94b17d4..3018eaa 100644 --- a/public/logo-frameport-colored-package.svg +++ b/public/logo-frameport-colored-package.svg @@ -1 +1 @@ - + From cad79bfb7e4b027b28cd7e36338c783b3fe49f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Vassbotn=20R=C3=B8yne-Helgesen?= Date: Thu, 19 Oct 2023 22:19:47 +0200 Subject: [PATCH 3/7] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20Documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 260 +++++++++++++++++------ api/README.md | 26 +++ api/interfaces/types.FrameportOptions.md | 209 ++++++++++++++++++ api/modules/config_browser.md | 113 ++++++++++ api/modules/config_generate.md | 26 +++ api/modules/config_generate_viewports.md | 26 +++ api/modules/features_dom.md | 26 +++ api/modules/main.md | 36 ++++ api/modules/types.md | 40 ++++ api/modules/utils_blob.md | 28 +++ api/modules/utils_code.md | 27 +++ api/modules/utils_constants.md | 38 ++++ api/modules/utils_create.md | 27 +++ api/modules/utils_css.md | 27 +++ api/modules/utils_element.md | 51 +++++ api/modules/utils_headers.md | 27 +++ api/modules/utils_iframe.md | 21 ++ api/modules/utils_js.md | 27 +++ api/modules/utils_page.md | 27 +++ api/modules/utils_source.md | 27 +++ api/modules/utils_style.md | 27 +++ api/modules/utils_styles.md | 76 +++++++ api/modules/utils_wait.md | 62 ++++++ package.json | 19 +- 24 files changed, 1202 insertions(+), 71 deletions(-) create mode 100644 api/README.md create mode 100644 api/interfaces/types.FrameportOptions.md create mode 100644 api/modules/config_browser.md create mode 100644 api/modules/config_generate.md create mode 100644 api/modules/config_generate_viewports.md create mode 100644 api/modules/features_dom.md create mode 100644 api/modules/main.md create mode 100644 api/modules/types.md create mode 100644 api/modules/utils_blob.md create mode 100644 api/modules/utils_code.md create mode 100644 api/modules/utils_constants.md create mode 100644 api/modules/utils_create.md create mode 100644 api/modules/utils_css.md create mode 100644 api/modules/utils_element.md create mode 100644 api/modules/utils_headers.md create mode 100644 api/modules/utils_iframe.md create mode 100644 api/modules/utils_js.md create mode 100644 api/modules/utils_page.md create mode 100644 api/modules/utils_source.md create mode 100644 api/modules/utils_style.md create mode 100644 api/modules/utils_styles.md create mode 100644 api/modules/utils_wait.md diff --git a/README.md b/README.md index 5b437c0..93ee9b4 100644 --- a/README.md +++ b/README.md @@ -1,112 +1,248 @@ -# Frameport +# @phun-ky/frameport + +![logo](./public/logo-frameport-colored-package.svg) > Frameport enables you to fake and display your responsive components in real life media queries! -Frameprot was created so I could display responsive examples of components in a style guide. It creates iframes with your component (html, css and javascript) that acts as natural viewports, thus making use of your media queries! +[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg)](http://makeapullrequest.com) [![SemVer 2.0](https://img.shields.io/badge/SemVer-2.0-green.svg)](http://semver.org/spec/v2.0.0.html) ![npm version](https://img.shields.io/npm/v/@phun-ky/frameport) ![issues](https://img.shields.io/github/issues/phun-ky/frameport) ![license](https://img.shields.io/npm/l/@phun-ky/frameport) ![size](https://img.shields.io/bundlephobia/min/@phun-ky/frameport) ![npm](https://img.shields.io/npm/dm/%40phun-ky/frameport) ![GitHub Repo stars](https://img.shields.io/github/stars/phun-ky/frameport) + +1. [@phun-ky/frameport](#phun-kyframeport) + 1. [About](#about) + 2. [API](#api) + 3. [Demo](#demo) + 4. [Options](#options) + 5. [Usage](#usage) + 1. [Typescript](#typescript) + 2. [ESM](#esm) + 3. [Script](#script) + 6. [Advanced usage](#advanced-usage) + 1. [Lazy](#lazy) + 7. [Features](#features) + 8. [Via DOM](#via-dom) + 1. [Use templates as a target](#use-templates-as-a-target) + 2. [Use targets with different template](#use-targets-with-different-template) + 1. [Allowed tags](#allowed-tags) + +## About + +Frameprot was created so I could display frameports of components in a style guide. It creates iframes with your component (html, css and javascript) that acts as natural viewports, thus making use of your media queries! ```shell-session -$ npm i -S @phun-ky/frameport -// installs +npm i -S @phun-ky/frameport ``` -## Use programatically +## API + +Go [here](https://github.com/phun-ky/frameport/blob/main/api/README.md) to read the full API documentation. + +## Demo + +Click [here for a demo on codepen.io](https://codepen.io/phun-ky/full/MWWWvLm) + +## Options + +| Option | Type | Required | Description | +| ---------------- | ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| | | | | +| html | string | ✓ | The html you want to use in the viewport example | +| height | string \| number | | The height of the viewport, either as a string (e.g., '400') or a number (e.g., 400) | +| width | string \| number | | The width of the viewport, either as a string (e.g., '600') or a number (e.g., 600) | +| className | string | | Class names to be given the generated iframe | +| style | string | | Inline styles (CSS) to be inserted into a ` + + + +
+
+ home + projects +
+ buy me a coffee? + sponsor me! + +
+
+
+
+
+

Responsive Documentation Examples

+

+ Responsive Documentation Examples (rde) enables you to fake and + display your responsive components in real life media queries! See + README + for instructions. +

+
+ github + npm +
+
$ npm i @phun-ky/responsive-documentation-examples --save
+
+
+
+
+
+
+
+ +
+
+
+
+
+

Look mah, I'm in an iframe

+ +
+
+
+
+
+
+ +
+ + + + + diff --git a/dev/ph.css b/dev/ph.css new file mode 100644 index 0000000..a466a0f --- /dev/null +++ b/dev/ph.css @@ -0,0 +1,1019 @@ +:root { + --ph-font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif; + --ph-font-family-code: 'Menlo for Powerline', 'Menlo Regular for Powerline', + 'DejaVu Sans Mono', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', + monospace; + --ph-color-link: #6ca7f9; + --ph-color-link-hover: #6ca7f9; + --ph-color-link-active: #6ca7f9; + --ph-color-link-visited: #6ca7f9; + --ph-color-text: #9fa8ad; + --ph-color-text-accent: #e4e4e7; + --ph-color-message: var(--ph-color-text); + --ph-color-well-background: hsla(201, 8%, 65%, 0.1); + --ph-color-code-block-background: var(--ph-color-well-background); + --ph-color-code-block: var(--ph-color-code-color-6); + --ph-color-code: var(--ph-color-code-color-6); + --ph-color-background: #181a22; + --ph-color-background-gradient-2: #262a3b; + --ph-color-background-notice-warning: rgba(210, 153, 34, 0.2); + --ph-color-background-notice-note: rgba(47, 129, 247, 0.2); + --ph-color-background-notice-important: rgba(163, 113, 247, 0.2); + --ph-color-background-notice-error: rgba(248, 81, 73, 0.2); + --ph-color-background-notice-success: rgba(46, 160, 67, 0.2); + --ph-color-background-notice-info: var(--ph-color-well-background); + --ph-color-code-color-1: #859ba3; + --ph-color-code-color-2: #c79500; + --ph-color-code-color-3: #2caaa0; + --ph-color-code-color-4: #469edd; + --ph-color-code-color-5: #8c9b9b; + --ph-color-code-color-6: #e4e4e7; + --ph-color-code-color-7: #262831; + --ph-color-code-color-8: #f66; + --ph-background-radial-1: #262a3b; + --ph-background-radial-2: #181a22; +} +:root.theme--light { + --ph-color-link: #0750b6; + --ph-color-link-hover: #0750b6; + --ph-color-link-active: #0750b6; + --ph-color-link-visited: #0750b6; + --ph-color-text: #454444; + --ph-color-text-accent: #000; + --ph-color-message: var(--ph-color-text-accent); + --ph-color-well-background: hsla(201, 8%, 65%, 0.1); + --ph-color-code-block-background: var(--ph-color-well-background); + --ph-color-background: #fff; + --ph-color-background-notice-warning: rgba(210, 153, 34, 0.2); + --ph-color-background-notice-note: rgba(47, 129, 247, 0.2); + --ph-color-background-notice-important: rgba(163, 113, 247, 0.2); + --ph-color-background-notice-error: rgba(248, 81, 73, 0.2); + --ph-color-background-notice-success: rgba(46, 160, 67, 0.2); + --ph-color-background-notice-info: var(--ph-color-well-background); + --ph-color-code-color-1: #566d71; + --ph-color-code-color-2: #806200; + --ph-color-code-color-3: #1e766d; + --ph-color-code-color-4: #1d699f; + --ph-color-code-color-5: #5c6a6a; + --ph-color-code-color-6: #000; + --ph-color-code-color-7: #f5f6f7; + --ph-color-code-color-8: #cd0404; + --ph-background-radial-1: #f5f6f7; + --ph-background-radial-2: #fff; +} +.sr-only { + clip: rect(1px, 1px, 1px, 1px) !important; + border: 0 !important; + -webkit-clip-path: inset(50%) !important; + clip-path: inset(50%) !important; + height: 1px !important; + margin: -1px !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 1px !important; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + clip: auto !important; + -webkit-clip-path: none !important; + clip-path: none !important; + height: auto !important; + margin: auto !important; + overflow: visible !important; + white-space: normal !important; + width: auto !important; +} +.sr-skip-link { + align-items: center; + background-color: var(--dtm-color-obsidian) !important; + color: var(--dtm-color-white) !important; + display: flex; + font-weight: 700; + justify-content: center; + left: 25%; + padding: 0.3125rem 0.625rem; + position: absolute; + top: 0; + transform: translateY(-100%); + z-index: 900; +} +.sr-skip-link:focus { + transform: translateY(0); +} +.ph :focus { + outline: var(--ph-color-link) solid 0.1875rem; + outline-offset: 0.125rem; +} +.ph :focus:not(:focus-visible) { + outline: none; +} +.ph :focus-visible { + outline: var(--ph-color-link) solid 0.1875rem; + outline-offset: 0.125rem; +} +.ph.showcase { + grid-gap: 5rem; + background-color: var(--ph-color-text-accent); + border-radius: 0.375rem; + display: grid; + padding-bottom: 5rem; + padding-top: 5rem; +} +.ph sup, +.ph sup a { + font-size: 0.5rem; + font-weight: 400; +} +figcaption.ph { + color: var(--ph-color-text); + font-size: 0.875rem; + font-style: italic; + line-height: 1.25rem; + max-width: none; + opacity: 0.8; + padding-top: 0.5rem; +} +figure figcaption.ph:before { + content: 'Figure ' counter(figure); + font-style: normal; + font-weight: 700; +} +figcaption.ph p.ph:first-child { + margin-top: 0; +} +figcaption.ph p.ph { + font-size: 0.875rem; + font-style: italic; + line-height: 1.25rem; + max-width: none; +} +figure.ph { + counter-increment: figure; +} +figure.ph > pre { + margin: 0; +} +figure.ph :not(figcaption) img { + height: 100%; + margin: 0; + object-fit: contain; + width: 100%; +} +figcaption.ph a { + font-weight: 400; +} +ol.ph, +ul.ph { + margin-bottom: 1.25em; + margin-top: 1.25em; + padding-left: 1rem; +} +ol.ph ol.ph, +ol.ph ul.ph, +ul.ph ol.ph, +ul.ph ul.ph { + margin-bottom: 0; + margin-top: 0; +} +blockquote.ph { + border-radius: 0.375rem; + font-size: 1.125rem; + font-style: italic; + font-weight: 500; + line-height: 1.75rem; + padding: 3rem 1.1428571em 0.8571429em 2rem; + position: relative; +} +@media screen and (min-width: 1024px) { + blockquote.ph { + padding: 5rem 1.1428571em 0.8571429em 4rem; + } +} +blockquote.ph footer.ph > .ph { + color: var(--ph-color-text); + display: block; + font-size: 0.875rem; + font-style: italic; + font-weight: 400; + line-height: 1.25rem; + max-width: none; + opacity: 0.8; + padding-top: 0.5rem; + text-align: right; +} +blockquote.ph:before { + content: '“'; + font-size: 10rem; + left: 0; + line-height: 10rem; + position: absolute; + top: 0; +} +hr.ph { + background-color: var(--ph-color-text); + border: none; + height: 2pt; + margin: 3em auto 3em 0; + width: 80%; +} +.ph.category-navigation { + display: none; + padding: 5rem 0; +} +@media screen and (min-width: 1024px) { + .ph.category-navigation { + display: block; + } +} +.ph.posts { + grid-gap: 5rem; + display: grid; + grid-template-columns: 1fr; + list-style: none; + margin: 0; + padding: 5rem 0; +} +.ph.post a.ph { + color: inherit; + text-decoration: inherit; +} +.ph.post a.ph:hover .ph.post-title { + text-decoration: underline; +} +.ph.post .ph.post-title { + font-size: 2.25rem; + font-weight: 700; + line-height: 1.375; + margin: 0; +} +.ph.post .ph.post-description { + font-size: 1rem; + font-weight: 400; + line-height: 1.75; +} +.ph.post .ph.post-meta { + font-size: 0.875rem; + font-style: inherit; + font-weight: 400; + line-height: 1.75; +} +.ph.post .ph.post-meta a.ph { + color: var(--ph-color-link); + text-decoration: underline; +} +.ph.post .ph.post-meta a.ph:hover { + color: var(--ph-color-link-hover); +} +.ph.frontpage-posts { + grid-gap: 5rem; + display: grid; + grid-template-columns: 1fr; +} +@media screen and (min-width: 1024px) { + .ph.frontpage-posts { + grid-template-columns: 2fr 1fr; + } +} +.ph.categories-title { + color: var(--ph-color-text); + font-size: 0.875rem; + font-weight: 700; + line-height: 1.25rem; + margin: 0; + padding-bottom: 0.5rem; + padding-top: 0.75rem; + text-transform: uppercase; +} +.ph.categories { + list-style: none; + padding: 0; +} +.ph.categories .ph.category-link { + font-size: 1.25rem; + font-weight: 500; + line-height: 2; + text-decoration: none; +} +.ph.categories .ph.category-link:hover { + text-decoration: underline; +} +.ph.tags-title { + color: var(--ph-color-text); + font-size: 0.875rem; + font-weight: 700; + line-height: 1.25rem; + margin: 0; + padding-bottom: 0.5rem; + padding-top: 0.75rem; + text-transform: uppercase; +} +.ph.tags { + grid-gap: 0 0.5rem; + display: flex; + flex-wrap: wrap; + list-style: none; + padding: 0; +} +.ph.tags .ph.tag-link { + font-size: 1rem; + font-weight: 400; + line-height: 1.25; + text-decoration: none; + text-transform: lowercase; +} +.ph.tags .ph.tag-link:hover { + text-decoration: underline; +} +figure.ph { + display: flex; + flex-direction: column; + margin-bottom: 1.25em; + margin-top: 1.25em; +} +article.ph img, +figure.ph img { + max-width: 100%; +} +.ph.message { + background-color: var(--ph-color-well-background); + border-radius: 0.375rem; + color: var(--ph-color-text); + font-size: 0.875rem; + line-height: 1.5rem; + margin-bottom: 1.5rem; + margin-top: 1.5rem; + overflow-x: auto; + padding: 0.75rem 1rem; +} +@media screen and (min-width: 1024px) { + .ph.message { + font-size: 1rem; + line-height: 1.75rem; + margin-bottom: 2rem; + margin-top: 2rem; + padding: 1rem 1.5rem; + } +} +.ph.message .ph.title { + font-size: 1.25rem; + font-weight: 500; + line-height: 2; +} +.ph.message .ph.title .ph.icon { + fill: currentColor; + height: 1.125rem; + margin-right: 0.5rem; + transform: translateY(2px); + width: 1.125rem; +} +.ph.message * { + color: var(--ph-color-message); +} +.ph.message.warning { + background-color: var(--ph-color-background-notice-warning); +} +.ph.message.note { + background-color: var(--ph-color-background-notice-note); +} +.ph.message.error { + background-color: var(--ph-color-background-notice-error); +} +.ph.message.info { + background-color: var(--ph-color-background-notice-info); +} +.ph.message.success { + background-color: var(--ph-color-background-notice-success); +} +.ph.message.important { + background-color: var(--ph-color-background-notice-important); +} +.ph.message .ph.description { + margin-bottom: 1rem; + margin-top: 1rem; +} +.ph.message p.ph { + max-width: none; +} +article.ph h2.ph { + font-size: 1.5rem; + line-height: 2rem; + margin-bottom: 1.5rem; + margin-top: 3rem; +} +@media screen and (min-width: 1024px) { + article.ph h2.ph { + font-size: 1.875rem; + line-height: 2.5rem; + margin-bottom: 2rem; + margin-top: 3.5rem; + } +} +article.ph h3.ph { + font-size: 1.25rem; + line-height: 2rem; + margin-bottom: 0.75rem; + margin-top: 2rem; +} +@media screen and (min-width: 1024px) { + article.ph h3.ph { + font-size: 1.5rem; + line-height: 2.25rem; + margin-bottom: 1rem; + margin-top: 2.5rem; + } +} +article.ph li.ph > code[class^='language-'], +article.ph p.ph > code[class^='language-'] { + background-color: transparent; + color: var(--ph-color-code); +} +article.ph li.ph > code[class^='language-']:after, +article.ph li.ph > code[class^='language-']:before, +article.ph p.ph > code[class^='language-']:after, +article.ph p.ph > code[class^='language-']:before { + content: '`'; +} +.cp_embed_wrapper { + background-color: var(--ph-color-well-background); + border-radius: 0.375rem; + overflow: hidden; +} +.ph.breadcrumbs { + align-items: center; + display: flex; + justify-content: flex-start; + list-style: none; + margin: 0; + padding: 1.25rem 0; + position: relative; +} +@media screen and (min-width: 1440px) { + .ph.breadcrumbs { + z-index: 200; + } +} +.ph.breadcrumbs li:not(:first-of-type) { + align-items: center; + color: var(--ph-color-text-accent); + display: flex; + justify-content: flex-start; +} +.ph.breadcrumbs a { + color: var(--ph-color-text-accent); + font-size: 1.125rem; + font-weight: 600; + line-height: 1.75rem; + text-decoration: none; +} +@media screen and (min-width: 1024px) { + .ph.breadcrumbs a { + font-size: 1.25rem; + line-height: 1.75rem; + } +} +.ph.breadcrumbs a:hover { + color: var(--ph-color-link-hover); + text-decoration: underline; +} +.ph.sustainable-verification { + grid-gap: 1rem; + display: flex; + flex-wrap: wrap; +} +figure.ph>a[href^="https://i.vimeocdn"].ph,figure.ph>a[href^="https://player.vimeo.com"].ph,figure.ph>a[href^="https://videos.files.wordpres"].ph,figure.ph>a[href^="https://vimeo.com"].ph,figure.ph>a[href^="https://www.vimeo.com"].ph,figure.ph>a[href^="https://www.youtube.com"].ph,figure.ph>a[href^="https://youtube.com"].ph +{ + display: block; + position: relative; +} +figure.ph>a[href^="https://i.vimeocdn"].ph:before,figure.ph>a[href^="https://player.vimeo.com"].ph:before,figure.ph>a[href^="https://videos.files.wordpres"].ph:before,figure.ph>a[href^="https://vimeo.com"].ph:before,figure.ph>a[href^="https://www.vimeo.com"].ph:before,figure.ph>a[href^="https://www.youtube.com"].ph:before,figure.ph>a[href^="https://youtube.com"].ph:before +{ + background-color: var(--ph-color-well-background); + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' xml:space='preserve' viewBox='0 0 1024 721'%3E%3Cpath fill='%23FFF' d='m407 493 276-143-276-144v287z'/%3E%3Cpath fill='%23333' d='m407 206 242 161.6 34-17.6-276-144z' opacity='.12'/%3E%3ClinearGradient id='a' x1='512.5' x2='512.5' y1='719.7' y2='1.2' gradientTransform='matrix(1 0 0 -1 0 721)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' style='stop-color:%23000'/%3E%3Cstop offset='1' style='stop-color:%23333'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M1013 156.3s-10-70.4-40.6-101.4C933.6 14.2 890 14 870.1 11.6 727.1 1.3 512.7 1.3 512.7 1.3h-.4s-214.4 0-357.4 10.3C135 14 91.4 14.2 52.6 54.9 22 85.9 12 156.3 12 156.3S1.8 238.9 1.8 321.6v77.5C1.8 481.8 12 564.4 12 564.4s10 70.4 40.6 101.4c38.9 40.7 89.9 39.4 112.6 43.7 81.7 7.8 347.3 10.3 347.3 10.3s214.6-.3 357.6-10.7c20-2.4 63.5-2.6 102.3-43.3 30.6-31 40.6-101.4 40.6-101.4s10.2-82.7 10.2-165.3v-77.5c0-82.7-10.2-165.3-10.2-165.3zM407 493V206l276 144-276 143z'/%3E%3C/svg%3E"); + background-position: 50%; + background-repeat: no-repeat; + background-size: 3rem; + border-radius: 5rem; + content: ''; + display: block; + height: 5rem; + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 5rem; +} +:not(pre) > code[class*='language-'].ph { + background-color: transparent; + color: var(--ph-color-code); + font-weight: 700; +} +:not(pre) > code[class*='language-'].ph:after, +:not(pre) > code[class*='language-'].ph:before { + content: '`'; +} +.ph.definition { + background-color: var(--ph-color-well-background); + border-radius: 0.375rem; + color: var(--ph-color-text-accent); + font-size: 0.75rem; + line-height: 1rem; + margin-bottom: 1.5rem; + margin-top: 1.5rem; + overflow-x: auto; + padding: 0.75rem 1rem; +} +@media screen and (min-width: 1024px) { + .ph.definition { + font-size: 0.875rem; + line-height: 1.5rem; + margin-bottom: 2rem; + margin-top: 2rem; + padding: 1rem 1.5rem; + } +} +.ph.definition p.ph { + font-size: 0.75rem; + line-height: 1.25rem; +} +@media screen and (min-width: 1024px) { + .ph.definition p.ph { + font-size: 0.875rem; + line-height: 1.5rem; + } +} +.ph.definition .ph.word { + display: block; + font-size: 1.125rem; + line-height: 1.25rem; + text-align: left; + width: 100%; +} +@media screen and (min-width: 1024px) { + .ph.definition .ph.word { + font-size: 1.25rem; + line-height: 2rem; + } +} +.ph.definition .ph.example-sentence, +.ph.definition .ph.states { + color: var(--ph-color-text); +} +.ph.definition .ph.example-sentence:after, +.ph.definition .ph.example-sentence:before { + content: '"'; +} +.ph.class { + color: var(--ph-color-text-accent); +} +.ph.definition .ph.badge { + background-color: var(--ph-color-well-background); + border-radius: 0.375rem; + color: var(--ph-color-text); + padding: 0.25rem 0.5rem; + text-transform: uppercase; +} +.ph.definition > ol { + grid-gap: 1rem; + display: flex; + flex-direction: column; +} +.ph.definition > ol > li::marker { + font-weight: 700; +} +.ph.definition > ol ul { + margin-bottom: 1rem; + margin-top: 1rem; +} +.ph.definition > ol ul > li { + list-style: disc; +} +.ph.definition li { + padding-left: 0.75rem; +} +.ph.definition .ph.phonetic { + font-family: var(--ph-font-family-code); +} +article.ph h2.ph .ph.years-ago, +article.ph h3.ph .ph.years-ago, +article.ph h4.ph .ph.years-ago { + display: inline-block; + font-size: 70%; + font-style: italic; + font-weight: 300; + line-height: 100%; + margin-left: 1ch; +} +article.ph h2.ph .ph.years-ago:before, +article.ph h3.ph .ph.years-ago:before, +article.ph h4.ph .ph.years-ago:before { + content: '('; +} +article.ph h2.ph .ph.years-ago:after, +article.ph h3.ph .ph.years-ago:after, +article.ph h4.ph .ph.years-ago:after { + content: ')'; +} +.ph.ascii-flow > pre.ph { + align-items: center; + display: flex; + justify-content: center; + line-height: 1rem; + margin: 0; + pointer-events: none; + user-select: none; +} +article.ph p.ph a.ph img.ph:not(img[src*='shields.io']) { + width: 100%; +} +.ph.explicit { + overflow: hidden; + position: relative; +} +.ph.explicit:before { + align-items: center; + background-color: var(--ph-color-well-background); + bottom: 0; + content: 'Explicit content. Click to view'; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 100; +} +.ph.explicit > img { + filter: blur(30px); +} +figcaption.ph > p.ph:first-of-type { + display: inline; +} +h1:hover .ph.heading-link:before, +h2:hover .ph.heading-link:before, +h3:hover .ph.heading-link:before, +h4:hover .ph.heading-link:before, +h5:hover .ph.heading-link:before, +h6:hover .ph.heading-link:before { + content: '#'; + display: inline-block; + font-size: inherit; + margin-left: 1ch; +} +.ph.code-toolbar { + position: relative; +} +.ph.code-toolbar .ph.tools { + grid-gap: 0.5rem; + align-items: center; + display: flex; + justify-content: flex-end; + position: absolute; + right: 1.5rem; + top: 1rem; +} +.ph.code-toolbar .ph.language { + color: var(--ph-color-text); + pointer-events: none; + user-select: none; +} +.ph.code-toolbar .ph.copy, +.ph.code-toolbar .ph.language { + align-items: center; + display: flex; + font-family: var(--ph-font-family); + font-size: 0.75rem; + justify-content: center; + text-transform: uppercase; +} +.ph.code-toolbar .ph.copy { + appearance: none; + background-color: transparent; + border: none; + color: var(--ph-color-text-accent); + cursor: pointer; + transition: all 0.1s cubic-bezier(0.4, 0, 0.2, 1); +} +.ph.code-toolbar .ph.copy:hover { + color: var(--ph-color-text); +} +.ph.swatch { + grid-gap: 1.25rem; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + width: 100%; +} +.ph.swatch .ph.color { + align-items: center; + display: flex; + font-family: var(--ph-font-family-code); + font-size: 1.5rem; + font-weight: 600; + height: 8rem; + justify-content: center; + line-height: 8rem; + position: relative; + width: 8rem; +} +.ph.swatch .ph.color:before { + bottom: 0.25rem; + color: inherit; + content: attr(data-color-name); + font-size: 0.75rem; + font-weight: 400; + left: 0.25rem; + line-height: 1rem; + position: absolute; +} +.ph.color-badge { + color: var(--ph-color-text-accent); + display: inline-block; + font-family: var(--ph-font-family-code); + font-weight: 400; + padding-left: 1.75rem; + position: relative; + white-space: nowrap; +} +.ph.color-badge .ph.color-drop { + background-clip: padding-box; + border: 1pt solid #fff; + border-radius: 100%; + display: inline-block; + height: 1rem; + left: 6px; + margin-right: 0.25rem; + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 1rem; +} +.theme--light .ph.color-badge .ph.color-drop { + border: 1pt solid #000; +} +table.ph { + background-color: var(--ph-color-well-background); + border-collapse: collapse; + border-radius: 0.375rem; + border-spacing: 0; + color: var(--ph-color-text); + display: block; + font-size: 0.875rem; + line-height: 1.5rem; + margin-bottom: 1.5rem; + margin-top: 1.5rem; + max-width: 100%; + overflow: auto; + padding: 1.25rem; + table-layout: fixed; + width: max-content; +} +@media screen and (min-width: 1024px) { + table.ph { + border-collapse: normal; + font-size: 1rem; + line-height: 1.75rem; + margin-bottom: 2rem; + margin-top: 2rem; + padding: 1rem 1.5rem; + } +} +table.ph th.ph { + text-align: left; +} +table.ph td.ph, +table.ph th.ph { + padding: 0 0.5rem; + word-break: normal; +} +@media screen and (min-width: 1024px) { + table.ph td.ph, + table.ph th.ph { + padding: 0 1rem; + } +} +table.ph > tbody.ph > tr:nth-child(2n) { + background-color: var(--ph-color-well-background); +} +table.ph code.ph { + word-break: normal; +} +@media screen and (min-width: 1440px) { + main.ph a.ph { + position: relative; + z-index: 300; + } +} +.ph.project-main-logo { + height: 20rem; + margin: 0 auto; +} +.ph.project article img.ph[src^='/img/'] { + max-width: 960px; + width: 100%; +} +.ph.app.project.speccer .ph.hero .ph.content { + background-color: #ffc72c; + color: #000; + flex-direction: column; +} +.ph.app.project.speccer .ph.hero .ph.content .ph.slogan { + position: relative; +} +.ph.app.project.speccer .ph.hero .ph.content svg { + max-width: 70%; +} +.ph.app.project.speccer .ph.hero .ph.content .ph.slogan { + display: none; + font-size: 1rem; + font-weight: 600; + text-align: center; + text-transform: uppercase; + width: 70%; +} +@media screen and (min-width: 1024px) { + .ph.app.project.speccer .ph.hero .ph.content .ph.slogan { + display: block; + } +} +.ph.app.project.speccer .ph.banner { + background-image: radial-gradient(circle, #262a3b 0, #181a22 100%); + color: var(--ph-color-text-accent); + flex-direction: column; +} +.ph.app.project.speccer .ph.banner svg { + display: block; + margin: 0 auto; + max-width: 80%; + width: 100%; +} +.ph.app.project.speccer .ph.banner .ph.slogan { + color: #ffc72c; + display: none; + font-size: 1.3rem; + font-weight: 600; + margin: 0 auto; + max-width: 80%; + text-align: center; + text-transform: uppercase; + width: 100%; +} +@media screen and (min-width: 1024px) { + .ph.app.project.speccer .ph.banner .ph.slogan { + display: block; + } +} +.ph.app.project .ph.hero { + display: flex; + flex-direction: column; + height: 480px; + margin: 0 auto; + max-width: 1440px; + width: 100%; +} +@media screen and (min-width: 1024px) { + .ph.app.project .ph.hero { + display: grid; + grid-template-areas: 'content logo' 'content reel'; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr 1fr; + } +} +.ph.app.project .ph.hero .ph.content { + align-items: center; + display: flex; + grid-area: content; + height: 280px; + justify-content: center; + padding: 1.5rem; +} +@media screen and (min-width: 1024px) { + .ph.app.project .ph.hero .ph.content { + height: 100%; + } +} +.ph.app.project .ph.hero .ph.logo { + align-items: center; + background-image: radial-gradient( + circle, + var(--ph-background-radial-1) 0, + var(--ph-background-radial-2) 100% + ); + color: var(--ph-color-text-accent); + display: none; + grid-area: logo; + justify-content: center; +} +@media screen and (min-width: 1024px) { + .ph.app.project .ph.hero .ph.logo { + display: flex; + } +} +.ph.app.project .ph.hero .ph.logo svg { + max-width: 300px; + width: 100%; +} +.ph.app.project .ph.hero .ph.reel { + filter: grayscale(0.9); + height: 200px; +} +@media screen and (min-width: 1024px) { + .ph.app.project .ph.hero .ph.reel { + grid-area: reel; + height: auto; + } +} +.ph.speccer .ph.reel { + background-image: url(/img/speccer/speccer-showcase.jpeg); + background-repeat: no-repeat; + background-size: cover; +} +.ph.used-by-logo { + display: block; + height: 3rem; + width: 3rem; +} +.ph.button { + align-items: center; + background-color: transparent; + border: 2pt solid var(--ph-color-text); + border-radius: 12px; + color: var(--ph-color-text); + display: inline-flex; + justify-content: center; + max-width: 25ch; + min-height: 48px; + min-width: 10ch; + padding: 0.5rem 1rem; + text-decoration: none; +} +.ph.button:hover { + border-color: var(--ph-color-link); + color: var(--ph-color-link); +} +.ph.button + .ph.button { + margin-left: 1rem; +} +.ph.button.cta { + background-color: var(--ph-color-link); + border: 2pt solid transparent; + color: var(--ph-color-background); +} +.ph.button.cta:hover { + background-color: transparent; + border-color: var(--ph-color-link); + color: var(--ph-color-link); +} +.ph.features { + display: flex; + flex-direction: column; + justify-content: center; + width: 100%; +} +@media screen and (min-width: 1024px) { + .ph.features { + grid-gap: 2rem 2rem; + display: grid; + grid-template-columns: 320px 320px 320px; + padding-left: 10rem; + padding-right: 10rem; + } + .ph.features .ph.feature { + max-width: 320px; + } +} +.ph.features .ph.feature img.ph { + border: 2pt solid var(--ph-color-well-background); + border-radius: 12px; + width: 100%; +} +.ph.features .ph.feature { + background-color: var(--ph-color-background-notice-note); + border-radius: 0.375rem; + color: var(--ph-color-text); + font-size: 0.875rem; + line-height: 1.5rem; + margin-bottom: 1.5rem; + margin-top: 1.5rem; + overflow-x: auto; + padding: 0.75rem 1rem; +} +@media screen and (min-width: 1024px) { + .ph.features .ph.feature { + font-size: 1rem; + line-height: 1.75rem; + margin-bottom: 2rem; + margin-top: 2rem; + padding: 1rem 1.5rem; + } +} +#features > h2.ph { + text-align: center; +} +@media screen and (max-width: 1023px) { + .ph-speccer { + display: none !important; + } +} From 6a6fe9e71808041e8515a8768370e6935a4a7867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Vassbotn=20R=C3=B8yne-Helgesen?= Date: Thu, 19 Oct 2023 22:20:16 +0200 Subject: [PATCH 5/7] =?UTF-8?q?chore:=20=F0=9F=A4=96=20build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frameport.d.ts | 39 +++++++++++++++++++++++++++++++++++++++ frameport.js | 2 ++ frameport.js.map | 1 + 3 files changed, 42 insertions(+) create mode 100644 frameport.d.ts create mode 100644 frameport.js create mode 100644 frameport.js.map diff --git a/frameport.d.ts b/frameport.d.ts new file mode 100644 index 0000000..338b3e2 --- /dev/null +++ b/frameport.d.ts @@ -0,0 +1,39 @@ +/** + * Example usage: + * ```ts + * const options: FrameportOptions = { + * html: '
Hello, World!
', + * height: '300', + * width: 400, + * className: 'my-embed', + * style: 'color: blue;', + * css: '.my-embed { background-color: yellow; }', + * code: 'console.log("Embedded content");', + * javascript: '/dummy.js', + * headers: ['Authorization: Bearer Token'] + * }; + * ``` + */ +type FrameportFunctionType = () => void; + +/** + * Extends the global Window interface to add custom properties. + */ +declare global { + interface Window { + /** + * Represents the frameport object for additional functionality. + */ + frameport: any; + } +} + +declare const modes: { + domReady: (frameport: FrameportFunctionType) => void; + lazy: () => void; + manual: (frameport: FrameportFunctionType) => void; + activate: (frameport: FrameportFunctionType) => void; +}; +declare const frameport: () => void; + +export { frameport as default, modes }; diff --git a/frameport.js b/frameport.js new file mode 100644 index 0000000..12c9e93 --- /dev/null +++ b/frameport.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).frameport={})}(this,(function(e){"use strict";const t=e=>{let{html:t,style:r,css:o,code:a,javascript:n,headers:s=[]}=e;return o=(e=>e?``:"")(o),n=(e=>e?``;\n }\n return '';\n};\n","/**\n * Get a script element containing the provided code if available.\n *\n * @param {string | undefined} code - The code to include in the script element.\n * @returns {string} - The script element or an empty string if code is not available.\n */\nexport const getCode = (code: string | undefined): string => {\n if (code) {\n return ``;\n }\n return '';\n};\n","/**\n * Generate a style element based on the provided CSS styles.\n *\n * @param {string | undefined} style - The CSS styles to include in the style element.\n * @returns {string} - The style element as a string or an empty string if no styles are provided.\n */\nexport const getStyle = (style: string | undefined): string => {\n if (style) {\n return ``;\n }\n return '';\n};\n","import { getBlobURL } from \"./blob\";\nimport { getSource } from \"./source\";\n\n/**\n * Get the URL of a generated HTML page based on the provided options.\n *\n * @param {object} options - The options for generating the HTML page.\n * @returns {string} - The URL of the generated HTML page as a Blob URL.\n */\nexport const getGeneratedPageURL = (options) => {\n const source = getSource(options);\n return getBlobURL(source, 'text/html');\n};\n","/**\n * Generates a Blob URL from HTML content with the specified MIME type.\n *\n * @param {string} html - The HTML content to create a Blob from.\n * @param {string} type - The MIME type of the Blob (e.g., 'text/html', 'image/jpeg').\n * @returns {string} - The generated Blob URL.\n */\nexport const getBlobURL = (html: string, type: string): string => {\n const blob = new Blob([html], { type });\n return URL.createObjectURL(blob);\n};\n","/* eslint no-console:0 */\n'use strict';\nimport { waitForFrame } from './wait';\n\n/**\n * Adds CSS styles to an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to apply styles to.\n * @param {object | Array<{ key: string; value: string }>} styles - An object or an array of objects containing CSS styles to apply.\n * @returns {Promise} - A Promise that resolves after styles are applied.\n *\n * @example\n * ```ts\n * // Apply styles as an object\n * const element = document.getElementById('my-element');\n * await add(element, { color: 'red', fontSize: '16px' });\n *\n * // Apply styles as an array of objects\n * const styles = [\n * { key: 'color', value: 'blue' },\n * { key: 'backgroundColor', value: 'yellow' }\n * ];\n * await add(element, styles);\n * ```\n */\nexport const add = async (\n el: HTMLElement,\n styles: object | Array<{ key: string; value: string }>\n): Promise => {\n if (\n !el ||\n !styles ||\n typeof styles === 'string' ||\n typeof styles === 'number' ||\n typeof styles === 'boolean' ||\n (Array.isArray(styles) && styles.length === 0) ||\n (Object.keys(styles).length === 0 && styles.constructor === Object)\n ) {\n return;\n }\n\n await waitForFrame();\n\n if (Array.isArray(styles)) {\n styles.forEach(\n (style: { key: string; value: string }) =>\n (el.style[style.key] = style.value)\n );\n } else {\n Object.keys(styles).forEach((key) => (el.style[key] = styles[key]));\n }\n};\n\n/**\n * Gets the computed CSS styles of an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to get computed styles from.\n * @returns {Promise} - A Promise that resolves with the computed CSS styles.\n *\n * @example\n * ```ts\n * // Get computed styles of an element\n * const element = document.getElementById('my-element');\n * const computedStyles = await get(element);\n * console.log(computedStyles.color); // Logs the color property value\n * ```\n */\nexport const get = async (el: HTMLElement): Promise => {\n await waitForFrame();\n\n return getComputedStyle(el, null);\n};\n","/**\n * Waits for the specified amount of time in milliseconds.\n *\n * @param {number} ms - The number of milliseconds to wait.\n * @returns {Promise} - A Promise that resolves after the specified time.\n *\n * @example\n * ```ts\n * // Wait for 1 second (1000 milliseconds)\n * await waitFor(1000);\n * ```\n */\nexport const waitFor = (ms: number): Promise =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Waits for the next animation frame using requestAnimationFrame.\n *\n * @returns {Promise} - A Promise that resolves with the timestamp of the next animation frame.\n *\n * @example\n * ```ts\n * // Wait for the next animation frame and get the rect\n * await waitForFrame();\n * const rect = el.getBoundingClientRect();\n * // Wait for the next animation frame and get the timestamp\n * const timestamp = await waitForFrame();\n * ```\n */\nexport const waitForFrame = (): Promise =>\n new Promise(requestAnimationFrame);\n","import { FrameportOptions } from 'types';\nimport { createIframe } from 'utils/iframe';\nimport { getGeneratedPageURL } from 'utils/page';\nimport { add as addStyles } from 'utils/styles';\n\n/**\n * Create an iframe element with specified options and styles.\n *\n * @param {FrameportOptions} options - The options for creating the iframe.\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const create = (\n options: FrameportOptions\n): HTMLIFrameElement => {\n const { className, height, width } = options;\n const url = getGeneratedPageURL(options);\n const iframeElement = createIframe();\n const iframeStyle = {};\n\n iframeElement.src = url;\n iframeElement.setAttribute('data-rde-iframe', '');\n\n if (!className || className === '') {\n iframeStyle['border'] = 'none';\n } else {\n iframeElement.classList.add(className);\n }\n\n iframeStyle['width'] = `${width}px`;\n\n if (height) {\n iframeStyle['height'] = `${height}px`;\n }\n\n addStyles(iframeElement, iframeStyle);\n\n return iframeElement;\n};\n","/**\n * Style object for hiding an element in the HTML.\n *\n * @type {{ clip: string, height: string, margin: string, overflow: string, position: string, width: string }}\n */\nexport const HIDE_TEMPLATE_STYLE: { clip: string; height: string; margin: string; overflow: string; position: string; width: string; } = {\n clip: 'rect(1px, 1px, 1px, 1px)',\n height: '1px',\n margin: '0',\n overflow: 'hidden',\n position: 'absolute',\n width: '1px'\n};\n\n/**\n * Default meta headers for an HTML document.\n *\n * @type {string[]}\n */\nexport const DEFAULT_HEADERS: string[] = [\n '',\n '',\n '',\n ''\n];\n","import { generate } from 'config/generate';\nimport { generateViewports } from 'config/generate-viewports';\nimport { FrameportOptions } from 'types';\nimport { HIDE_TEMPLATE_STYLE } from 'utils/constants';\nimport { add as addStyles } from 'utils/styles';\n\n/**\n * Generate iframes into the DOM, possibly generating viewports.\n *\n * @param {HTMLElement} targetElement - The target HTML element.\n * @param {FrameportOptions} options - The options for the iframe.\n * @returns {void}\n */\nconst dom = (\n targetElement: HTMLElement,\n options: FrameportOptions\n): void => {\n if (\n !targetElement ||\n !options ||\n (options && Object.keys(options).length === 0)\n )\n return;\n\n const { html, viewports, templateElement } = options;\n\n if (!html || html === '') return;\n\n console.log(templateElement)\n\n addStyles(templateElement as HTMLElement, HIDE_TEMPLATE_STYLE);\n\n if (viewports) {\n generateViewports(targetElement, options);\n } else {\n generate(targetElement, options);\n }\n};\n\nexport default dom;\n","import { FrameportOptions } from 'types';\nimport { create } from 'utils/create';\n\n/**\n * Generate multiple iframe elements for different viewports and append them to a target element.\n *\n * @param {HTMLElement} target - The target HTML element to insert iframes after.\n * @param {FrameportOptions} options - The options for generating the iframes.\n * @returns {void}\n */\nexport const generateViewports = (\n target: HTMLElement,\n options: FrameportOptions\n): void => {\n const { viewports } = options;\n\n if (!viewports || viewports === '') return;\n\n let screens: string[] = [];\n\n if (viewports.indexOf(',') !== -1) {\n screens = [...screens, ...viewports.split(',')];\n } else {\n screens.push(viewports);\n }\n\n screens.forEach((viewPort: string) => {\n const values = viewPort.split('x');\n const width = values[0];\n const height = values[1];\n\n const iframeElement = create({ ...options, height, width });\n\n target.insertAdjacentElement('afterend', iframeElement);\n });\n};\n","import { FrameportOptions } from 'types';\nimport { create } from 'utils/create';\n\n/**\n * Generate an iframe with the given options and append it to a target element.\n *\n * @param {HTMLElement} targetElement - The target HTML element to append the iframe to.\n * @param {FrameportOptions} options - The options for generating the iframe.\n * @returns {void}\n */\nexport const generate = (\n targetElement: HTMLElement,\n options: FrameportOptions\n): void => {\n const { width } = options;\n\n if (!width) return;\n\n const iframeElement = create(options);\n\n targetElement.append(iframeElement);\n};\n","import { DEFAULT_HEADERS } from \"./constants\";\n\n/**\n * Get headers for the iframe generated\n *\n * @param {string|string[]|null|undefined} rdeHeaders - The custom headers to include.\n * @returns {string[]} - An array of headers, including default and custom headers.\n */\nexport const getHeaders = (rdeHeaders: string | string[] | null | undefined): string[] => {\n let headers: string[] = [...DEFAULT_HEADERS];\n\n if (rdeHeaders) {\n if (Array.isArray(rdeHeaders)) {\n headers = [...headers, ...rdeHeaders];\n } else if (rdeHeaders.indexOf(',') !== -1) {\n headers = [...headers, ...rdeHeaders.split(',')];\n } else if (rdeHeaders !== '') {\n headers.push(rdeHeaders);\n }\n }\n\n return headers;\n};\n","/* eslint no-console:0 */\n'use strict';\n\nimport { FrameportFunctionType } from 'types';\nimport dom from 'features/dom';\nimport { getHeaders } from 'utils/headers';\n\n/**\n * A function to initialize frameport when the DOM is ready.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // domReady(myRDE);\n * ```\n */\nexport const domReady = (\n frameport: FrameportFunctionType\n): void => {\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n frameport();\n });\n } else {\n // `DOMContentLoaded` already fired\n frameport();\n\n }\n};\n\n/**\n * A function to initialize lazy frameport functionality.\n *\n * @example\n * ```ts\n * // Usage example:\n * // lazy();\n * ```\n */\nexport const lazy = (): void => {\n const frameportObserverTarget = new IntersectionObserver((els, observer) => {\n els.forEach((el: IntersectionObserverEntry) => {\n if (el.intersectionRatio > 0) {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports,\n },\n } = el.target as HTMLElement;\n\n let html = el.target.innerHTML;\n let templateElementToUse = el.target as HTMLElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports,\n };\n dom(el.target as HTMLElement, options);\n observer.unobserve(el.target);\n }\n });\n });\n\n document.querySelectorAll('[data-frameport]').forEach((el) => {\n frameportObserverTarget.observe(el);\n });\n};\n\n/**\n * A function to manually activate frameport.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // manual(myRDE);\n * ```\n */\nexport const manual = (\n frameport: FrameportFunctionType\n): void => {\n window.frameport = frameport;\n};\n\n/**\n * A function to activate frameport based on script attributes.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // activate(myRDE);\n * ```\n */\nexport const activate = (\n frameport: FrameportFunctionType\n): void => {\n const script = document.currentScript;\n\n if (script) {\n const frameportScriptSrc = script.getAttribute('src');\n\n if (frameportScriptSrc && frameportScriptSrc.indexOf('frameport.js') !== -1) {\n if (script.hasAttribute('data-manual')) {\n manual(frameport);\n } else if (script.hasAttribute('data-instant')) {\n frameport();\n } else if (script.hasAttribute('data-dom')) {\n domReady(frameport);\n } else if (script.hasAttribute('data-lazy')) {\n lazy();\n } else {\n domReady(frameport);\n }\n }\n }\n};\n","import { domReady, lazy, manual, activate } from 'config/browser';\nimport dom from 'features/dom';\nimport { getHeaders } from 'utils/headers';\n\nexport const modes = {\n domReady,\n lazy,\n manual,\n activate,\n};\n\nconst frameport = () => {\n document\n .querySelectorAll('[data-frameport-iframe]')\n .forEach((iframe) => iframe.remove());\n\n const elsToBeTransformedTemplate = document.querySelectorAll('[data-frameport]');\n\n console.log(elsToBeTransformedTemplate)\n\n elsToBeTransformedTemplate.forEach((targetElement: HTMLElement) => {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports,\n },\n } = targetElement;\n\n let html = targetElement.innerHTML;\n let templateElementToUse = targetElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports,\n };\n\n dom(targetElement, options);\n });\n};\n\nexport default frameport;\n\nactivate(frameport);\n"],"names":["getSource","options","html","style","css","code","javascript","headers","getCSS","window","location","protocol","host","getJavaScript","getCode","getStyle","join","getGeneratedPageURL","type","blob","Blob","URL","createObjectURL","getBlobURL","add","async","el","styles","Array","isArray","length","Object","keys","constructor","Promise","requestAnimationFrame","forEach","key","value","create","className","height","width","url","iframeElement","document","createElement","iframeStyle","src","setAttribute","classList","addStyles","HIDE_TEMPLATE_STYLE","clip","margin","overflow","position","DEFAULT_HEADERS","dom","targetElement","viewports","templateElement","console","log","target","screens","indexOf","split","push","viewPort","values","insertAdjacentElement","generateViewports","append","generate","getHeaders","rdeHeaders","domReady","frameport","readyState","addEventListener","lazy","frameportObserverTarget","IntersectionObserver","els","observer","intersectionRatio","dataset","frameportTemplate","templateSelector","frameportVh","frameportVw","frameportCss","frameportStyle","frameportCode","frameportJs","frameportClass","frameportHeaders","frameportViewports","innerHTML","templateElementToUse","querySelector","unobserve","querySelectorAll","observe","manual","activate","script","currentScript","frameportScriptSrc","getAttribute","hasAttribute","modes","iframe","remove","elsToBeTransformedTemplate"],"mappings":"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"} \ No newline at end of file From e6e40f8d2b8515972513dbfc2ce9a602b1c41516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Vassbotn=20R=C3=B8yne-Helgesen?= Date: Thu, 19 Oct 2023 22:21:11 +0200 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Use=20a=20doctype=20t?= =?UTF-8?q?o=20avoid=20quirks=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/source.ts b/src/utils/source.ts index 3ff4366..712ef0d 100644 --- a/src/utils/source.ts +++ b/src/utils/source.ts @@ -18,7 +18,7 @@ export const getSource = (options: FrameportOptions): string => { code = getCode(code); style = getStyle(style); - return ` + return ` ${headers.join('\n')} ${style} From 4bcb362b14e88f1b5506c14bd634395642783ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Vassbotn=20R=C3=B8yne-Helgesen?= Date: Thu, 19 Oct 2023 22:22:55 +0200 Subject: [PATCH 7/7] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20update=20docum?= =?UTF-8?q?entation=20example=20regarding=20CSS=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 93ee9b4..b25e571 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ With this approach, the script will locate given template and produce frameports ```html