Skip to content

Commit

Permalink
Create content-svelte template
Browse files Browse the repository at this point in the history
  • Loading branch information
cezaraugusto committed Dec 23, 2024
1 parent 1894c07 commit b9a7f17
Show file tree
Hide file tree
Showing 20 changed files with 382 additions and 0 deletions.
31 changes: 31 additions & 0 deletions examples/content-svelte/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules

# testing
coverage

# production
dist

# misc
.DS_Store

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# lock files
yarn.lock
package-lock.json

# debug files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# extension.js
extension-env.d.ts
1 change: 1 addition & 0 deletions examples/content-svelte/background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello from the background script!')
90 changes: 90 additions & 0 deletions examples/content-svelte/content/ContentApp.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<script lang="ts">
let isDialogOpen = true;
function setIsDialogOpen(value: boolean) {
isDialogOpen = value;
}
</script>

{#if isDialogOpen}
<div>
<div class="mx-auto max-w-7xl md:px-0 lg:p-6">
<div
class="relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl lg:rounded-3xl md:pt-24 md:h-full sm:h-[100vh] lg:flex lg:gap-x-20 lg:px-24 lg:pt-0"
>
<div
class="absolute z-20 top-0 inset-x-0 flex justify-center overflow-hidden pointer-events-none"
>
<div class="w-[108rem] flex-none flex justify-end">
<picture>
<img
src="../images/tailwind_bg.png"
alt=""
class="w-[90rem] flex-none max-w-none hidden dark:block"
decoding="async"
/>
</picture>
</div>
</div>
<div
class="mx-auto max-w-md text-center lg:py-12 lg:mx-0 lg:flex-auto lg:text-left"
>
<div
class="flex items-center justify-center space-x-4 my-4 mx-auto"
>
<img
alt="Svelte logo"
src="../images/logo.svg"
class="relative inline-block w-12"
/>
<div class="text-3xl text-white">+</div>
<img
alt="TypeScript logo"
src="../images/typescript.png"
class="relative inline-block w-12"
/>
<div class="text-3xl text-white">+</div>
<img
alt="Tailwind logo"
src="../images/tailwind.png"
class="relative inline-block w-12"
/>
</div>
<h2
class="text-3xl font-bold tracking-tight text-white sm:text-4xl"
>
This is a content script running Svelte, TypeScript, and Tailwind.css
</h2>
<p class="mt-6 text-lg leading-8 text-gray-300">
Learn more about creating cross-browser extensions by
<button
on:click={() => setIsDialogOpen(false)}
class="underline hover:no-underline"
>
closing this hint
</button>
.
</p>
</div>
<div class="relative mt-16 h-80 lg:mt-8">
<img
class="absolute left-0 top-0 w-[57rem] max-w-none rounded-md bg-white/5 ring-1 ring-white/10"
src="../images/chromeWindow.png"
alt="Chrome window screenshot"
width="1824"
height="1080"
/>
</div>
</div>
</div>
</div>
{:else}
<div class="mx-auto p-6">
<button
on:click={() => setIsDialogOpen(true)}
class="bg-white rounded-md p-3 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
>
🧩 Open content script hint <span aria-hidden="true">+</span>
</button>
</div>
{/if}
36 changes: 36 additions & 0 deletions examples/content-svelte/content/scripts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as svelte from 'svelte'
import ContentApp from './ContentApp.svelte'
import './styles.css?inline_style'

function initial() {
// Create a new div element and append it to the document's body
const rootDiv = document.createElement('div')
rootDiv.id = 'extension-root'
document.body.appendChild(rootDiv)

// Inject content_scripts inside a shadow DOM
// to prevent conflicts with the host page's styles.
const shadowRoot = rootDiv.attachShadow({mode: 'open'})

// @ts-expect-error - global reference.
window.__EXTENSION_SHADOW_ROOT__ = shadowRoot

// Create a container inside the shadow DOM for the Vue app
const shadowAppContainer = document.createElement('div')
shadowAppContainer.className = 'content_script'
shadowRoot.appendChild(shadowAppContainer)

// Mount the Vue app to the container inside the shadow DOM
svelte.mount(ContentApp, {
target: shadowAppContainer
})
}

// Initialize the app
if (document.readyState === 'complete') {
initial()
} else {
document.addEventListener('readystatechange', () => {
if (document.readyState === 'complete') initial()
})
}
10 changes: 10 additions & 0 deletions examples/content-svelte/content/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

.content_script {
position: fixed;
bottom: 0;
right: 0;
z-index: 99999;
}
Binary file added examples/content-svelte/images/chromeWindow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/content-svelte/images/extension_48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions examples/content-svelte/images/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/content-svelte/images/tailwind.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/content-svelte/images/tailwind_bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/content-svelte/images/typescript.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions examples/content-svelte/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "https://json.schemastore.org/chrome-manifest.json",
"manifest_version": 3,
"version": "0.0.1",
"name": "Content Scripts Svelte",
"description": "An Extension.js example.",
"icons": {
"48": "images/extension_48.png"
},
"permissions": ["activeTab", "scripting"],
"host_permissions": ["<all_urls>"],
"background": {
"chromium:service_worker": "background.ts",
"firefox:scripts": ["background.ts"]
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content/scripts.ts"]
}
]
}
20 changes: 20 additions & 0 deletions examples/content-svelte/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"private": true,
"name": "new-svelte",
"description": "An Extension.js example.",
"version": "0.0.1",
"author": {
"name": "Cezar Augusto",
"email": "boss@cezaraugusto.net",
"url": "https://cezaraugusto.com"
},
"license": "MIT",
"dependencies": {
"svelte": "5.15.0",
"tailwindcss": "^3.4.1"
},
"devDependencies": {
"@tsconfig/svelte": "5.0.4",
"typescript": "5.3.3"
}
}
6 changes: 6 additions & 0 deletions examples/content-svelte/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
}
Binary file added examples/content-svelte/public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/content-svelte/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions examples/content-svelte/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['**/*.svelte'],
theme: {
extend: {}
},
plugins: []
}
84 changes: 84 additions & 0 deletions examples/content-svelte/template.spec copy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import path from 'path'
import {execSync} from 'child_process'
import {extensionFixtures, getShadowRootElement} from '../extension-fixtures'

const exampleDir = 'examples/content-vue'
const pathToExtension = path.join(__dirname, `dist/chrome`)
const test = extensionFixtures(pathToExtension, true)

test.beforeAll(async () => {
execSync(`pnpm extension build ${exampleDir}`, {
cwd: path.join(__dirname, '..')
})
})

test('should exist an element with the class name extension-root', async ({
page
}) => {
await page.goto('https://extension.js.org/')
const shadowRootHandle = await page
.locator('#extension-root')
.evaluateHandle((host: HTMLElement) => host.shadowRoot)

// Validate that the Shadow DOM exists
test.expect(shadowRootHandle).not.toBeNull()

// Verify Shadow DOM has children
const shadowChildrenCount = await shadowRootHandle.evaluate(
(shadowRoot: ShadowRoot) => shadowRoot.children.length
)
test.expect(shadowChildrenCount).toBeGreaterThan(0)
})

test('should exist an h2 element with specified content', async ({page}) => {
await page.goto('https://extension.js.org/')
const h2 = await getShadowRootElement(page, '#extension-root', 'h2')
if (!h2) {
throw new Error('h2 element not found in Shadow DOM')
}
const textContent = await h2.evaluate((node) => node.textContent)
await test
.expect(textContent)
.toContain(
'This is a content script running Vue, TypeScript, and Tailwind.css.'
)
})

test('should exist a default color value', async ({page}) => {
await page.goto('https://extension.js.org/')
const h2 = await getShadowRootElement(page, '#extension-root', 'h2')
if (!h2) {
throw new Error('h2 element not found in Shadow DOM')
}
const color = await h2.evaluate((node) =>
window.getComputedStyle(node as HTMLElement).getPropertyValue('color')
)
test.expect(color).toEqual('rgb(255, 255, 255)')
})

test('should load all images successfully', async ({page}) => {
await page.goto('https://extension.js.org/')
const shadowRootHandle = await page
.locator('#extension-root')
.evaluateHandle((host: HTMLElement) => host.shadowRoot)

const imagesHandle = await shadowRootHandle.evaluateHandle(
(shadow: ShadowRoot) => Array.from(shadow.querySelectorAll('img'))
)

const imageHandles = await imagesHandle.getProperties()
const results: boolean[] = []

for (const [, imageHandle] of imageHandles) {
const naturalWidth = await imageHandle.evaluate(
(img) => (img as HTMLImageElement).naturalWidth
)
const naturalHeight = await imageHandle.evaluate(
(img) => (img as HTMLImageElement).naturalHeight
)
const loadedSuccessfully = naturalWidth > 0 && naturalHeight > 0
results.push(loadedSuccessfully)
}

test.expect(results.every((result) => result)).toBeTruthy()
})
43 changes: 43 additions & 0 deletions examples/content-svelte/template.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import path from 'path'
import {execSync} from 'child_process'
import {extensionFixtures, takeScreenshot} from '../extension-fixtures'

const exampleDir = 'examples/new-svelte'
const pathToExtension = path.join(__dirname, `dist/chrome`)
const test = extensionFixtures(pathToExtension, true)

test.beforeAll(async () => {
execSync(`pnpm extension build ${exampleDir}`, {
cwd: path.join(__dirname, '..')
})
})

test('should exist an element with the welcome message text', async ({
page
}) => {
await page.goto('chrome://newtab/')
const h1 = await page.waitForSelector('h1', {
state: 'visible',
timeout: 10000
})
const textContent = await h1.textContent()
test.expect(textContent).toMatch(/Welcome to your/i)
})

test('should exist a default color value', async ({page}) => {
await page.goto('chrome://newtab/')
const h1 = page.locator('h1')
const color = await page.evaluate(
(locator) => {
return window.getComputedStyle(locator!).getPropertyValue('color')
},
await h1.elementHandle()
)
test.expect(color).toEqual('rgb(201, 201, 201)')
})

test.skip('takes a screenshot of the page', async ({page}) => {
await page.goto('chrome://newtab/')
await page.waitForSelector('h1')
await takeScreenshot(page, path.join(__dirname, 'screenshot.png'))
})
23 changes: 23 additions & 0 deletions examples/content-svelte/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "esnext"],
"moduleResolution": "node",
"module": "esnext",
"noEmit": true,
"resolveJsonModule": true,
"strict": true,
"target": "esnext",
"verbatimModuleSyntax": true,
"useDefineForClassFields": true,
"skipLibCheck": true
},
"include": ["./", "extension-env.d.ts"],
"exclude": ["node_modules", "dist"]
}

0 comments on commit b9a7f17

Please sign in to comment.