A chrome extension that replaces the new tab.
Download ext.crx
and plugins.zip
from here.
Go to chrome://extensions
in your browser, then drag ext.crx
inside.
Navigate to the settings page to add buttons, plugins, and themes.
IMPORTANT: Chrome 35 and above disallow installation of non-webstore extensions. See this for possible workarounds.
Run npm install
then gulp pack
, and the extension can be found packed in the ./build/dist
directory, or unpacked in the ./build/src
directory.
- Run
npm init
in the plugin's folder and fill out the info - Use
npm install --save
to add your dependencies - Create a
package.json
like the one described below - Run the bundler (
node bundler.js
), with the first argument the plugin folder, and the second a path to write the compiled plugin file to
main
: the main page, the 'new tab'settings
: the extension's options pageglobal
: matches any view
Any of these can access a plugin api object called api
.
main
: runs on the main viewsettings
: runs on the settings viewglobal
: runs on any view, but before the view-specific hookinit
: is executed only on plugin install/update
api.setting(settingName)
: get value of specified setting, or its default if it's unsetapi.insertStyle(css)
: insert the given css string into an inline style elementapi.registerAction(displayName, actionPathname, handler)
: register a handler for a custom button action. Run this in theglobal
hookapi.insertView(htmlElement, order, alignment)
: (only in themain
hook) insert a view to the default activity.alignment
can beleft
,center
orright
.order
is the order within each alignment, and it maps to the css propertyorder
api.pushActivity(activityName, htmlElement)
: (only in themain
hook) navigate to another activity. When called, the current activity's element will be hidden, the given element will be shown, theactivityName
will replace the tab title and navbar title, and a button to navigate back appears in the navbarapi.popActivity()
: (only in themain
hook) hide current activity, and show previous one. If the default activity is shown, this function is a no-op
This file is used by npm
and by the bundler. Paths are relative to the package.json
's directory.
{
"pluginName": "displayName",
"description": "message",
"author": "name",
"version": "1.1.1",
"settings": [],
"dependencies": {},
"webpackConfig": "path/to/webpack.config",
"html": {
"main": {
"path/to/file1.html": "querySelector1",
"path/to/file2.html": "querySelector2"
...
},
"settings": {
"path/to/file1.html": "querySelector1",
"path/to/file2.html": "querySelector2"
...
},
"global": {
"path/to/file1.html": "querySelector1",
"path/to/file2.html": "querySelector2"
...
}
},
"css": {
"main": ["path/to/file1.css", "path/to/file2.css", ...],
"settings": ["path/to/file3.css", "path/to/file4.css", ...],
"global": ["path/to/file5.css", "path/to/file6.css", ...]
},
"js": {
"main": "path/to/file1.js",
"settings": "path/to/file2.js",
"global": "path/to/file3.js",
"init": "path/to/file4.js"
}
}
pluginName
: (string) name of plugindescription
: (string) plugin descriptionauthor
: (string) self-explanatoryversion
: (string) semver version stringsettings
: (array of objects) setting format described below. Setting values are preserved during updates only if thename
andtype
properties are unchangeddependencies
: (object) npm's dependencies fieldwebpackConfig
: (path string) path to a webpack config to be require'd. Theentry
andoutput
properties are handled by the bundlerhtml
: (object) each property represents a view. For each view, there are html files associated with a query selector. The html will be inserted in the element obtained from the selectorcss
: (object) each property represents a view. The css files for each view are concatenated, and the merged data is appended to an inline stylesheet after the html has been insertedjs
: (object) each property represents a hook. The js at the specified path for each hook is an entry point for webpack
Themes are just JSON files:
{
"name": "Default Theme",
"isDark": false,
"background": "#FAFAFA",
"main": "#FF9800",
"accent": "#B2FF59",
"deleted": undefined
}
name
: (string) name of themeisDark
: (boolean) whether or not the theme should be considered "dark", as dark themes trigger light styles for some elements/textbackground
,main
,accent
: (css color strings) base colors for the UIdeleted
: (optional boolean) if true, it signals that this theme was "deleted" by the user; this element will be removed before saving to storage
Usually, this is to be generated by the bundler from the package.json
above. This should be valid JSON.
{
"name": "displayName",
"desc": "message",
"author": "name",
"version": "1.1.1",
"settings": [],
"js": {
"init": "(function (api) {})()",
"global": "(function (api) {})()",
"main": "(function (api) {})()",
"settings": "(function (api) {})()"
},
"css": {
"main": "cssText",
"settings": "cssText",
},
"html": {
"main": {
"querySelector": "htmlToAdd"
...
},
"settings": {
"querySelector": "htmlToAdd"
...
}
},
"deleted": undefined
}
name
: (string) see above, is equivalent topluginName
desc
: (string) see above, is equivalent todescription
author
: (string) see aboveversion
: (semver string) see abovesettings
: (array of setting objects) see abovejs
: (object) all functions are stringified IIFEs, each property is a hookcss
: (object) the css from each property will be added to it's respective viewhtml
: (object of objects) every property targets a view. For every view,htmlToAdd
will be added at the position specified by thequerySelector
. There can be multiplequerySelector
sdeleted
: (optional boolean) if true, it signals that this plugin was "deleted" by the user; this element will be removed before saving to storage
{
"name": "displayName",
"desc": "message",
"type": "type",
"valid": [],
"default": "",
"value": undefined,
"isVisible": true
}
name
: (string) title of settingdesc
: (optional string) description of settingtype
: (enum string) input types, orenum
valid
: (array of objects) iftype
isenum
, this is a list of objects with aname
and avalue
property, otherwise not defineddefault
: (any) if the value is not set, this value should be used as a defaultvalue
: (any) undefined until setisVisible
: (boolean) if false, it means this 'setting' is just storage
{
"kind": "default",
"pictureType": "image",
"imagePath": "http://example.com",
"ligatureName": "",
"href": "http://example.com",
"text": "Button",
"position": 3.14,
"hotkey": "K",
"deleted": undefined
}
kind
: (enum string) what kind of "button" it is; values aredefault
,divider
,subheader
pictureType
: (enum string) if it isimage
, use theimagePath
, if it isicon
useligatureName
imagePath
: (uri string) path to imageligatureName
: (string) name of material iconhref
: (uri string) where does it point totext
: (string) displyed textposition
: (float) used to determine order of buttonshotkey
: (string) using alt+key triggers the buttondeleted
: (optional boolean) if true, it signals that this button was "deleted" by the user; this element will be removed before saving to storage
This API is used in /plugins/reddit/main.js.
The page will perform GET requests for the user data associated with the given username.