Skip to content

Commit

Permalink
Google Doodle
Browse files Browse the repository at this point in the history
  • Loading branch information
eagleoflqj committed Jul 30, 2024
1 parent 6233f86 commit b37b66f
Show file tree
Hide file tree
Showing 11 changed files with 296 additions and 0 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: build

on:
push:
branches:
- master
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Use Node.js latest
uses: actions/setup-node@v2
with:
node-version: 22.x

- name: Install node dependencies
run: |
npm i -g pnpm
pnpm i
- name: Lint
run: |
pnpm run lint
- name: Type check
run: |
pnpm run check
- name: Build
run: |
pnpm run build
- name: Package
run: |
pnpm run package
- name: Create Nightly release
uses: marvinpinto/action-automatic-releases@latest
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
automatic_release_tag: latest
prerelease: true
title: Nightly Build
files: |
package/*.zip
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
node_modules
dist
package
pnpm-lock.yaml
49 changes: 49 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,

// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},

// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off", "fixable": true },
{ "rule": "format/*", "severity": "off", "fixable": true },
{ "rule": "*-indent", "severity": "off", "fixable": true },
{ "rule": "*-spacing", "severity": "off", "fixable": true },
{ "rule": "*-spaces", "severity": "off", "fixable": true },
{ "rule": "*-order", "severity": "off", "fixable": true },
{ "rule": "*-dangle", "severity": "off", "fixable": true },
{ "rule": "*-newline", "severity": "off", "fixable": true },
{ "rule": "*quotes", "severity": "off", "fixable": true },
{ "rule": "*semi", "severity": "off", "fixable": true }
],

// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml",
"toml",
"xml",
"gql",
"graphql",
"astro",
"css",
"less",
"scss",
"pcss",
"postcss"
]
}
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Fcitx5 plugin template

This is a template repository for developers to create a plugin for [fcitx5-macos](https://github.com/fcitx-contrib/fcitx5-macos).

## Usage
Start by clicking `Use this template` or cloning the repo.

Follow the commands in [ci.yml](.github/workflows/ci.yml) to generate `package/google-doodle.zip`.

Unzip it under `~/.local/share/fcitx5/www/plugin`, so you get `~/.local/share/fcitx5/www/plugin/google-doodle/{dist, package.json}`.

Enable `google-doodle` and `curl` in `Theme Editor` -> `Advanced`.

Now with international network, you should see today's Google Doodle in scroll mode.

## Note
* When developing your own plugin, remember to change the `name` field in [package.json](package.json). It's the unique identifier of your plugin. Don't use organization namespace.

* APIs can be hooked but may break. Check latest [global.d.ts](src/global.d.ts) here.

* Do read platform's [source code](https://github.com/fcitx-contrib/fcitx5-webview) but don't use APIs undocumented here.

* All plugins must have GPLv3 license noted in [package.json](package.json) in order to be loaded. Don't distribute your plugin if you don't want to share source code.
5 changes: 5 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import antfu from '@antfu/eslint-config'

export default antfu({

})
24 changes: 24 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "google-doodle",
"version": "0.1.0",
"private": true,
"description": "Show today's Google Doodle in scroll mode.",
"license": "GPL-3.0-or-later",
"keywords": [
"fcitx5"
],
"main": "dist/index.js",
"scripts": {
"lint": "eslint src",
"lint:fix": "eslint src --fix",
"check": "tsc --noEmit",
"build": "node scripts/build.mjs",
"package": "node scripts/package.mjs"
},
"devDependencies": {
"@antfu/eslint-config": "^2.24.0",
"esbuild": "^0.23.0",
"eslint": "^9.8.0",
"typescript": "^5.5.4"
}
}
11 changes: 11 additions & 0 deletions scripts/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { build } from 'esbuild'

await build({
entryPoints: ['src/index.ts'],
bundle: true,
outfile: 'dist/index.js',
target: 'es2020',
format: 'iife',
platform: 'browser',
sourcemap: false,
})
20 changes: 20 additions & 0 deletions scripts/package.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// eslint-disable-next-line
import packageJson from '../package.json' with { type: "json" }
import { chdir } from 'process'
import { spawnSync } from 'child_process'
import { rmSync, mkdirSync, cpSync } from 'fs';

const { name } = packageJson

if (name.includes('/')) {
throw new Error('No organization allowed in package name.')
}

const dir = `package/${name}`

rmSync('package', { recursive: true, force: true })
mkdirSync(dir, { recursive: true })
cpSync('dist', `${dir}/dist`, { recursive: true })
cpSync('package.json', `${dir}/package.json`)
chdir('package')
spawnSync('zip', ['-r', `${name}.zip`, name], { stdio: 'inherit' })
60 changes: 60 additions & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Refer to https://github.com/fcitx-contrib/fcitx5-plugin-template/blob/master/src/global.d.ts for latest version.

declare global {
interface CandidateAction {
id: number
text: string
}

interface Candidate {
text: string
label: string
comment: string
actions: CandidateAction[]
}

type SCROLL_STATE = 0 | 1 | 2

interface CurlArgs {
method?: 'GET' | 'POST' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'PUT' | 'PATCH'
headers?: { [key: string]: string }
data?: string // ignored if `json` exists
json?: JSON
binary?: boolean
timeout?: number // milliseconds
}

interface CurlResponse {
status: number
data: string
}

interface FcitxPlugin {
load: () => void
unload: () => void
}

interface Window {
// APIs that can be hooked.
setCandidates: (cands: Candidate[], highlighted: number, markText: string, pageable: boolean, hasPrev: boolean, hasNext: boolean, scrollState: SCROLL_STATE, scrollStart: boolean, scrollEnd: boolean) => void
setLayout: (layout: 0 | 1) => void
updateInputPanel: (preeditHTML: string, auxUpHTML: string, auxDownHTML: string) => void
resize: (dx: number, dy: number, dragging: boolean, hasContextmenu: boolean) => void
setTheme: (theme: 0 | 1 | 2) => void
setAccentColor: (color: number | null) => void
setStyle: (style: string) => void
setWritingMode: (mode: 0 | 1 | 2) => void

// No CORS restriction and all headers are customizable.
curl?: (url: string, args?: CurlArgs) => Promise<CurlResponse>

// Log to stderr.
fcitxLog: (...args: unknown[]) => void

pluginManager: {
register: (plugin: FcitxPlugin) => void
}
}
}

export {}
37 changes: 37 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const id = 'google-doodle'

function load() {
if (!window.curl) {
window.fcitxLog('curl permission is not granted.')
return
}

window.curl('https://doodles.google/').then((res) => {
const html = res.data
const el = document.createElement('html')
el.innerHTML = html
const src = (<HTMLImageElement | null>el.querySelector('.doodle-card-img img'))?.src
if (!src) {
window.fcitxLog('No doodle found.')
return
}

const style = document.createElement('style')
style.id = id
style.innerHTML = `.fcitx-hoverables.fcitx-horizontal-scroll {
background-image: url(https:${src})!important;
background-size: contain;
background-repeat: no-repeat;
}`
document.head.appendChild(style)
})
}

function unload() {
document.head.querySelector(`#${id}`)?.remove()
}

window.pluginManager.register({
load,
unload,
})
13 changes: 13 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"esModuleInterop": true,
"isolatedModules": true
},
"include": ["src/*.ts"]
}

0 comments on commit b37b66f

Please sign in to comment.