cleanup scripts

This commit is contained in:
Jeremy Danyow 2017-05-03 08:11:51 -07:00
parent 985f355d6b
commit f2c3bf9548
No known key found for this signature in database
GPG Key ID: 96C45DE6B2C1DF40
45 changed files with 284 additions and 3333 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
node_modules
debug
dist
output
chrome

42
.yarnclean Normal file
View File

@ -0,0 +1,42 @@
# test directories
__tests__
test
tests
powered-test
# asset directories
docs
doc
website
images
assets
# examples
example
examples
# code coverage directories
coverage
.nyc_output
# build scripts
Makefile
Gulpfile.js
Gruntfile.js
# configs
.tern-project
.gitattributes
.editorconfig
.*ignore
.eslintrc
.jshintrc
.flowconfig
.documentup.json
.yarn-metadata.json
.*.yml
*.yml
# misc
*.gz
*.md

View File

38
dist/client.debug.js vendored
View File

@ -1,38 +0,0 @@
(function () {
'use strict';
function param(obj) {
var parts = [];
for (var name_1 in obj) {
if (obj.hasOwnProperty(name_1)) {
parts.push(encodeURIComponent(name_1) + "=" + encodeURIComponent(obj[name_1]));
}
}
return parts.join('&');
}
var script = document.currentScript;
var attrs = {};
for (var i = 0; i < script.attributes.length; i++) {
var attribute = script.attributes.item(i);
attrs[attribute.name] = attribute.value;
}
attrs.url = location.href;
attrs.origin = location.origin;
attrs.pathname = location.pathname.substr(1).replace(/\.\w+$/, '');
attrs.title = document.title;
var descriptionMeta = document.querySelector("meta[name='description']");
attrs.description = descriptionMeta ? descriptionMeta.content : '';
document.head.insertAdjacentHTML('afterbegin', "<style>\n .utterances {\n position: relative;\n width: 100%;\n }\n .utterances-frame {\n position: absolute;\n left: 0;\n right: 0;\n width: 1px;\n min-width: 100%;\n max-width: 100%;\n height: 100%;\n border: 0;\n }\n </style>");
var url = script.src.replace(/\/client(\.debug)?\.js(?:$|\?)/, '/utterances$1.html');
script.insertAdjacentHTML('afterend', "<div class=\"utterances\">\n <iframe class=\"utterances-frame\" scrolling=\"no\" src=\"" + url + "?" + param(attrs) + "\"></iframe>\n </div>");
var container = script.nextElementSibling;
script.parentElement.removeChild(script);
addEventListener('message', function (event) {
var data = event.data;
if (data && data.type === 'resize' && data.height) {
container.style.height = data.height + "px";
}
});
}());

1
dist/client.js vendored
View File

@ -1 +0,0 @@
!function(){"use strict";function e(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(encodeURIComponent(n)+"="+encodeURIComponent(e[n]));return t.join("&")}for(var t=document.currentScript,n={},r=0;r<t.attributes.length;r++){var i=t.attributes.item(r);n[i.name]=i.value}n.url=location.href,n.origin=location.origin,n.pathname=location.pathname.substr(1).replace(/\.\w+$/,""),n.title=document.title;var a=document.querySelector("meta[name='description']");n.description=a?a.content:"",document.head.insertAdjacentHTML("afterbegin","<style>\n .utterances {\n position: relative;\n width: 100%;\n }\n .utterances-frame {\n position: absolute;\n left: 0;\n right: 0;\n width: 1px;\n min-width: 100%;\n max-width: 100%;\n height: 100%;\n border: 0;\n }\n </style>");var o=t.src.replace(/\/client(\.debug)?\.js(?:$|\?)/,"/utterances$1.html");t.insertAdjacentHTML("afterend",'<div class="utterances">\n <iframe class="utterances-frame" scrolling="no" src="'+o+"?"+e(n)+'"></iframe>\n </div>');var s=t.nextElementSibling;t.parentElement.removeChild(t),addEventListener("message",function(e){var t=e.data;t&&"resize"===t.type&&t.height&&(s.style.height=t.height+"px")})}();

1020
dist/index.css vendored

File diff suppressed because it is too large Load Diff

2
dist/index.html vendored

File diff suppressed because one or more lines are too long

127
dist/index.js vendored
View File

@ -1,127 +0,0 @@
(function () {
'use strict';
var Token = (function () {
function Token() {
this.storageKey = 'OAUTH_TOKEN';
}
Object.defineProperty(Token.prototype, "value", {
get: function () {
return localStorage.getItem(this.storageKey);
},
set: function (newValue) {
if (newValue === null) {
localStorage.removeItem(this.storageKey);
}
else {
localStorage.setItem(this.storageKey, newValue);
}
},
enumerable: true,
configurable: true
});
return Token;
}());
var token = new Token();
function decodeBase64UTF8(encoded) {
encoded = encoded.replace(/\s/g, '');
return decodeURIComponent(escape(atob(encoded)));
}
var GITHUB_API = 'https://api.github.com/';
var GITHUB_ENCODING__HTML = 'application/vnd.github.VERSION.html';
var GITHUB_ENCODING__REACTIONS_PREVIEW = 'application/vnd.github.squirrel-girl-preview';
var owner;
var repo;
var branch;
function setRepoContext(context) {
owner = context.owner;
repo = context.repo;
branch = context.branch;
}
function githubRequest(relativeUrl, init) {
init = init || {};
init.mode = 'cors';
init.cache = 'no-cache';
var request = new Request(GITHUB_API + relativeUrl, init);
request.headers.set('Accept', GITHUB_ENCODING__REACTIONS_PREVIEW);
if (token.value !== null) {
request.headers.set('Authorization', "token " + token.value);
}
return request;
}
var rateLimit = {
standard: {
limit: Number.MAX_VALUE,
remaining: Number.MAX_VALUE,
reset: 0
},
search: {
limit: Number.MAX_VALUE,
remaining: Number.MAX_VALUE,
reset: 0
}
};
function processRateLimit(response) {
var limit = response.headers.get('X-RateLimit-Limit');
var remaining = response.headers.get('X-RateLimit-Remaining');
var reset = response.headers.get('X-RateLimit-Reset');
var isSearch = /\/search\//.test(response.url);
var rate = isSearch ? rateLimit.search : rateLimit.standard;
rate.limit = +limit;
rate.remaining = +remaining;
rate.reset = +reset;
if (response.status === 403 && rate.remaining === 0) {
var resetDate = new Date(0);
resetDate.setUTCSeconds(rate.reset);
var mins = Math.round((resetDate.getTime() - new Date().getTime()) / 1000 / 60);
var apiType = isSearch ? 'search API' : 'non-search APIs';
console.warn("Rate limit exceeded for " + apiType + ". Resets in " + mins + " minute" + (mins === 1 ? '' : 's') + ".");
}
}
function githubFetch(request) {
return fetch(request).then(function (response) {
if (response.status === 401) {
token.value = null;
}
processRateLimit(response);
return response;
});
}
function loadJsonFile(path, html) {
if (html === void 0) { html = false; }
var request = githubRequest("repos/" + owner + "/" + repo + "/contents/" + path + "?ref=" + branch);
if (html) {
request.headers.set('accept', GITHUB_ENCODING__HTML);
}
return githubFetch(request).then(function (response) {
if (response.status === 404) {
throw new Error("Repo \"" + owner + "/" + repo + "\" does not have a file named \"" + path + "\" in the \"" + branch + "\" branch.");
}
if (!response.ok) {
throw new Error("Error fetching " + path + ".");
}
return html ? response.text() : response.json();
}).then(function (file) {
if (html) {
return file;
}
var content = file.content;
var decoded = decodeBase64UTF8(content);
return JSON.parse(decoded);
});
}
var context = {
owner: 'utterance',
repo: 'utterances',
branch: 'master'
};
setRepoContext(context);
loadJsonFile('README.md', true).then(function (html) {
var commentDiv = document.querySelector('.comment');
commentDiv.insertAdjacentHTML('beforeend', html);
});
}());

1186
dist/utterances.css vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

660
dist/utterances.js vendored
View File

@ -1,660 +0,0 @@
(function () {
'use strict';
function deparam(query) {
var match;
var plus = /\+/g;
var search = /([^&=]+)=?([^&]*)/g;
var decode = function (s) { return decodeURIComponent(s.replace(plus, ' ')); };
var params = {};
while (match = search.exec(query)) {
params[decode(match[1])] = decode(match[2]);
}
return params;
}
function param(obj) {
var parts = [];
for (var name_1 in obj) {
if (obj.hasOwnProperty(name_1)) {
parts.push(encodeURIComponent(name_1) + "=" + encodeURIComponent(obj[name_1]));
}
}
return parts.join('&');
}
function readPageAttributes() {
var params = deparam(location.search.substr(1));
var issueTerm = null;
var issueNumber = null;
if ('issue-term' in params) {
issueTerm = params['issue-term'];
if (issueTerm !== undefined) {
if (issueTerm === '') {
throw new Error('When issue-term is specified, it cannot be blank.');
}
if (['title', 'url', 'pathname'].indexOf(issueTerm) !== -1) {
issueTerm = params[issueTerm];
}
}
}
else if ('issue-number' in params) {
issueNumber = +params['issue-number'];
if (issueNumber.toString(10) !== params['issue-number']) {
throw new Error("issue-number is invalid. \"" + params['issue-number']);
}
}
else {
throw new Error('Invalid query string arguments. Either "issue-term" or "issue-number" must be specified.');
}
if (!('repo' in params)) {
throw new Error('Invalid query string arguments. "repo" is required.');
}
if (!('origin' in params)) {
throw new Error('Invalid query string arguments. "origin" is required.');
}
var matches = /^([a-z][\w-]+)\/([a-z][\w-]+)$/i.exec(params.repo);
if (matches === null) {
throw new Error("Invalid repo: \"" + params.repo + "\"");
}
return {
owner: matches[1],
repo: matches[2],
branch: 'branch' in params ? params.branch : 'master',
configPath: 'config-path' in params ? params['config-path'] : 'utterances.json',
issueTerm: issueTerm,
issueNumber: issueNumber,
origin: params.origin,
url: params.url,
title: params.title,
description: params.description
};
}
var pageAttributes = readPageAttributes();
var authorizeUri = 'https://github.com/login/oauth/authorize';
var tokenUri = 'https://utterances-oauth.herokuapp.com/access-token';
var redirect_uri = 'https://utteranc.es/authorized.html';
var client_id = '1a560753410b181458de';
var scopes = 'public_repo';
var Token = (function () {
function Token() {
this.storageKey = 'OAUTH_TOKEN';
}
Object.defineProperty(Token.prototype, "value", {
get: function () {
return localStorage.getItem(this.storageKey);
},
set: function (newValue) {
if (newValue === null) {
localStorage.removeItem(this.storageKey);
}
else {
localStorage.setItem(this.storageKey, newValue);
}
},
enumerable: true,
configurable: true
});
return Token;
}());
var token = new Token();
function popup(url) {
var resolve;
window.oautherized = function (query) {
window.oautherized = null;
resolve(deparam(query));
};
var promise = new Promise(function (r) { return resolve = r; });
window.open(url);
return promise;
}
function requestAuthorizationCode() {
var args = {
client_id: client_id,
redirect_uri: redirect_uri,
scope: scopes,
state: Math.floor(Math.random() * 100000).toString()
};
var url = authorizeUri + "?" + param(args);
return popup(url)
.then(function (result) {
if (!(result.code && result.state)) {
throw new Error('Redirect did not include code and state parameters.');
}
if (result.state !== args.state) {
throw new Error('State mismatch.');
}
return result;
});
}
function requestAccessToken(_a) {
var code = _a.code, state = _a.state;
var args = { code: code, state: state };
var url = tokenUri + "?" + param(args);
return fetch(url)
.then(function (response) { return response.json(); });
}
function login() {
return requestAuthorizationCode()
.then(function (response) { return requestAccessToken(response); })
.then(function (_a) {
var access_token = _a.access_token;
return token.value = access_token;
})
.catch(function (reason) {
token.value = null;
throw reason;
});
}
function decodeBase64UTF8(encoded) {
encoded = encoded.replace(/\s/g, '');
return decodeURIComponent(escape(atob(encoded)));
}
var GITHUB_API = 'https://api.github.com/';
var GITHUB_ENCODING__HTML_JSON = 'application/vnd.github.VERSION.html+json';
var GITHUB_ENCODING__HTML = 'application/vnd.github.VERSION.html';
var GITHUB_ENCODING__REACTIONS_PREVIEW = 'application/vnd.github.squirrel-girl-preview';
var UTTERANCES_API = 'https://utterances-oauth.herokuapp.com';
var PAGE_SIZE = 100;
var owner;
var repo;
var branch;
function setRepoContext(context) {
owner = context.owner;
repo = context.repo;
branch = context.branch;
}
function githubRequest(relativeUrl, init) {
init = init || {};
init.mode = 'cors';
init.cache = 'no-cache';
var request = new Request(GITHUB_API + relativeUrl, init);
request.headers.set('Accept', GITHUB_ENCODING__REACTIONS_PREVIEW);
if (token.value !== null) {
request.headers.set('Authorization', "token " + token.value);
}
return request;
}
var rateLimit = {
standard: {
limit: Number.MAX_VALUE,
remaining: Number.MAX_VALUE,
reset: 0
},
search: {
limit: Number.MAX_VALUE,
remaining: Number.MAX_VALUE,
reset: 0
}
};
function processRateLimit(response) {
var limit = response.headers.get('X-RateLimit-Limit');
var remaining = response.headers.get('X-RateLimit-Remaining');
var reset = response.headers.get('X-RateLimit-Reset');
var isSearch = /\/search\//.test(response.url);
var rate = isSearch ? rateLimit.search : rateLimit.standard;
rate.limit = +limit;
rate.remaining = +remaining;
rate.reset = +reset;
if (response.status === 403 && rate.remaining === 0) {
var resetDate = new Date(0);
resetDate.setUTCSeconds(rate.reset);
var mins = Math.round((resetDate.getTime() - new Date().getTime()) / 1000 / 60);
var apiType = isSearch ? 'search API' : 'non-search APIs';
console.warn("Rate limit exceeded for " + apiType + ". Resets in " + mins + " minute" + (mins === 1 ? '' : 's') + ".");
}
}
function readRelNext(response) {
var link = response.headers.get('link');
if (link === null) {
return 0;
}
var match = /\?page=([2-9][0-9]*)>; rel="next"/.exec(link);
if (match === null) {
return 0;
}
return +match[1];
}
function githubFetch(request) {
return fetch(request).then(function (response) {
if (response.status === 401) {
token.value = null;
}
processRateLimit(response);
return response;
});
}
function loadJsonFile(path, html) {
if (html === void 0) { html = false; }
var request = githubRequest("repos/" + owner + "/" + repo + "/contents/" + path + "?ref=" + branch);
if (html) {
request.headers.set('accept', GITHUB_ENCODING__HTML);
}
return githubFetch(request).then(function (response) {
if (response.status === 404) {
throw new Error("Repo \"" + owner + "/" + repo + "\" does not have a file named \"" + path + "\" in the \"" + branch + "\" branch.");
}
if (!response.ok) {
throw new Error("Error fetching " + path + ".");
}
return html ? response.text() : response.json();
}).then(function (file) {
if (html) {
return file;
}
var content = file.content;
var decoded = decodeBase64UTF8(content);
return JSON.parse(decoded);
});
}
function loadIssueByTerm(term) {
var q = "\"" + term + "\" type:issue in:title repo:" + owner + "/" + repo;
var request = githubRequest("search/issues?q=" + encodeURIComponent(q) + "&sort=created&order=asc");
return githubFetch(request).then(function (response) {
if (!response.ok) {
throw new Error('Error fetching issue via search.');
}
return response.json();
}).then(function (results) {
if (results.total_count === 0) {
return null;
}
if (results.total_count > 1) {
console.warn("Multiple issues match \"" + q + "\". Using earliest created.");
}
return results.items[0];
});
}
function loadIssueByNumber(issueNumber) {
var request = githubRequest("repos/" + owner + "/" + repo + "/issues/" + issueNumber);
return githubFetch(request).then(function (response) {
if (!response.ok) {
throw new Error('Error fetching issue via issue number.');
}
return response.json();
});
}
function commentsRequest(issueNumber, page) {
var url = "repos/" + owner + "/" + repo + "/issues/" + issueNumber + "/comments?page=" + page + "&per_page=" + PAGE_SIZE;
var request = githubRequest(url);
var accept = GITHUB_ENCODING__HTML_JSON + "," + GITHUB_ENCODING__REACTIONS_PREVIEW;
request.headers.set('Accept', accept);
return request;
}
function loadCommentsPage(issueNumber, page) {
var request = commentsRequest(issueNumber, page);
return githubFetch(request).then(function (response) {
if (!response.ok) {
throw new Error('Error fetching comments.');
}
var nextPage = readRelNext(response);
return response.json()
.then(function (items) { return ({ items: items, nextPage: nextPage }); });
});
}
function loadUser() {
if (token.value === null) {
return Promise.resolve(null);
}
return githubFetch(githubRequest('user'))
.then(function (response) {
if (response.ok) {
return response.json();
}
return null;
});
}
function createIssue(issueTerm, documentUrl, title, description) {
var request = new Request(UTTERANCES_API + "/repos/" + owner + "/" + repo + "/issues", {
method: 'POST',
body: JSON.stringify({
title: issueTerm,
body: "# " + title + "\n\n" + description + "\n\n" + documentUrl + "\n\n> :crystal_ball: *Issue created by [utteranc.es](https://utteranc.es) bot*"
})
});
request.headers.set('Accept', GITHUB_ENCODING__REACTIONS_PREVIEW);
return fetch(request).then(function (response) {
if (!response.ok) {
throw new Error('Error creating comments container issue');
}
return response.json();
});
}
function postComment(issueNumber, markdown) {
var url = "repos/" + owner + "/" + repo + "/issues/" + issueNumber + "/comments";
var body = JSON.stringify({ body: markdown });
var request = githubRequest(url, { method: 'POST', body: body });
var accept = GITHUB_ENCODING__HTML_JSON + "," + GITHUB_ENCODING__REACTIONS_PREVIEW;
request.headers.set('Accept', accept);
return githubFetch(request).then(function (response) {
if (!response.ok) {
throw new Error('Error posting comment.');
}
return response.json();
});
}
var thresholds = [
1000, 'second',
1000 * 60, 'minute',
1000 * 60 * 60, 'hour',
1000 * 60 * 60 * 24, 'day',
1000 * 60 * 60 * 24 * 7, 'week',
1000 * 60 * 60 * 24 * 27, 'month'
];
var formatOptions = { month: 'short', day: 'numeric', year: 'numeric' };
function timeAgo(current, value) {
var elapsed = current - value.getTime();
if (elapsed < 5000) {
return 'just now';
}
var i = 0;
while (i + 2 < thresholds.length && elapsed * 1.1 > thresholds[i + 2]) {
i += 2;
}
var divisor = thresholds[i];
var text = thresholds[i + 1];
var units = Math.round(elapsed / divisor);
if (units > 3 && i === thresholds.length - 2) {
return "on " + value.toLocaleDateString(undefined, formatOptions);
}
return units === 1 ? (text === 'hour' ? 'an' : 'a') + " " + text + " ago" : units + " " + text + "s ago";
}
var avatarArgs = '?v=3&s=88';
var CommentComponent = (function () {
function CommentComponent(comment, currentUser, repoOwner) {
this.comment = comment;
this.currentUser = currentUser;
this.repoOwner = repoOwner;
var user = comment.user, html_url = comment.html_url, created_at = comment.created_at, body_html = comment.body_html;
this.element = document.createElement('article');
this.element.classList.add('timeline-comment');
if (user.login === currentUser) {
this.element.classList.add('current-user');
}
if (user.login === repoOwner) {
this.element.classList.add('repo-owner');
}
this.element.innerHTML = "\n <a class=\"avatar\" href=\"" + user.html_url + "\" target=\"_blank\">\n <img alt=\"@" + user.login + "\" height=\"44\" width=\"44\"\n src=\"" + user.avatar_url + avatarArgs + "\">\n </a>\n <div class=\"comment\">\n <header class=\"comment-header\">\n <a class=\"text-link\" href=\"" + user.html_url + "\" target=\"_blank\">" + user.login + "</a>\n commented\n <a class=\"text-link\" href=\"" + html_url + "\" target=\"_blank\">\n " + timeAgo(Date.now(), new Date(created_at)) + "\n </a>\n </header>\n <div class=\"markdown-body\">\n " + body_html + "\n </div>\n </div>";
this.retargetLinks();
}
CommentComponent.prototype.setComment = function (comment) {
var commentDiv = this.element.lastElementChild;
var user = comment.user, html_url = comment.html_url, created_at = comment.created_at, body_html = comment.body_html;
if (this.comment.user.login !== user.login) {
if (user.login === this.currentUser) {
this.element.classList.add('current-user');
}
else {
this.element.classList.remove('current-user');
}
if (user.login === this.repoOwner) {
this.element.classList.add('repo-owner');
}
else {
this.element.classList.remove('repo-owner');
}
var avatarAnchor = this.element.firstElementChild;
var avatarImg = avatarAnchor.firstElementChild;
avatarAnchor.href = user.html_url;
avatarImg.alt = '@' + user.login;
avatarImg.src = user.avatar_url + avatarArgs;
var authorAnchor = commentDiv
.firstElementChild.firstElementChild;
authorAnchor.href = user.html_url;
authorAnchor.textContent = user.login;
}
if (this.comment.created_at !== created_at || this.comment.html_url !== html_url) {
var timestamp = commentDiv.firstElementChild.firstElementChild.lastElementChild;
timestamp.href = html_url;
timestamp.textContent = timeAgo(Date.now(), new Date(created_at));
}
if (this.comment.body_html !== body_html) {
var body = commentDiv.lastElementChild;
body.innerHTML = body_html;
this.retargetLinks();
}
this.comment = comment;
};
CommentComponent.prototype.setCurrentUser = function (currentUser) {
if (this.currentUser === currentUser) {
return;
}
var commentDiv = this.element.firstElementChild;
if (this.comment.user.login === this.currentUser) {
commentDiv.classList.add('current-user');
}
else {
commentDiv.classList.remove('current-user');
}
if (this.comment.user.login === this.repoOwner) {
this.element.classList.add('repo-owner');
}
else {
this.element.classList.remove('repo-owner');
}
this.currentUser = currentUser;
};
CommentComponent.prototype.retargetLinks = function () {
var links = this.element.lastElementChild.lastElementChild.querySelectorAll('a');
var j = links.length;
while (j--) {
var link = links.item(j);
link.target = '_blank';
}
};
return CommentComponent;
}());
var hostOrigin;
function setHostOrigin(origin) {
hostOrigin = origin;
addEventListener('resize', publishResize);
}
var lastHeight = -1;
function publishResize() {
var body = document.body, html = document.documentElement;
var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
if (height === lastHeight) {
return;
}
lastHeight = height;
var message = { type: 'resize', height: height };
parent.postMessage(message, hostOrigin);
}
var TimelineComponent = (function () {
function TimelineComponent(user, issue, repoOwner) {
this.user = user;
this.issue = issue;
this.repoOwner = repoOwner;
this.timeline = [];
this.element = document.createElement('section');
this.element.classList.add('timeline');
this.element.innerHTML = "\n <h1 class=\"timeline-header\">\n <a class=\"text-link\" target=\"_blank\"></a>\n <em>\n - powered by\n <a class=\"text-link\" href=\"https://utteranc.es\" target=\"_blank\">utteranc.es</a>\n </em>\n </h1>";
this.countAnchor = this.element.firstElementChild.firstElementChild;
this.marker = document.createComment('marker');
this.element.appendChild(this.marker);
this.setIssue(issue);
}
TimelineComponent.prototype.setUser = function (user) {
this.user = user;
var login = user ? user.login : null;
for (var i = 0; i < this.timeline.length; i++) {
this.timeline[i].setCurrentUser(login);
}
publishResize();
};
TimelineComponent.prototype.setIssue = function (issue) {
this.issue = issue;
if (issue) {
this.countAnchor.textContent = issue.comments + " Comment" + (issue.comments === 1 ? '' : 's');
this.countAnchor.href = issue.html_url;
}
else {
this.countAnchor.textContent = "0 Comments";
this.countAnchor.removeAttribute('href');
}
};
TimelineComponent.prototype.appendComment = function (comment) {
var component = new CommentComponent(comment, this.user ? this.user.login : null, this.repoOwner);
this.timeline.push(component);
this.element.insertBefore(component.element, this.marker);
publishResize();
};
TimelineComponent.prototype.replaceComments = function (comments) {
var i;
for (i = 0; i < comments.length; i++) {
var comment = comments[i];
if (i <= this.timeline.length) {
this.appendComment(comment);
continue;
}
this.timeline[i].setComment(comment);
}
for (; i < this.timeline.length; i++) {
this.element.removeChild(this.element.lastElementChild);
}
publishResize();
};
return TimelineComponent;
}());
var anonymousAvatarUrl = "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 14 16\" version=\"1.1\"><path fill=\"rgb(179,179,179)\" fill-rule=\"evenodd\" d=\"M8 10.5L9 14H5l1-3.5L5.25 9h3.5L8 10.5zM10 6H4L2 7h10l-2-1zM9 2L7 3 5 2 4 5h6L9 2zm4.03 7.75L10 9l1 2-2 3h3.22c.45 0 .86-.31.97-.75l.56-2.28c.14-.53-.19-1.08-.72-1.22zM4 9l-3.03.75c-.53.14-.86.69-.72 1.22l.56 2.28c.11.44.52.75.97.75H5l-2-3 1-2z\"></path></svg>";
var NewCommentComponent = (function () {
function NewCommentComponent(user, submit) {
this.user = user;
this.submit = submit;
this.element = document.createElement('article');
this.element.classList.add('timeline-comment');
this.element.addEventListener('mousemove', publishResize);
this.element.innerHTML = "\n <a class=\"avatar\" target=\"_blank\">\n <img height=\"44\" width=\"44\">\n </a>\n <div class=\"new-comment\">\n <header class=\"new-comment-header\">\n Join the discussion\n </header>\n <form class=\"new-comment-body\" id=\"comment-form\" accept-charset=\"UTF-8\" action=\"javascript:\">\n <textarea placeholder=\"Leave a comment\" aria-label=\"comment\"></textarea>\n </form>\n <footer class=\"new-comment-footer\">\n <a class=\"text-link markdown-info\" tabindex=\"-1\" target=\"_blank\"\n href=\"https://guides.github.com/features/mastering-markdown/\">\n Styling with Markdown is supported\n </a>\n <button class=\"btn btn-primary\" form=\"comment-form\" type=\"submit\">Comment</button>\n </footer>\n </div>";
this.setUser(user);
}
NewCommentComponent.prototype.setUser = function (user) {
var _this = this;
this.user = user;
var avatarAnchor = this.element.firstElementChild;
var avatar = avatarAnchor.firstElementChild;
if (user) {
avatarAnchor.href = user.html_url;
avatar.alt = '@' + user.login;
avatar.src = user.avatar_url + '?v=3&s=88';
}
else {
avatarAnchor.removeAttribute('href');
avatar.alt = '@anonymous';
avatar.src = anonymousAvatarUrl;
}
var form = avatarAnchor.nextElementSibling.firstElementChild.nextElementSibling;
var textarea = form.firstElementChild;
var submitButton = form.nextElementSibling.lastElementChild;
submitButton.textContent = user ? 'Comment' : 'Sign in to comment';
submitButton.disabled = !!user;
textarea.disabled = !user;
textarea.addEventListener('input', function () {
submitButton.disabled = /^\s*$/.test(textarea.value);
if (textarea.scrollHeight < 450 && textarea.offsetHeight < textarea.scrollHeight) {
textarea.style.height = textarea.scrollHeight + "px";
publishResize();
}
});
var submitting = false;
form.addEventListener('submit', function (event) {
event.preventDefault();
if (submitting) {
return;
}
submitting = true;
if (_this.user) {
textarea.disabled = true;
submitButton.disabled = true;
}
_this.submit(textarea.value).catch(function () { return 0; }).then(function () {
submitting = false;
textarea.disabled = !_this.user;
textarea.value = '';
submitButton.disabled = false;
});
});
};
NewCommentComponent.prototype.clear = function () {
var textarea = this.element.lastElementChild.lastElementChild
.firstElementChild.firstElementChild;
textarea.value = '';
};
return NewCommentComponent;
}());
function normalizeConfig(filename, rawConfig) {
if (!Array.isArray(rawConfig.origins)) {
throw new Error(filename + ": origins must be an array");
}
return rawConfig;
}
function loadRepoConfig(path) {
return loadJsonFile(path)
.then(function (config) { return normalizeConfig(path, config); });
}
setRepoContext(pageAttributes);
function loadIssue() {
if (pageAttributes.issueNumber !== null) {
return loadIssueByNumber(pageAttributes.issueNumber);
}
return loadIssueByTerm(pageAttributes.issueTerm);
}
Promise.all([loadRepoConfig(pageAttributes.configPath), loadIssue(), loadUser()])
.then(function (_a) {
var repoConfig = _a[0], issue = _a[1], user = _a[2];
return bootstrap(repoConfig, issue, user);
});
function bootstrap(config, issue, user) {
if (config.origins.indexOf(pageAttributes.origin) === -1) {
throw new Error("The origins specified in " + pageAttributes.configPath + " do not include " + pageAttributes.origin);
}
setHostOrigin(pageAttributes.origin);
var timeline = new TimelineComponent(user, issue, pageAttributes.owner);
document.body.appendChild(timeline.element);
if (issue && issue.comments > 0) {
loadCommentsPage(issue.number, 1).then(function (_a) {
var items = _a.items;
return timeline.replaceComments(items);
});
}
if (issue && issue.locked) {
return;
}
var submit = function (markdown) {
if (user) {
var commentPromise = void 0;
if (issue) {
commentPromise = postComment(issue.number, markdown);
}
else {
commentPromise = createIssue(pageAttributes.issueTerm, pageAttributes.url, pageAttributes.title, pageAttributes.description).then(function (newIssue) {
issue = newIssue;
timeline.setIssue(issue);
return postComment(issue.number, markdown);
});
}
return commentPromise.then(function (comment) {
timeline.appendComment(comment);
newCommentComponent.clear();
});
}
return login().then(function () { return loadUser(); }).then(function (u) {
user = u;
timeline.setUser(user);
newCommentComponent.setUser(user);
});
};
var newCommentComponent = new NewCommentComponent(user, submit);
timeline.element.appendChild(newCommentComponent.element);
publishResize();
}
}());

View File

@ -1,3 +0,0 @@
{
"origins": ["https://utteranc.es", "http://localhost:9000"]
}

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 616 B

After

Width:  |  Height:  |  Size: 616 B

View File

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 923 B

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 722 B

After

Width:  |  Height:  |  Size: 722 B

View File

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -4,23 +4,30 @@
"main": "dist/client.js",
"license": "MIT",
"scripts": {
"clean": "rm -rf output",
"rollup-client": "rollup output/client.js --format iife --output dist/client.debug.js",
"rollup-utterances": "rollup output/utterances.js --format iife --output dist/utterances.js",
"rollup-index": "rollup output/index.js --format iife --output dist/index.js",
"rollup": "yarn run rollup-client && yarn run rollup-utterances && yarn run rollup-index",
"sass": "node-sass src --output dist --include-path node_modules",
"optimize-client": "uglifyjs --compress --mangle --output dist/client.js -- dist/client.debug.js",
"optimize-utterances": "inliner --skip-absolute-urls dist/utterances.debug.html > dist/utterances.html",
"optimize-index": "inliner --skip-absolute-urls dist/index.debug.html > dist/index.html",
"optimize": "yarn run optimize-client && yarn run optimize-utterances && yarn run optimize-index",
"prebuild": "yarn run clean",
"build": "tsc && yarn run rollup && yarn run sass && yarn run optimize",
"watch-output": "chokidar \"output/**/*.js\" --command \"yarn run rollup\"",
"serve": "browser-sync start --server dist --files=\"dist/**/*\" --port 9000 --no-open --no-ui --no-online --no-ghost-mode",
"predevelop": "yarn run build",
"develop": "concurrently --kill-others \"yarn run watch-output\" \"tsc --watch\" \"yarn run sass -- --watch --recursive\" \"yarn run serve\"",
"lint": "tslint --project tsconfig.json",
"clean": "rm -rf output && rm -rf debug && rm -rf dist && mkdir debug && mkdir dist",
"rollup-client": "rollup output/client.js --format iife --output debug/client.js",
"rollup-utterances": "rollup output/utterances.js --format iife --output debug/utterances.js",
"rollup-index": "rollup output/index.js --format iife --output debug/index.js",
"rollup": "yarn run rollup-client && yarn run rollup-utterances && yarn run rollup-index",
"html": "cp src/*.html debug/ && cp src/authorized.html dist/",
"sass": "node-sass src --output debug --include-path node_modules",
"optimize-client": "uglifyjs --compress --mangle --output dist/client.js -- debug/client.js",
"optimize-utterances": "inliner --skip-absolute-urls debug/utterances.html > dist/utterances.html",
"optimize-index": "inliner --skip-absolute-urls debug/index.html > dist/index.html",
"optimize": "yarn run optimize-client && yarn run optimize-utterances && yarn run optimize-index",
"watch-output": "chokidar \"output/**/*.js\" --command \"yarn run rollup\"",
"watch-html": "chokidar \"src/*.html\" --command \"yarn run html\"",
"watch-debug": "chokidar \"debug/*/**\" --command \"yarn run optimize\"",
"watch": "concurrently --kill-others \"tsc --watch\" \"yarn run sass -- --watch --recursive\" \"yarn run watch-output\" \"yarn run watch-html\" \"yarn run watch-debug\"",
"serve-debug": "browser-sync start --server debug --files=\"debug/**/*\" --port 9000 --no-open --no-ui --no-online --no-ghost-mode",
"serve-dist": "browser-sync start --server dist --files=\"dist/**/*\" --port 8000 --no-open --no-ui --no-online --no-ghost-mode",
"serve": "concurrently --kill-others \"yarn run serve-debug\" \"yarn run serve-dist\"",
"predevelop": "yarn run clean && yarn run html && tsc && yarn run rollup && yarn run sass && yarn run optimize",
"develop": "concurrently --kill-others \"yarn run watch\" \"yarn run serve\"",
"prebuild": "yarn run clean",
"build": "yarn run html && tsc && yarn run rollup && yarn run sass && yarn run optimize",
"predeploy": "yarn run build && cp -R icons dist/ && cp .nojekyll dist/ && cp CNAME dist/ && cp utterances.json dist/",
"deploy": "gh-pages --dist dist",
"chrome": "google-chrome --disable-web-security --allow-running-insecure-content --user-data-dir=\"chrome\""
},

47
src/_buttons.scss Normal file
View File

@ -0,0 +1,47 @@
@import "primer-base/index";
.btn {
position: relative;
display: inline-block;
padding: 6px 12px;
font-size: $body-font-size;
font-weight: $font-weight-bold;
line-height: 20px; // Specifically not inherit our `<body>` default
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
user-select: none;
background-repeat: repeat-x;
background-position: -1px -1px;
background-size: 110% 110%;
border: 1px solid transparentize($black, 0.8);
border-radius: 0.25em;
appearance: none; // Corrects inability to style clickable `input` types in iOS.
&:hover {
text-decoration: none;
background-repeat: repeat-x;
}
&:focus {
outline: 0;
}
&:disabled,
&.disabled {
cursor: default;
// Repeat `background-position` because `:hover`
background-position: 0 0;
}
&:active,
&.selected {
background-image: none;
}
}
// .btn { @include btn-solid($text-gray-dark, $gray-000, darken($bg-gray, 2%)); }
.btn-primary { @include btn-solid($text-white, $green-400, $green-500); }
// .btn-purple { @include btn-solid($text-white, lighten($purple-500, 5%), darken($purple-500, 5%)); }
// .btn-blue { @include btn-solid($text-white, lighten($blue-500, 8%), darken($blue-500, 2%)); }
// .btn-danger { @include btn-inverse($red-600, $gray-000, darken($bg-gray, 2%)); }

111
src/_timeline-comment.scss Normal file
View File

@ -0,0 +1,111 @@
@import "primer-base/index";
@import "primer-markdown/index";
@import "pygments-vs";
.timeline-comment {
display: flex;
align-items: flex-start;
margin: $spacer-3 0;
.avatar {
display: none;
}
.avatar > img {
border-radius: $border-radius;
}
.comment {
position: relative;
flex-grow: 1;
flex-basis: 0;
min-width: 0px;
border: $border;
border-radius: $border-radius;
}
.comment-header {
padding: $spacer-2 $spacer-3;
color: $text-gray;
background-color: $bg-gray;
border-bottom: $border;
.user-login {
font-weight: $font-weight-bold;
}
}
.markdown-body {
padding: $spacer-3 $spacer-3;
max-height: 400px;
overflow-x: hidden;
overflow-y: auto;
font-size: $body-font-size;
}
.comment-body {
padding: $spacer-2;
textarea {
display: block;
padding: $spacer-2;
width: 100%;
min-height: 90px;
max-height: 550px;
resize: vertical;
border: $border;
border-radius: $border-radius;
}
textarea:focus {
box-shadow: $btn-input-focus-shadow;
}
textarea:disabled {
background-color: $gray-100;
}
}
.comment-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 $spacer-2 $spacer-2 $spacer-2;
.markdown-info {
font-size: $font-size-small;
}
}
}
.timeline-comment.current-user .comment-header {
background-color: $bg-blue-light;
}
.timeline-comment.repo-owner .comment-header :last-child::after {
float: right;
margin-top: -1px;
padding: 2px 5px;
border: $border;
border-radius: $border-radius;
font-size: $font-size-small;
font-weight: $font-weight-semibold;
content: 'Owner';
}
@media (min-width: map-get($breakpoints, sm)) {
.timeline-comment {
.avatar {
display: block;
margin-right: $spacer-3;
}
.comment {
@include double-caret($bg-gray, $border-gray-dark);
}
}
.timeline-comment.current-user .comment {
@include double-caret($bg-blue-light, $border-gray-dark);
}
}

27
src/_timeline.scss Normal file
View File

@ -0,0 +1,27 @@
.timeline {
max-width: 760px;
margin: $spacer-3 $spacer-1;
}
.timeline-header {
margin: 0;
padding-left: $spacer-3;
font-size: $body-font-size;
color: $text-gray;
}
.timeline-header em {
font-weight: $font-weight-normal;
}
@media (min-width: map-get($breakpoints, sm)) {
.timeline-header {
padding-left: 44 + $spacer-3;
}
}
@media (min-width: map-get($breakpoints, md)) {
.timeline {
margin: 0 auto;
}
}

3
src/_util.scss Normal file
View File

@ -0,0 +1,3 @@
.text-link {
color: $text-gray;
}

View File

@ -27,7 +27,7 @@ export class CommentComponent {
</a>
<div class="comment">
<header class="comment-header">
<a class="text-link" href="${user.html_url}" target="_blank">${user.login}</a>
<a class="user-login text-link" href="${user.html_url}" target="_blank">${user.login}</a>
commented
<a class="text-link" href="${html_url}" target="_blank">
${timeAgo(Date.now(), new Date(created_at))}

View File

@ -26,7 +26,7 @@
</a>
<div class="comment">
<header class="comment-header">
utterances
<a class="user-login text-link" href="https://github.com/utterance">utterances</a>
</header>
</div>
</article>

View File

@ -177,8 +177,7 @@ export function createIssue(issueTerm: string, documentUrl: string, title: strin
method: 'POST',
body: JSON.stringify({
title: issueTerm,
// tslint:disable-next-line:max-line-length
body: `# ${title}\n\n${description}\n\n${documentUrl}\n\n> :crystal_ball: *Issue created by [utteranc.es](https://utteranc.es) bot*`
body: `# ${title}\n\n${description}\n\n[${documentUrl}](${documentUrl})`
})
});
request.headers.set('Accept', GITHUB_ENCODING__REACTIONS_PREVIEW);

View File

@ -26,7 +26,7 @@
</a>
<div class="comment">
<header class="comment-header">
utterances
<a class="user-login text-link" href="https://github.com/utterance">utterances</a>
</header>
</div>
</article>
@ -37,7 +37,7 @@
<script src="https://utteranc.es/client.js"
repo="utterance/utterances"
branch="gh-pages"
issue-term="pathname"
issue-term="homepage"
async>
</script>

View File

@ -1,72 +1,17 @@
@import "primer-base/index";
@import "primer-markdown/index";
@import "pygments-vs";
@import "util";
@import "timeline";
@import "timeline-comment";
.timeline {
max-width: 760px;
margin: $spacer-3 $spacer-1;
}
.timeline-comment .markdown-body {
max-height: unset;
font-size: 16px;
.timeline-comment {
display: flex;
align-items: flex-start;
margin: $spacer-3 0;
}
.avatar {
display: none;
}
.avatar > img {
border-radius: $border-radius;
}
.comment {
position: relative;
flex-grow: 1;
flex-basis: 0;
min-width: 0px;
border: $border;
border-radius: $border-radius;
}
.comment-header {
padding: $spacer-2 $spacer-3;
color: $text-gray;
background-color: $bg-gray;
border-bottom: $border;
font-weight: $font-weight-bold;
}
.markdown-body {
padding: $spacer-3 $spacer-3;
}
.markdown-body {
h1, h2, h2, h4, h5, h6 {
h1,h2,h3,h4,h5,h6 {
.anchor {
display: none;
}
}
}
@media (min-width: map-get($breakpoints, sm)) {
.timeline-header {
padding-left: 44 + $spacer-3;
}
.avatar {
display: block;
margin-right: $spacer-3;
}
.comment {
@include double-caret($bg-gray, $border-gray-dark);
}
}
@media (min-width: map-get($breakpoints, md)) {
.timeline {
margin: 0 auto;
}
}

View File

@ -19,14 +19,14 @@ export class NewCommentComponent {
<a class="avatar" target="_blank">
<img height="44" width="44">
</a>
<div class="new-comment">
<header class="new-comment-header">
<div class="comment">
<header class="comment-header">
Join the discussion
</header>
<form class="new-comment-body" id="comment-form" accept-charset="UTF-8" action="javascript:">
<form class="comment-body" id="comment-form" accept-charset="UTF-8" action="javascript:">
<textarea placeholder="Leave a comment" aria-label="comment"></textarea>
</form>
<footer class="new-comment-footer">
<footer class="comment-footer">
<a class="text-link markdown-info" tabindex="-1" target="_blank"
href="https://guides.github.com/features/mastering-markdown/">
Styling with Markdown is supported

View File

@ -21,15 +21,15 @@ function readPageAttributes() {
throw new Error(`issue-number is invalid. "${params['issue-number']}`);
}
} else {
throw new Error('Invalid query string arguments. Either "issue-term" or "issue-number" must be specified.');
throw new Error('"issue-term" or "issue-number" must be specified.');
}
if (!('repo' in params)) {
throw new Error('Invalid query string arguments. "repo" is required.');
throw new Error('"repo" is required.');
}
if (!('origin' in params)) {
throw new Error('Invalid query string arguments. "origin" is required.');
throw new Error('"origin" is required.');
}
const matches = /^([a-z][\w-]+)\/([a-z][\w-]+)$/i.exec(params.repo);

View File

@ -1,208 +1,11 @@
@import "primer-base/index";
@import "primer-markdown/index";
@import "pygments-vs";
body {
overflow: hidden;
}
.text-link {
color: $text-gray;
}
.timeline {
max-width: 760px;
margin: $spacer-3 $spacer-1;
}
.timeline-header {
margin: 0;
padding-left: $spacer-3;
font-size: $body-font-size;
color: $text-gray;
}
.timeline-header em {
font-weight: $font-weight-normal;
}
.timeline-comment {
display: flex;
align-items: flex-start;
margin: $spacer-3 0;
}
.avatar {
display: none;
}
.avatar > img {
border-radius: $border-radius;
}
.comment {
position: relative;
flex-grow: 1;
flex-basis: 0;
min-width: 0px;
border: $border;
border-radius: $border-radius;
}
.comment-header {
padding: $spacer-2 $spacer-3;
color: $text-gray;
background-color: $bg-gray;
border-bottom: $border;
}
.comment-header :first-child {
font-weight: $font-weight-bold;
}
.current-user .comment-header {
background-color: $bg-blue-light;
}
.repo-owner .comment-header :last-child::after {
float: right;
margin-top: -1px;
padding: 2px 5px;
border: $border;
border-radius: $border-radius;
font-size: $font-size-small;
font-weight: $font-weight-semibold;
content: 'Owner';
}
.markdown-body {
padding: $spacer-3 $spacer-3;
max-height: 400px;
overflow-x: hidden;
overflow-y: auto;
font-size: $body-font-size;
}
.new-comment {
flex-grow: 1;
position: relative;
border: $border;
border-radius: $border-radius;
}
.new-comment-header {
padding: $spacer-2 $spacer-3;
font-weight: $font-weight-bold;
color: $text-gray;
background-color: $bg-blue-light;
border-bottom: $border;
}
.new-comment-body {
padding: $spacer-2;
}
.new-comment-body textarea {
display: block;
padding: $spacer-2;
width: 100%;
min-height: 90px;
max-height: 550px;
resize: vertical;
border: $border;
border-radius: $border-radius;
}
.new-comment-body textarea:focus {
box-shadow: $btn-input-focus-shadow;
}
.new-comment-body textarea:disabled {
background-color: $gray-100;
}
.new-comment-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 $spacer-2 $spacer-2 $spacer-2;
}
.markdown-info {
font-size: $font-size-small;
}
.btn {
position: relative;
display: inline-block;
padding: 6px 12px;
font-size: $body-font-size;
font-weight: $font-weight-bold;
line-height: 20px; // Specifically not inherit our `<body>` default
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
user-select: none;
background-repeat: repeat-x;
background-position: -1px -1px;
background-size: 110% 110%;
border: 1px solid transparentize($black, 0.8);
border-radius: 0.25em;
appearance: none; // Corrects inability to style clickable `input` types in iOS.
&:hover {
text-decoration: none;
background-repeat: repeat-x;
}
&:focus {
outline: 0;
}
&:disabled,
&.disabled {
cursor: default;
// Repeat `background-position` because `:hover`
background-position: 0 0;
}
&:active,
&.selected {
background-image: none;
}
}
// .btn { @include btn-solid($text-gray-dark, $gray-000, darken($bg-gray, 2%)); }
.btn-primary { @include btn-solid($text-white, $green-400, $green-500); }
// .btn-purple { @include btn-solid($text-white, lighten($purple-500, 5%), darken($purple-500, 5%)); }
// .btn-blue { @include btn-solid($text-white, lighten($blue-500, 8%), darken($blue-500, 2%)); }
// .btn-danger { @include btn-inverse($red-600, $gray-000, darken($bg-gray, 2%)); }
@media (min-width: map-get($breakpoints, sm)) {
.timeline-header {
padding-left: 44 + $spacer-3;
}
.avatar {
display: block;
margin-right: $spacer-3;
}
.comment {
@include double-caret($bg-gray, $border-gray-dark);
}
.current-user .comment {
@include double-caret($bg-blue-light, $border-gray-dark);
}
.new-comment {
@include double-caret($bg-blue-light, $border-gray-dark);
}
}
@media (min-width: map-get($breakpoints, md)) {
.timeline {
margin: 0 auto;
}
}
@import "primer-base/index";
@import "primer-markdown/index";
@import "pygments-vs";
@import "util";
@import "buttons";
@import "timeline";
@import "timeline-comment";

3
utterances.json Normal file
View File

@ -0,0 +1,3 @@
{
"origins": ["https://utteranc.es", "http://localhost:9000", "http://localhost:8000"]
}