s
-
-
Save garrettmac/6a29e16ba03b0b20e915d775b323714a to your computer and use it in GitHub Desktop.
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
ul:not(.browser-default) { | |
padding-left: 0px; | |
list-style-type: none; | |
} | |
} | |
@media screen, projection { | |
.z-depth-1, | |
nav, | |
.card-panel, | |
.card, | |
.toast, | |
.btn, | |
.btn-large, | |
.btn-floating, | |
.dropdown-content, | |
.collapsible, | |
.side-nav { | |
box-shadow: rgba(0, 0, 0, 0.14) 0px 2px 2px 0px, | |
rgba(0, 0, 0, 0.12) 0px 1px 5px 0px, | |
rgba(0, 0, 0, 0.2) 0px 3px 1px -2px; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs { | |
position: relative; | |
overflow-x: auto; | |
overflow-y: hidden; | |
height: 48px; | |
width: 100%; | |
background-color: rgb(255, 255, 255); | |
margin: 0px auto; | |
white-space: nowrap; | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
ul:not(.browser-default) li { | |
list-style-type: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab { | |
display: inline-block; | |
text-align: center; | |
line-height: 48px; | |
height: 48px; | |
padding: 0px; | |
margin: 0px; | |
} | |
} | |
@media screen, projection { | |
a { | |
background-color: transparent; | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
a { | |
color: rgb(3, 155, 229); | |
text-decoration: none; | |
-webkit-tap-highlight-color: transparent; | |
} | |
} | |
@media screen, projection { | |
a { | |
text-decoration: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab a { | |
color: rgba(238, 110, 115, 0.7); | |
display: block; | |
width: 100%; | |
height: 100%; | |
padding: 0px 24px; | |
font-size: 14px; | |
text-overflow: ellipsis; | |
overflow: hidden; | |
transition: color 0.28s ease; | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
ul:not(.browser-default) li { | |
list-style-type: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab { | |
display: inline-block; | |
text-align: center; | |
line-height: 48px; | |
height: 48px; | |
padding: 0px; | |
margin: 0px; | |
} | |
} | |
@media screen, projection { | |
a { | |
background-color: transparent; | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
a { | |
color: rgb(3, 155, 229); | |
text-decoration: none; | |
-webkit-tap-highlight-color: transparent; | |
} | |
} | |
@media screen, projection { | |
a { | |
text-decoration: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab a { | |
color: rgba(238, 110, 115, 0.7); | |
display: block; | |
width: 100%; | |
height: 100%; | |
padding: 0px 24px; | |
font-size: 14px; | |
text-overflow: ellipsis; | |
overflow: hidden; | |
transition: color 0.28s ease; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab a:hover, | |
.redditlabs-tabs .redditlab-tab a.active { | |
background-color: transparent; | |
color: rgb(238, 110, 115); | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
ul:not(.browser-default) li { | |
list-style-type: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab { | |
display: inline-block; | |
text-align: center; | |
line-height: 48px; | |
height: 48px; | |
padding: 0px; | |
margin: 0px; | |
} | |
} | |
@media screen, projection { | |
a { | |
background-color: transparent; | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
a { | |
color: rgb(3, 155, 229); | |
text-decoration: none; | |
-webkit-tap-highlight-color: transparent; | |
} | |
} | |
@media screen, projection { | |
a { | |
text-decoration: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab a { | |
color: rgba(238, 110, 115, 0.7); | |
display: block; | |
width: 100%; | |
height: 100%; | |
padding: 0px 24px; | |
font-size: 14px; | |
text-overflow: ellipsis; | |
overflow: hidden; | |
transition: color 0.28s ease; | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
ul:not(.browser-default) li { | |
list-style-type: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab { | |
display: inline-block; | |
text-align: center; | |
line-height: 48px; | |
height: 48px; | |
padding: 0px; | |
margin: 0px; | |
} | |
} | |
@media screen, projection { | |
a { | |
background-color: transparent; | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
a { | |
color: rgb(3, 155, 229); | |
text-decoration: none; | |
-webkit-tap-highlight-color: transparent; | |
} | |
} | |
@media screen, projection { | |
a { | |
text-decoration: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .redditlab-tab a { | |
color: rgba(238, 110, 115, 0.7); | |
display: block; | |
width: 100%; | |
height: 100%; | |
//padding: 0px 24px; | |
font-size: 14px; | |
text-overflow: ellipsis; | |
overflow: hidden; | |
transition: color 0.28s ease; | |
} | |
} | |
@media screen, projection { | |
*, ::before, ::after { | |
box-sizing: inherit; | |
} | |
} | |
@media screen, projection { | |
ul:not(.browser-default) li { | |
list-style-type: none; | |
} | |
} | |
@media screen, projection { | |
.redditlabs-tabs .reddit-labs-indicator { | |
position: absolute; | |
bottom: 0px; | |
height: 2px; | |
background-color: rgb(246, 178, 181); | |
will-change: left, right; | |
} | |
} |
How to Build A Chrome Extension: Part 2
Understanding the Chrome API's chrome.*
functions.
This is Part 2 of my X Part Tutorial if you need an overview of Project Concepts, Structure, and Terminology check out my Part 1 of this Tutorial.
There are [TODO:HOW MANY] chrome.*
actions (functions) that you have access to and I'm going to give a ELI5 definition for all of them and tell you what they all do.
Notice: If you followed the docs and example and your function is not working as expected then you likely have a permissions issue from not setting up your manifest.json
correctly and may need to revisit Part 1
Be aware (as noted in Part 1)
Now that that's understood lets hope right onto each chrome.*
methods.
chrome.extension
Use to communicate between compoents and resolve urls of extinsion files.
chrome.browserActions
Change's the appearance of your Chrome Extensions Icon.
This includes:
- The badge that displays on your Extension Icon
- Your Extensions Icon Image (yes you can change it dynamically)
Read more about this in the below, Lessons Learned Section.
chrome.pageActions
Use to enable or disable pageActions
chrome.window
Requires tabs
permission in manifest.json
This enables the ability to open, close, search for, or update your browser windows.
Side note: You would think this would require a window
permission but they don't have one, it's tabs
because of how close the window
and tab
functions are in functionality, so close in-fact the Chrome Team should depreciate the window
function and attach it to the chrome.tabs
functions.
chrome.tabs
Requires tabs
permission in manifest.json
This manages all instances of all windows and all tabs in all window.
chrome.bookmarks
Requires bookmarks
permission in manifest.json
This manages users bookmarks.
Helpful Functions
- Get a full list of all chrome tabs you can run.
chrome.tabs.query({}, function(tabs){
console.warn("tabs",tabs);
});
This will spit out an array of all chrome tabs, include each tabs windowId
and tabId
.
- Change the badges background color:
chrome.browserAction.setBadgeBackgroundColor({
color:[255,255,255,.5]
})
. :
- Send Message from background.html to popup.html:
Add a listenter in your React App
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
console.warn(" From Injected Page: ",request.msg);//outputs => "Here's my message!"
sendResponse({ msg: 'got message successfully! Thax!' });
});
in your injected page
chrome.extension.sendMessage({ "msg":"Here's my message!" }, function(resp) {
console.warn("Sent MESSAGE callback mssg",store);
//outputs -> 'got message successfully! Thax!'
});
- Send Logs from Extension Window (React Side) to Background.html:
in react app
function consoleLog(msg){
chrome.extension.sendMessage({ "method":"log","data":msg });
}
consoleLog("my message")
now add a listener in your background,js
chrome.extension.onMessage.addListener(function(req, sender, sendResponse) {
if(req.method==="log")console.warn("Message From React App: ",req.data);
});
for more on messaging checkout https://developer.chrome.com/extensions/messaging
Lessons Learned
I felt comfortable with javascript and always wanted to build a chrome extension so dedicated a 1.5 to building one and the one most annoying issue that held me up was with the browser_action
object I declared in my manifest.json
no enabling the chrome.browserAction.setBadgeText
to trigger.
I was trying to change the extensions Icon based on Reddit API I made for each Tab, the Chrome Extension that checks if each page you visit has been posted on reddit before, if it has then is should display what they are with a badge that include the count, and update the Icon with a Reddit Aliens face that meets the emotion with the results, so for no results the alien has a "IDK shrug face", and my manifest.json
looked like
"browser_action": {
"default_title": "RedditLabs",
"default_popup": "popup.html"
},
"icons": {
"16": "img/reddit-icon-7-16X16.png",
"48": "img/reddit-icon-7-48X48.png",
"128": "img/icon-128.png"
},
I gave permissions to my Icons but not in the correct place, I need it to look like:
"browser_action": {
"default_title": "RedditLabs",
"default_popup": "popup.html",
"default_icon": {
"16": "img/icon-16.png",
"48": "img/Icon-48.png",
"128": "img/icon-128.png"
}
},
"icons": {
"16": "img/reddit-icon-7-16X16.png",
"48": "img/reddit-icon-7-48X48.png",
"128": "img/icon-128.png"
},
I need to give the browser_action
object a default_icon
with a default Icon or it disable me from being able to update my Badge by running:
chrome.browserAction.setBadgeText({ text: currentTabPosts.length.toString() });
Note: Badges text must be strings
and not numbers, you can use [your number].toString()
like I did above.
The icons
at the root of the manifest.json
object is used for the image shown in the chrome://extensions
tab of your browser.
How to Build A Chrome Extension: Part 3
How and Where to call Third Party APIs
Here we are going make a chrome extension that displays a window with a list of the Reddit Subreddit that the user's current url tab has been posted on.
So for chrome to enable us to have access to the users tab
instances, and we want to make reddit api calls we need to add the following permission to our manifest.json
{
"permissions":["tabs","https://www.reddit.com/*","http://www.reddit.com/"]
}
Here we want a subwindow to display when when a user clicks our extension we are going to need to declare a browser_action
inside our manifest.json
and lets tell it to load our popup.html
file when the user clicks the icon. We can do that by adding the following browser_action
object inside our manifest.json
file.
"browser_action": {
"default_title": "RedditLabs",
"default_popup": "popup.html",
"default_icon":"img/default-icon.png"
},
So you're prolly asking, "where does the logic to make Reddit API calls go?" because I did.
We'll you can load in .js
files into the popup.html
file defined in our manifests.json
file and that will work just fine, however you should use the background.js script for this that you can declare in your manifest.json
browser_action
object by adding
`background_page`:`background.html`
Let me clear up some things that may be confusing when looking at this. The background page is in .html
but is not attached to your apps DOM Events
.
Here the popup.html
file will simply be a dumb view, only able to accept parameters from the background.html
that we'll set up to do the heaving lifting, ergo making the our Reddit API Calls.
To enable the popup.html
to awuire parameters from our background worker page we need to add the following refrence to our popup.html
const worker = chrome.extension.getBackgroundPage()
You now have access to the full scope of functions of any script tag loaded into the background.html
. For instance if the background.html
page includes:
<html>
<script>
function foo(param){
console.log("foo: ", param)
}
</script>
</html>
then in our popup.html
page we can access it by:
const worker = chrome.extension.getBackgroundPage()
worker.foo("bar")
So knowing that lets enable us into being able to access the console
object in our worker page inside our popup.html
page, to do this we add the following to our background.html
<html>
<script>
function chromeConsole(type="log",msg){
return {type:"log",msg}
}
</script>
</html>
Then use chromeConsole()
unstead of console.log()
and add
worker.chromeConsole(type="log",msg){
console[type](msg)
}
to get them to emit to our popup.html page.
Things
Redditlabs Chrome Extension
A Chrome Extension that includes reddit.com's comment section into each page you visit
Project Overview
Project File Structure:
dist/ | (where `src` folders build -setup in gulfile.babel.js)
src/ | (working directories)
popup/
content/
event/
gulpfile.babel.js | (compiles and reallocates output files in `dist` folder)
To start run:
gulp watch
See blog post
How to Build A Chrome Extension: Part 1
The Basics. Working with Project Concepts, Structure, and Terminology.
A bird's eye overview.
Chrome extensions are web friendly files (
js
,html
andcss
) that get injected into your browser to, as you know, add functionality to your browser.These extensions are uniquely identified with a 32 characters [a-z] string, and if you're a proud Mac owner then your chrome extensions are located at
/Users/$(whoami)/Library/Application\ Support/Google/Chrome/Default/Extensions
and if you're a Mac owner and not a proud one then you can GTFO.How it works.
I wanna start by introducing the
manifest.json
file (as I will be mentioning it throughout). All projects have a file that must be namedmanifest.json
. This is a special file that chrome looks for to grant permssions to your app located at the root of your Chrome Extensions folders (so again, that would be located at/Users/$(whoami)/Library/Application\ Support/Google/Chrome/Default/Extensions/<YOUR EXTENSIONS a-z ID]/manifest.json
). If you are pulling your hair out asking "Why is Chrome not recognizing mychrome.*
action? I'm doing exactly what their doc's say!", then it's likely a problem that starts here.Now let's hope right into.
There are two UI system you can utilize as a developer when building your chrome extension Browser Actions and Page Actions and you'd best plan which route you'd like to ultimately go as you can only use one or the other!
So what is this liberal bullsh*t you ask?
Browser Actions
Declared as
browser_actions
in yourmanifest.json
.Include every permission you want the
chrome.browserActions
scope to have, in Part 2 I'll share an annoying experience I had with this one and how I fixed it in part 2.The
browser_actions
object, that is a nested object inside themanifest.json
file includes the following child attributes/keys:default_title
- What appears when the users mouse hovers over your Chrome Extensiondefault_popup
- The.html
file location of the page you'd like to be displayed when the user clicks your icondefault_icon
- A string or object of a default icon for your extension.String Example:
Object Example:
A completed Example of the nested
browser_action
object insidemanifest.json
would look like:Page Actions
Declared as
page_actions
in yourmanifest.json
.Once you decide which route your going then you'll have some of the following functionality declared in your
manifest.json
file that include the use of the following:Content Scripts
Declared as
content_scripts
in yourmanifest.json
Any arbitrary
.js
and.css
files (scripts) that youd like to be injected into pages.When to use this?
When you want to create your own modded out version of what you think a web page would look like.
When you want to create your own modded out functionality to a webpage, for instance if you wanted to add spechail buttons or hover actions (like the popular Hover Zoom Extinsion
See the Chrome Stores Personalize Chrome Section for example of this.
Background Pages
Declared as
background_pages
in yourmanifest.json
This runs all the time even when you have no tabs or windows open.
This is assuming Chrome is in-fact running.
This is where you want your Apps core logic to go, for persistence.
Long running scripts that manage state and apply tasks across your apps components.
Popup Page