diff --git a/archetypes/default.md b/archetypes/default.md deleted file mode 100644 index 00e77bd..0000000 --- a/archetypes/default.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }}" -date: {{ .Date }} -draft: true ---- - diff --git a/config.toml b/config.toml index 60d0e11..9cbbd3d 100755 --- a/config.toml +++ b/config.toml @@ -1,14 +1,14 @@ baseurl = "https://mehl.mx/" languageCode = "en-GB" title = "Max Mehl" -theme = [ "hugo-sustain", "hugo-cloak-email" ] +theme = [ "hugo-sustain", "hugo-cloak-email", "hugo-mastodon-comments" ] [blackfriday] # preserves linebreaks, and transforms to
extensions = [ "hardLineBreak" ] [permalinks] - post = "/:year/:month/:day/:slug" + blog = "/blog/:year/:slug" [params] avatar = "profile.jpg" @@ -17,8 +17,11 @@ extensions = [ "hardLineBreak" ] keywords = "manager, free software, open source, project, campaign, konstanz, berlin, munster, communication, IT service, computer, politics, administration, FSFE, scouts, founder" # Custom assets can be linked with their paths relative to static/ - custom_css = ['css/custom.css'] - custom_js = [] + custom_css = ['css/custom.css', 'comments/mastodon-comments.css'] + custom_js = ['comments/getcomments.js'] + +[params.blog] + headline = "Thoughts about tech, politics, and more" [params.social] Github = "mxmehl" diff --git a/content/blog/creating-a-new-theme.md b/content/blog/creating-a-new-theme.md index b6ae663..23a06d2 100755 --- a/content/blog/creating-a-new-theme.md +++ b/content/blog/creating-a-new-theme.md @@ -4,7 +4,7 @@ date: 2014-09-28 linktitle: Creating a New Theme title: Creating a New Theme highlight: true -draft: true +draft: false --- diff --git a/content/blog/goisforlovers.md b/content/blog/goisforlovers.md index 99bb6ff..38dff62 100755 --- a/content/blog/goisforlovers.md +++ b/content/blog/goisforlovers.md @@ -14,7 +14,9 @@ categories = [ "golang", ] highlight = "true" -draft = true +draft = false +headerimage = "placeholder.jpg" +headercredits = "Unsplash, [Dlanor S](https://unsplash.com/photos/2xEQDxB0ss4)" +++ Hugo uses the excellent [go][] [html/template][gohtmltemplate] library for diff --git a/content/blog/hugoisforlovers.md b/content/blog/hugoisforlovers.md index 75b9166..ca49110 100755 --- a/content/blog/hugoisforlovers.md +++ b/content/blog/hugoisforlovers.md @@ -2,7 +2,7 @@ title = "Getting Started with Hugo" description = "" tags = [ - "radio lockdown", + "RadioLockdown", "golang", "hugo", "development", @@ -13,7 +13,7 @@ categories = [ "golang", ] highlight = "true" -draft = true +draft = false +++ ## Step 1. Install Hugo diff --git a/content/blog/migrate-from-jekyll.md b/content/blog/migrate-from-jekyll.md index 2937517..a4fb9d6 100755 --- a/content/blog/migrate-from-jekyll.md +++ b/content/blog/migrate-from-jekyll.md @@ -3,7 +3,7 @@ date: 2014-03-10 linktitle: Migrating from Jekyll title: Migrate to Hugo from Jekyll highlight: "true" -draft: true +draft: false --- ## Move static content to `static` diff --git a/content/blog/test.md b/content/blog/test.md new file mode 100755 index 0000000..a82f308 --- /dev/null +++ b/content/blog/test.md @@ -0,0 +1,25 @@ ++++ +title = "TEST ARTICLE" +description = "" +tags = [ + "test" +] +date = "2018-04-02" +categories = [ + "Development", +] +highlight = "true" +draft = false +headerimage = "placeholder.jpg" +headercredits = "Unsplash, [Dlanor S](https://unsplash.com/photos/2xEQDxB0ss4)" ++++ + +LOREM IPSUM Hugo uses the excellent [go][] [html/template][gohtmltemplate] library for +its template engine. It is an extremely lightweight engine that provides a very +small amount of logic. In our experience that it is just the right amount of +logic to be able to create a good static website. If you have used other +template systems from different languages or frameworks you will find a lot of +similarities in go templates. + +This document is a brief primer on using go templates. The [go docs][gohtmltemplate] +provide more details. diff --git a/static/img/placeholder.jpg b/static/img/placeholder.jpg new file mode 100644 index 0000000..8292428 Binary files /dev/null and b/static/img/placeholder.jpg differ diff --git a/themes/hugo-mastodon-comments/.gitignore b/themes/hugo-mastodon-comments/.gitignore new file mode 100644 index 0000000..0ed663d --- /dev/null +++ b/themes/hugo-mastodon-comments/.gitignore @@ -0,0 +1 @@ +static/comments/config.php diff --git a/themes/hugo-mastodon-comments/layouts/partials/comments.html b/themes/hugo-mastodon-comments/layouts/partials/comments.html new file mode 100644 index 0000000..8d2ad9f --- /dev/null +++ b/themes/hugo-mastodon-comments/layouts/partials/comments.html @@ -0,0 +1,14 @@ +
+
Comments
+
+
+
+
+
+
+
+ +
+ + + diff --git a/themes/hugo-mastodon-comments/static/comments/Mastodon_api.php b/themes/hugo-mastodon-comments/static/comments/Mastodon_api.php new file mode 100644 index 0000000..b57e252 --- /dev/null +++ b/themes/hugo-mastodon-comments/static/comments/Mastodon_api.php @@ -0,0 +1,975 @@ + + * @copyright KwangSeon Yun + * @license https://raw.githubusercontent.com/yks118/Mastodon-api-php/master/LICENSE MIT License + * @link https://github.com/yks118/Mastodon-api-php + */ +class Mastodon_api { + private $mastodon_url = ''; + private $client_id = ''; + private $client_secret = ''; + + private $token = array(); + private $scopes = array(); + + public function __construct () {} + + public function __destruct () {} + + /** + * _post + * + * curl post + * + * @param string $url + * @param array $data + * + * @return array $response + */ + private function _post ($url,$data = array()) { + $parameters = array(); + $parameters[CURLOPT_POST] = 1; + + // set access_token + if (isset($this->token['access_token'])) { + $data['access_token'] = $this->token['access_token']; + } + + if (count($data)) { + $parameters[CURLOPT_POSTFIELDS] = preg_replace('/([(%5B)]{1})[0-9]+([(%5D)]{1})/','$1$2',http_build_query($data)); + } + + $url = $this->mastodon_url.$url; + $response = $this->get_content_curl($url,$parameters); + return $response; + } + + /** + * _get + * + * @param string $url + * @param array $data + * + * @return array $response + */ + private function _get ($url,$data = array()) { + $parameters = array(); + + // set authorization bearer + if (isset($this->token['access_token'])) { + $authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token']; + $parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization); + } + + $url = $this->mastodon_url.$url; + if (count($data)) { + $url .= '?' . http_build_query($data); + } + + $response = $this->get_content_curl($url,$parameters); + return $response; + } + + /** + * _patch + * + * @param string $url + * @param array $data + * + * @return array $parameters + */ + private function _patch ($url,$data = array()) { + $parameters = array(); + $parameters[CURLOPT_CUSTOMREQUEST] = 'PATCH'; + + // set authorization bearer + if (isset($this->token['access_token'])) { + $authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token']; + $parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization); + } + + if (count($data)) { + $parameters[CURLOPT_POSTFIELDS] = json_encode($data); + } + + $url = $this->mastodon_url.$url; + $response = $this->get_content_curl($url,$parameters); + return $response; + } + + /** + * _delete + * + * @param string $url + * + * @return array $response + */ + private function _delete ($url) { + $parameters = array(); + $parameters[CURLOPT_CUSTOMREQUEST] = 'DELETE'; + + // set authorization bearer + if (isset($this->token['access_token'])) { + $authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token']; + $parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization); + } + + $url = $this->mastodon_url.$url; + $response = $this->get_content_curl($url,$parameters); + return $response; + } + + /** + * get_content_curl + * + * @param string $url + * @param array $parameters + * + * @return array $data + */ + protected function get_content_curl ($url,$parameters = array()) { + $data = array(); + + // set CURLOPT_USERAGENT + if (!isset($parameters[CURLOPT_USERAGENT])) { + if (isset($_SERVER['HTTP_USER_AGENT'])) { + $parameters[CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT']; + } else { + // default IE11 + $parameters[CURLOPT_USERAGENT] = 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'; + } + } + + // check curl_init + if (function_exists('curl_init')) { + $ch = curl_init(); + + // url 설정 + curl_setopt($ch,CURLOPT_URL,$url); + + foreach ($parameters as $key => $value) { + curl_setopt($ch,$key,$value); + } + + // https + if (!isset($parameters[CURLOPT_SSL_VERIFYPEER])) { + curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); + } + if (!isset($parameters[CURLOPT_SSLVERSION])) { + curl_setopt($ch,CURLOPT_SSLVERSION,6); + } + + // no header + if (!isset($parameters[CURLOPT_HEADER])) { + curl_setopt($ch,CURLOPT_HEADER,0); + } + + // POST / GET (default : GET) + if (!isset($parameters[CURLOPT_POST]) && !isset($parameters[CURLOPT_CUSTOMREQUEST])) { + curl_setopt($ch,CURLOPT_POST,0); + } + + // response get php value + if (!isset($parameters[CURLOPT_RETURNTRANSFER])) { + curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); + } + + // HTTP2 + if (!isset($parameters[CURLOPT_HTTP_VERSION])) { + curl_setopt($ch,CURLOPT_HTTP_VERSION,3); + } + if (!isset($parameters[CURLINFO_HEADER_OUT])) { + curl_setopt($ch,CURLINFO_HEADER_OUT,TRUE); + } + + $data['html'] = json_decode(curl_exec($ch),true); + $data['response'] = curl_getinfo($ch); + + curl_close($ch); + } + + return $data; + } + + /** + * set_url + * + * @param string $path + */ + public function set_url ($path) { + $this->mastodon_url = $path; + } + + /** + * set_client + * + * @param string $id + * @param string $secret + */ + public function set_client ($id,$secret) { + $this->client_id = $id; + $this->client_secret = $secret; + } + + /** + * set_token + * + * @param string $token + * @param string $type + */ + public function set_token ($token,$type) { + $this->token['access_token'] = $token; + $this->token['token_type'] = $type; + } + + /** + * set_scopes + * + * @param array $scopes read / write / follow + */ + public function set_scopes ($scopes) { + $this->scopes = $scopes; + } + + /** + * create_app + * + * @param string $client_name + * @param array $scopes read / write / follow + * @param string $redirect_uris + * @param string $website + * + * @return array $response + * int $response['id'] + * string $response['redirect_uri'] + * string $response['client_id'] + * string $response['client_secret'] + */ + public function create_app ($client_name,$scopes = array(),$redirect_uris = '',$website = '') { + $parameters = array(); + + if (count($scopes) == 0) { + if (count($this->scopes) == 0) { + $scopes = array('read','write','follow'); + } else { + $scopes = $this->scopes; + } + } + + $parameters['client_name'] = $client_name; + $parameters['scopes'] = implode(' ',$scopes); + + if (empty($redirect_uris)) { + $parameters['redirect_uris'] = 'urn:ietf:wg:oauth:2.0:oob'; + } else { + $parameters['redirect_uris'] = $redirect_uris; + } + + if ($website) { + $parameters['website'] = $website; + } + + $response = $this->_post('/api/v2/apps',$parameters); + + if (isset($response['html']['client_id'])) { + $this->client_id = $response['html']['client_id']; + $this->client_secret = $response['html']['client_secret']; + } + + return $response; + } + + /** + * login + * + * @param string $id E-mail Address + * @param string $password Password + * + * @return array $response + * string $response['access_token'] + * string $response['token_type'] bearer + * string $response['scope'] read + * int $response['created_at'] time + */ + public function login ($id,$password) { + $parameters = array(); + $parameters['client_id'] = $this->client_id; + $parameters['client_secret'] = $this->client_secret; + $parameters['grant_type'] = 'password'; + $parameters['username'] = $id; + $parameters['password'] = $password; + + if (count($this->scopes) == 0) { + $parameters['scope'] = implode(' ',array('read','write','follow')); + } else { + $parameters['scope'] = implode(' ',$this->scopes); + } + + $response = $this->_post('/oauth/token',$parameters); + + if (isset($response['html']['access_token'])) { + $this->token['access_token'] = $response['html']['access_token']; + $this->token['token_type'] = $response['html']['token_type']; + } + + return $response; + } + + /** + * accounts + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + * int $response['id'] + * string $response['username'] + * string $response['acct'] + * string $response['display_name'] The name to display in the user's profile + * bool $response['locked'] + * string $response['created_at'] + * int $response['followers_count'] + * int $response['following_count'] + * int $response['statuses_count'] + * string $response['note'] A new biography for the user + * string $response['url'] + * string $response['avatar'] A base64 encoded image to display as the user's avatar + * string $response['avatar_static'] + * string $response['header'] A base64 encoded image to display as the user's header image + * string $response['header_static'] + */ + public function accounts ($id) { + $response = $this->_get('/api/v2/accounts/'.$id); + return $response; + } + + /** + * accounts_verify_credentials + * + * Getting the current user + * + * @return array $response + */ + public function accounts_verify_credentials () { + $response = $this->_get('/api/v2/accounts/verify_credentials'); + return $response; + } + + /** + * accounts_update_credentials + * + * Updating the current user + * + * @param array $parameters + * string $parameters['display_name'] The name to display in the user's profile + * string $parameters['note'] A new biography for the user + * string $parameters['avatar'] A base64 encoded image to display as the user's avatar + * string $parameters['header'] A base64 encoded image to display as the user's header image + * + * @return array $response + */ + public function accounts_update_credentials ($parameters) { + $response = $this->_patch('/api/v2/accounts/update_credentials',$parameters); + return $response; + } + + /** + * accounts_followers + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_followers ($id) { + $response = $this->_get('/api/v2/accounts/'.$id.'/followers'); + return $response; + } + + /** + * accounts_following + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_following ($id) { + $response = $this->_get('/api/v2/accounts/'.$id.'/following'); + return $response; + } + + /** + * accounts_statuses + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_statuses ($id) { + $response = $this->_get('/api/v2/accounts/'.$id.'/statuses'); + return $response; + } + + /** + * accounts_own_statuses, only own statuses + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_own_statuses ($id) { + $response = $this->_get('/api/v2/accounts/'.$id.'/statuses?exclude_replies=1'); + $result = []; + foreach ($response['html'] as $r) { + if(is_null($r['reblog'])) { + $result[] = $r; + } + } + + $response['html'] = $result; + + return $response; + } + + /** + * accounts_follow + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_follow ($id) { + $response = $this->_post('/api/v2/accounts/'.$id.'/follow'); + return $response; + } + + /** + * accounts_unfollow + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_unfollow ($id) { + $response = $this->_post('/api/v2/accounts/'.$id.'/unfollow'); + return $response; + } + + /** + * accounts_block + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_block ($id) { + $response = $this->_post('/api/v2/accounts/'.$id.'/block'); + return $response; + } + + /** + * accounts_unblock + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_unblock ($id) { + $response = $this->_post('/api/v2/accounts/'.$id.'/unblock'); + return $response; + } + + /** + * accounts_mute + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_mute ($id) { + $response = $this->_post('/api/v2/accounts/'.$id.'/mute'); + return $response; + } + + /** + * accounts_unmute + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function accounts_unmute ($id) { + $response = $this->_post('/api/v2/accounts/'.$id.'/unmute'); + return $response; + } + + /** + * accounts_relationships + * + * @see https://your-domain/web/accounts/:id + * + * @param array $parameters + * int $parameters['id'] + * + * @return array $response + * int $response['id'] + * bool $response['following'] + * bool $response['followed_by'] + * bool $response['blocking'] + * bool $response['muting'] + * bool $response['requested'] + */ + public function accounts_relationships ($parameters) { + $response = $this->_get('/api/v2/accounts/relationships',$parameters); + return $response; + } + + /** + * accounts_search + * + * @param array $parameters + * string $parameters['q'] + * int $parameters['limit'] default : 40 + * + * @return array $response + */ + public function accounts_search ($parameters) { + $response = $this->_get('/api/v2/accounts/search',$parameters); + return $response; + } + + /** + * blocks + * + * @return array $response + */ + public function blocks () { + $response = $this->_get('/api/v2/blocks'); + return $response; + } + + /** + * favourites + * + * @return array $response + */ + public function favourites () { + $response = $this->_get('/api/v2/favourites'); + return $response; + } + + /** + * follow_requests + * + * @return array $response + */ + public function follow_requests () { + $response = $this->_get('/api/v2/follow_requests'); + return $response; + } + + /** + * follow_requests_authorize + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * + * @return array $response + */ + public function follow_requests_authorize ($id) { + $response = $this->_post('/api/v2/follow_requests/authorize',array('id'=>$id)); + return $response; + } + + /** + * follow_requests_reject + * + * @see https://your-domain/web/accounts/:id + * + * @param int $id + * @return array $response + */ + public function follow_requests_reject ($id) { + $response = $this->_post('/api/v2/follow_requests/reject',array('id'=>$id)); + return $response; + } + + /** + * follows + * + * Following a remote user + * + * @param string $uri username@domain of the person you want to follow + * @return array $response + */ + public function follows ($uri) { + $response = $this->_post('/api/v2/follows',array('uri'=>$uri)); + return $response; + } + + /** + * instance + * + * Getting instance information + * + * @return array $response + * string $response['uri'] + * string $response['title'] + * string $response['description'] + * string $response['email'] + */ + public function instance () { + $response = $this->_get('/api/v2/instance'); + return $response; + } + + /** + * media + * + * Uploading a media attachment + * + * @param string $file_path local path / http path + * + * @return array $response + * int $response['id'] ID of the attachment + * string $response['type'] One of: "image", "video", "gifv" + * string $response['url'] URL of the locally hosted version of the image + * string $response['remote_url'] For remote images, the remote URL of the original image + * string $response['preview_url'] URL of the preview image + * string $response['text_url'] Shorter URL for the image, for insertion into text (only present on local images) + */ + public function media ($file_path) { + $url = $this->mastodon_url.'/api/v2/media'; + $parameters = $data = array(); + $parameters[CURLOPT_HTTPHEADER] = array('Content-Type'=>'multipart/form-data'); + $parameters[CURLOPT_POST] = true; + + // set access_token + if (isset($this->token['access_token'])) { + $parameters[CURLOPT_POSTFIELDS]['access_token'] = $this->token['access_token']; + } + + if (is_file($file_path)) { + $mime_type = mime_content_type($file_path); + + $cf = curl_file_create($file_path,$mime_type,'file'); + $parameters[CURLOPT_POSTFIELDS]['file'] = $cf; + } + + $response = $this->get_content_curl($url,$parameters); + return $response; + } + + /** + * mutes + * + * Fetching a user's mutes + * + * @return array $response + */ + public function mutes () { + $response = $this->_get('/api/v2/mutes'); + return $response; + } + + /** + * notifications + * + * @param int $id + * + * @return array $response + */ + public function notifications ($id = 0) { + $url = '/api/v2/notifications'; + + if ($id > 0) { + $url .= '/'.$id; + } + + $response = $this->_get($url); + return $response; + } + + /** + * notifications_clear + * + * Clearing notifications + * + * @return array $response + */ + public function notifications_clear () { + $response = $this->_post('/api/v2/notifications/clear'); + return $response; + } + + /** + * get_reports + * + * Fetching a user's reports + * + * @return array $response + */ + public function get_reports () { + $response = $this->_get('/api/v2/reports'); + return $response; + } + + /** + * post_reports + * + * Reporting a user + * + * @param array $parameters + * int $parameters['account_id'] The ID of the account to report + * int $parameters['status_ids'] The IDs of statuses to report (can be an array) + * string $parameters['comment'] A comment to associate with the report. + * + * @return array $response + */ + public function post_reports ($parameters) { + $response = $this->_post('/api/v2/reports',$parameters); + return $response; + } + + /** + * search + * + * Searching for content + * + * @param array $parameters + * string $parameters['q'] The search query + * string $parameters['resolve'] Whether to resolve non-local accounts + * + * @return array $response + */ + public function search ($parameters) { + $response = $this->_get('/api/v2/search',$parameters); + return $response; + } + + /** + * statuses + * + * Fetching a status + * + * @param int $id + * + * @return array $response + */ + public function statuses ($id) { + $response = $this->_get('/api/v2/statuses/'.$id); + return $response; + } + + /** + * statuses_context + * + * Getting status context + * + * @param int $id + * + * @return array $response + */ + public function statuses_context ($id) { + $response = $this->_get('/api/v2/statuses/'.$id.'/context'); + return $response; + } + + /** + * statuses_card + * + * Getting a card associated with a status + * + * @param int $id + * + * @return array $response + */ + public function statuses_card ($id) { + $response = $this->_get('/api/v2/statuses/'.$id.'/card'); + return $response; + } + + /** + * statuses_reblogged_by + * + * Getting who reblogged a status + * + * @param int $id + * + * @return array $response + */ + public function statuses_reblogged_by ($id) { + $response = $this->_get('/api/v2/statuses/'.$id.'/reblogged_by'); + return $response; + } + + /** + * statuses_favourited_by + * + * Getting who favourited a status + * + * @param int $id + * + * @return array $response + */ + public function statuses_favourited_by ($id) { + $response = $this->_get('/api/v2/statuses/'.$id.'/favourited_by'); + return $response; + } + + /** + * post_statuses + * + * @param array $parameters + * string $parameters['status'] The text of the status + * int $parameters['in_reply_to_id'] (optional): local ID of the status you want to reply to + * int $parameters['media_ids'] (optional): array of media IDs to attach to the status (maximum 4) + * string $parameters['sensitive'] (optional): set this to mark the media of the status as NSFW + * string $parameters['spoiler_text'] (optional): text to be shown as a warning before the actual content + * string $parameters['visibility'] (optional): either "direct", "private", "unlisted" or "public" + * + * @return array $response + */ + public function post_statuses ($parameters) { + $response = $this->_post('/api/v2/statuses',$parameters); + return $response; + } + + /** + * delete_statuses + * + * Deleting a status + * + * @param int $id + * + * @return array $response empty + */ + public function delete_statuses ($id) { + $response = $this->_delete('/api/v2/statuses/'.$id); + return $response; + } + + /** + * statuses_reblog + * + * Reblogging a status + * + * @param int $id + * + * @return array $response + */ + public function statuses_reblog ($id) { + $response = $this->_post('/api/v2/statuses/'.$id.'/reblog'); + return $response; + } + + /** + * statuses_unreblog + * + * Unreblogging a status + * + * @param int $id + * + * @return array $response + */ + public function statuses_unreblog ($id) { + $response = $this->_post('/api/v2/statuses/'.$id.'/unreblog'); + return $response; + } + + /** + * statuses_favourite + * + * Favouriting a status + * + * @param int $id + * + * @return array $response + */ + public function statuses_favourite ($id) { + $response = $this->_post('/api/v2/statuses/'.$id.'/favourite'); + return $response; + } + + /** + * statuses_unfavourite + * + * Unfavouriting a status + * + * @param int $id + * + * @return array $response + */ + public function statuses_unfavourite ($id) { + $response = $this->_post('/api/v2/statuses/'.$id.'/unfavourite'); + return $response; + } + + /** + * timelines_home + * + * @return array $response + */ + public function timelines_home () { + $response = $this->_get('/api/v2/timelines/home'); + return $response; + } + + /** + * timelines_public + * + * @param array $parameters + * bool $parameters['local'] Only return statuses originating from this instance + * + * @return array $response + */ + public function timelines_public ($parameters = array()) { + $response = $this->_get('/api/v2/timelines/public',$parameters); + return $response; + } + + /** + * timelines_tag + * + * @param string $hashtag + * @param array $parameters + * bool $parameters['local'] Only return statuses originating from this instance + * + * @return array $response + */ + public function timelines_tag ($hashtag,$parameters = array()) { + $response = $this->_get('/api/v2/timelines/tag/'.$hashtag,$parameters); + return $response; + } +} diff --git a/themes/hugo-mastodon-comments/static/comments/config.sample.php b/themes/hugo-mastodon-comments/static/comments/config.sample.php new file mode 100644 index 0000000..8cdc8f7 --- /dev/null +++ b/themes/hugo-mastodon-comments/static/comments/config.sample.php @@ -0,0 +1,7 @@ + 'https://mastodon.social', + 'user-id' => 549759, + 'threshold' => 300, + 'token' => '47598kdjhfgkdg894kejg834joejg43' +]; diff --git a/themes/hugo-mastodon-comments/static/comments/getcomments.js b/themes/hugo-mastodon-comments/static/comments/getcomments.js new file mode 100644 index 0000000..a7d5576 --- /dev/null +++ b/themes/hugo-mastodon-comments/static/comments/getcomments.js @@ -0,0 +1,50 @@ +$(document).ready(function() { + + // check if we show a blog post or not. You might have to adapt this + var isArticle = /\/?blog\/\d\d\d\d\/.+$/.test(RelPermalink); + if (isArticle === false) { + console.log("Not a blog post, no need to search for comments"); + return; + } + + $.ajax({ + url: "/comments/getcomments.php", + type: "get", + data: { + search : RelPermalink + }, + success: function(data) { + var stats = data.stats; + var root = data.stats.root; + $("#like-count-container").append('
' + stats.favs + '
'); + $("#reblog-count-container").append('
' + stats.reblogs + '
'); + $("#reply-count-container").append('
' + stats.replies + '
'); + var comments = data.comments; + $.each(comments, function(key, value) { + var timestamp = Date.parse(value.date); + var date = new Date(timestamp); + var comment = "
"; + comment += ""; + comment += "
" + value.author.display_name + " wrote at "; + comment += "" + date.toDateString() + ', ' + date.toLocaleTimeString() + "
"; + comment += "
" + value.toot + "
"; + comment += "
"; + var parentComment = document.getElementById(value.reply_to); + if (value.reply_to === root || parentComment === null) { + $("#comments").append(comment); + } else { + var selector = '#'+value.reply_to; + $(selector).append(comment); + } + }); + if (parseInt(root) > 0) { + $("#reference").append("Join the discussion on Mastodon!"); + } else { + $("#comments").empty(); + $("#statistics").empty(); + $("#reference").append("Comments are handled by my Mastodon account. Sadly this article wasn't published at Mastodon. Feel free to send me a mail if you want to share your thoughts regarding this topic."); + } + + } + }); +}); diff --git a/themes/hugo-mastodon-comments/static/comments/getcomments.php b/themes/hugo-mastodon-comments/static/comments/getcomments.php new file mode 100644 index 0000000..2743773 --- /dev/null +++ b/themes/hugo-mastodon-comments/static/comments/getcomments.php @@ -0,0 +1,189 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +require_once 'Mastodon_api.php'; +require_once '../../mastodon.feed/config.php'; + +class CollectMastodonData { + + /** @var \Mastodon_api */ + private $api; + + /** @var string url of the mastodon instance */ + private $mastodonUrl = 'https://mastodon.social'; + + /** @var string token to authenticate at the mastodon instance */ + private $bearerToken; + + /** @var int keep cache at least 600 seconds = 10 minutes */ + private $threshold = 600; + + /** @var string uid on the mastodon instance */ + private $uid; + + /** @var array cached comments from previous searches */ + private $commentCache = []; + + private $cacheFile = 'myCommentsCache.json'; + + public function __construct($config) { + $this->mastodonUrl = $config['mastodon-instance']; + $this->bearerToken = $config['token']; + $this->uid = $config['user-id']; + + $this->api = new Mastodon_api(); + + $this->api->set_url($this->mastodonUrl); + $this->api->set_token($this->bearerToken, 'bearer'); + } + + private function filterComments($descendants, $root, &$result) { + foreach ($descendants as $d) { + $result['comments'][$d['id']] = [ + 'author' => [ + 'display_name' => $d['account']['display_name'] ? $d['account']['display_name'] : $d['account']['username'], + 'avatar' => $d['account']['avatar_static'], + 'url' => $d['account']['url'] + ], + 'toot' => $d['content'], + 'date' => $d['created_at'], + 'url' => $d['uri'], + 'reply_to' => $d['in_reply_to_id'], + 'root' => $root, + ]; + } + + return $result; + } + + private function filterStats($stats) { + $result = [ + 'reblogs' => (int)$stats['reblogs_count'], + 'favs' => (int)$stats['favourites_count'], + 'replies' => (int)$stats['replies_count'], + 'url' => $stats['url'] + ]; + return $result; + } + + private function filterSearchResults($searchResult) { + $result = []; + if (isset($searchResult['html']['statuses'])) { + foreach ($searchResult['html']['statuses'] as $status) { + if ($status['in_reply_to_id'] === null) { + $result[] = $status['id']; + } + } + } + + sort($result); + return $result; + } + + /** + * find all toots for a given blog post and return the corresponding IDs + * + * @param string $search + * @return array + */ + public function findToots($search) { + $result = $this->api->search(['q' => $search]); + return $this->filterSearchResults($result); + } + + public function getComments($id, &$result) { + $raw = file_get_contents("https://mastodon.social/api/v1/statuses/$id/context"); + $json = json_decode($raw, true); + $this->filterComments($json['descendants'], $id, $result); + } + + public function getStatistics($id, &$result) { + $raw = file_get_contents("https://mastodon.social/api/v1/statuses/$id"); + $json = json_decode($raw, true); + $newStats = $this->filterStats($json); + $result['stats']['reblogs'] += $newStats['reblogs']; + $result['stats']['favs'] += $newStats['favs']; + $result['stats']['replies'] += $newStats['replies']; + if (empty($result['stats']['url'])) { + $result['stats']['url'] = $newStats['url']; + } + } + + public function storeCollection($id, $comments) { + $timestamp = time(); + $comments['timestamp'] = $timestamp; + $this->commentCache[$id] = $comments; + file_put_contents($this->cacheFile, json_encode($this->commentCache)); + } + + public function getCachedCollection($search) { + if (file_exists($this->cacheFile)) { + $cachedComments = file_get_contents($this->cacheFile); + $cachedCommentsArray = json_decode($cachedComments, true); + if (is_array($cachedCommentsArray)) { + $this->commentCache = $cachedCommentsArray; + $currentTimestamp = time(); + if (isset($cachedCommentsArray[$search])) { + if ((int)$cachedCommentsArray[$search]['timestamp'] + $this->threshold > $currentTimestamp) { + unset($cachedCommentsArray[$search]['timestamp']); + return $cachedCommentsArray[$search]; + } + } + } + } + + return []; + } +} + +$result = ['comments' => [], 'stats' => ['reblogs' => 0, 'favs' => 0, 'replies' => 0, 'url' => '', 'root' => 0]]; + +$search = isset($_GET['search']) ? $_GET['search'] : ''; +$collector = new CollectMastodonData($config); +$ids = []; +if (!empty($search)) { + $oldCollection = $collector->getCachedCollection($search); + if (empty($oldCollection)) { + $ids = $collector->findToots($search); + $result['stats']['root'] = isset($ids[0]) ? $ids[0] : 0; + foreach ($ids as $id) { + // get comments + $newComments = $collector->getComments($id, $result); + // get statistics (likes, replies, boosts,...) + $collector->getStatistics($id, $result); + // FIXME: At the moment the API doesn't return the correct replies count so I count it manually + $result['stats']['replies'] = count($result['comments']); + } + $collector->storeCollection($search, $result); + } else { + $result = $oldCollection; + } +} + +// headers for not caching the results +header('Cache-Control: no-cache, must-revalidate'); +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); + +// headers to tell that result is JSON +header('Content-type: application/json'); + +// send the result now +echo json_encode($result); diff --git a/themes/hugo-mastodon-comments/static/comments/mastodon-comments.css b/themes/hugo-mastodon-comments/static/comments/mastodon-comments.css new file mode 100644 index 0000000..615ad72 --- /dev/null +++ b/themes/hugo-mastodon-comments/static/comments/mastodon-comments.css @@ -0,0 +1,60 @@ +.comments-container .comment .avatar { + float: left; + width: 50px; + height: 50px; + margin-left: 16px; + margin-right: 16px; + border-radius: 50%; +} + +.comments-container #reference { + text-align: center; + font-size: 16px; +} + +.comments-container .comment { + margin-top: 50px; + margin-bottom: 50px; + font-size: 16px; + padding-left: 20px; +} + +.comments-container .toot { + padding-left: 82px; +} + +.comments-container .author { + padding-top: 10px; + padding-bottom: 10px; +} + +.comments-container #mastodon-like-count, +.comments-container #mastodon-reblog-count, +.comments-container #mastodon-reply-count + { + float: right; + font-size: 16px; + background: #eee; + padding: 3px 10px; + margin: 30px 5px; + border-radius: 5px; +} + +.comments-container #mastodon-like-count a, +.comments-container #mastodon-reblog-count a, +.comments-container #mastodon-reply-count a + { + color: #333333; +} + +.comments-container #mastodon-like-count a:hover, +.comments-container #mastodon-reblog-count a:hover, +.comments-container #mastodon-reply-count a:hover + { + color: black; + text-decoration: none; +} + +.comments-container .fa { + padding-right: 10px; +} diff --git a/themes/hugo-mastodon-comments/theme.yaml b/themes/hugo-mastodon-comments/theme.yaml new file mode 100644 index 0000000..c5b6933 --- /dev/null +++ b/themes/hugo-mastodon-comments/theme.yaml @@ -0,0 +1,16 @@ +# theme.yaml configuration file + +name: Mastodon Comments +license: AGPL-3.0-or-later +licenselink: +description: Hugo theme component for scraping comments on a Mastodon post containing a site's address +homepage: +tags: + - component +features: + - comments +min_version: 0.40.0 + +author: + name: Björn Schießle, Max Mehl + homepage: diff --git a/themes/hugo-sustain/images/screenshot.png b/themes/hugo-sustain/images/screenshot.png deleted file mode 100644 index 2f72814..0000000 Binary files a/themes/hugo-sustain/images/screenshot.png and /dev/null differ diff --git a/themes/hugo-sustain/images/tn.png b/themes/hugo-sustain/images/tn.png deleted file mode 100644 index e401ec3..0000000 Binary files a/themes/hugo-sustain/images/tn.png and /dev/null differ diff --git a/themes/hugo-sustain/layouts/_default/list.html b/themes/hugo-sustain/layouts/_default/list.html index 211d75a..70e2019 100644 --- a/themes/hugo-sustain/layouts/_default/list.html +++ b/themes/hugo-sustain/layouts/_default/list.html @@ -1,31 +1,43 @@ {{ partial "head" . }} - -
- - {{ partial "header" . }} -
-

Archive

-
-
- {{ range .Data.Pages.ByPublishDate.Reverse }} -
-
-
- {{ .Date.Format "January 2, 2006" }} -
-
- -
- {{ end }} + +
+ + {{ partial "header" . }} +
+

{{ .Site.Params.Blog.Headline }} + {{ if (isset .Data "Singular") }} +
({{ .Data.Singular | humanize }}: {{lower .Title}}) + + {{ else }} + + {{ end }} +

+ {{ if .Site.Params.Social.CommentsProvider }} +

Subscribe to my Blog via Diaspora, Mastodon, Friendica or GNU Social. Never miss a article! Reshare, like and discuss it!

+ {{ end }} +

+ All + {{ range $name, $taxonomy := .Site.Taxonomies.categories }} + + {{ humanize $name }} + + {{ end }} +

+ +
+
+ {{ range .Data.Pages.ByPublishDate.Reverse }} +
+

{{ .Title | markdownify }}

+ +

{{ .Summary }}

-
+ {{ end }} +
- - {{ partial "footer" . }} - +
+ + {{ partial "footer" . }} + diff --git a/themes/hugo-sustain/layouts/_default/single.html b/themes/hugo-sustain/layouts/_default/single.html index 815c958..bf3be93 100644 --- a/themes/hugo-sustain/layouts/_default/single.html +++ b/themes/hugo-sustain/layouts/_default/single.html @@ -6,24 +6,27 @@ {{ partial "header" . }}
-

{{ .Title }}

-
{{ if ne .Params.page true }} -
-

- {{ .Date.Format "January 2, 2006" }} +
+

+ {{ .Date.Format "2 January 2006" }}    {{ range .Params.tags }} - {{ . }} - + {{ . }} {{ end }} -

+

{{ end }}
+ {{ if isset .Params "headerimage" }} +
+ +

{{ with .Params.headercredits }}{{ . | markdownify }}{{ end }}

+
+ {{ end }} {{ .Content }} {{ if or (eq .Params.related true) (ne .Params.page true) }} @@ -34,7 +37,7 @@
- {{ .Date.Format "January 2, 2006" }} + {{ .Date.Format "2 January 2006" }}
@@ -49,6 +52,7 @@

+ {{ partial "comments.html" . }} {{ partial "social" . }}
diff --git a/layouts/partials/matomo.html b/themes/hugo-sustain/layouts/partials/matomo.html similarity index 100% rename from layouts/partials/matomo.html rename to themes/hugo-sustain/layouts/partials/matomo.html diff --git a/layouts/shortcodes/links.html b/themes/hugo-sustain/layouts/shortcodes/links.html similarity index 100% rename from layouts/shortcodes/links.html rename to themes/hugo-sustain/layouts/shortcodes/links.html diff --git a/layouts/sitemap.xml b/themes/hugo-sustain/layouts/sitemap.xml similarity index 100% rename from layouts/sitemap.xml rename to themes/hugo-sustain/layouts/sitemap.xml diff --git a/static/css/bootstrap-3.3.7.min.css b/themes/hugo-sustain/static/css/bootstrap-3.3.7.min.css similarity index 100% rename from static/css/bootstrap-3.3.7.min.css rename to themes/hugo-sustain/static/css/bootstrap-3.3.7.min.css diff --git a/static/css/custom.css b/themes/hugo-sustain/static/css/custom.css similarity index 50% rename from static/css/custom.css rename to themes/hugo-sustain/static/css/custom.css index e213fb5..c7f394d 100644 --- a/static/css/custom.css +++ b/themes/hugo-sustain/static/css/custom.css @@ -11,13 +11,24 @@ div.footer { .container a:hover { color: #12437A; } -div.container.links .label-success { +.container .label-success { background-color: rgba(92, 139, 184, 0.6); + color: #FFF; } -div.container h1 { +.container a.label-success:hover { + background-color: rgba(92, 139, 184, 0.9); + color: #FFF; +} +.container h1 { font-weight: bold; color: #0D76EC; } +.container h4 a { + color: #0D76EC; +} +.container h4 a:hover { + color: #0060CC; +} /* Avoid scrollbar jumps in centering * see https://css-tricks.com/eliminate-jumps-in-horizontal-centering-by-forcing-a-scroll-bar/ @@ -63,3 +74,49 @@ div.contact p { .social-links li a:hover i { transform: scale(1); } + +/* BLOG */ +.categories { + font-size: 18px; + margin: 1em 0 3em 0; +} +.blog-summary { + padding-bottom: 1em; +} +.metadata { + font-size: 0.8em; + opacity: 0.7; +} +.blogpost .header-image img { + width: 100%; + height: auto; + padding-bottom: 2px; +} +.blogpost .header-image p { + opacity: 0.7; + font-size: 0.8em; + text-align: center; + line-height: 1em; + margin-bottom: 1.5em; +} + +a.learn-more { + font-size: 1.8em; + line-height: 0.8em; + font-weight: 700; + font-variant: small-caps; + text-transform: lowercase; + padding: 0 1em 0 .3em; + position: absolute; +} +a.learn-more::after { + position: absolute; + right: 0.3em; + content: " » "; + opacity: .8; + transition: all 150ms linear; +} +a.learn-more:hover::after { + right: 0; + opacity: 1; +} diff --git a/static/css/fontawesome/css/all.min.css b/themes/hugo-sustain/static/css/fontawesome/css/all.min.css similarity index 100% rename from static/css/fontawesome/css/all.min.css rename to themes/hugo-sustain/static/css/fontawesome/css/all.min.css diff --git a/static/css/fontawesome/webfonts/fa-brands-400.eot b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.eot similarity index 100% rename from static/css/fontawesome/webfonts/fa-brands-400.eot rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.eot diff --git a/static/css/fontawesome/webfonts/fa-brands-400.svg b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.svg similarity index 100% rename from static/css/fontawesome/webfonts/fa-brands-400.svg rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.svg diff --git a/static/css/fontawesome/webfonts/fa-brands-400.ttf b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.ttf similarity index 100% rename from static/css/fontawesome/webfonts/fa-brands-400.ttf rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.ttf diff --git a/static/css/fontawesome/webfonts/fa-brands-400.woff b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.woff similarity index 100% rename from static/css/fontawesome/webfonts/fa-brands-400.woff rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.woff diff --git a/static/css/fontawesome/webfonts/fa-brands-400.woff2 b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.woff2 similarity index 100% rename from static/css/fontawesome/webfonts/fa-brands-400.woff2 rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-brands-400.woff2 diff --git a/static/css/fontawesome/webfonts/fa-regular-400.eot b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.eot similarity index 100% rename from static/css/fontawesome/webfonts/fa-regular-400.eot rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.eot diff --git a/static/css/fontawesome/webfonts/fa-regular-400.svg b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.svg similarity index 100% rename from static/css/fontawesome/webfonts/fa-regular-400.svg rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.svg diff --git a/static/css/fontawesome/webfonts/fa-regular-400.ttf b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.ttf similarity index 100% rename from static/css/fontawesome/webfonts/fa-regular-400.ttf rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.ttf diff --git a/static/css/fontawesome/webfonts/fa-regular-400.woff b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.woff similarity index 100% rename from static/css/fontawesome/webfonts/fa-regular-400.woff rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.woff diff --git a/static/css/fontawesome/webfonts/fa-regular-400.woff2 b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.woff2 similarity index 100% rename from static/css/fontawesome/webfonts/fa-regular-400.woff2 rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-regular-400.woff2 diff --git a/static/css/fontawesome/webfonts/fa-solid-900.eot b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.eot similarity index 100% rename from static/css/fontawesome/webfonts/fa-solid-900.eot rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.eot diff --git a/static/css/fontawesome/webfonts/fa-solid-900.svg b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.svg similarity index 100% rename from static/css/fontawesome/webfonts/fa-solid-900.svg rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.svg diff --git a/static/css/fontawesome/webfonts/fa-solid-900.ttf b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.ttf similarity index 100% rename from static/css/fontawesome/webfonts/fa-solid-900.ttf rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.ttf diff --git a/static/css/fontawesome/webfonts/fa-solid-900.woff b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.woff similarity index 100% rename from static/css/fontawesome/webfonts/fa-solid-900.woff rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.woff diff --git a/static/css/fontawesome/webfonts/fa-solid-900.woff2 b/themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.woff2 similarity index 100% rename from static/css/fontawesome/webfonts/fa-solid-900.woff2 rename to themes/hugo-sustain/static/css/fontawesome/webfonts/fa-solid-900.woff2 diff --git a/static/css/fonts.css b/themes/hugo-sustain/static/css/fonts.css similarity index 100% rename from static/css/fonts.css rename to themes/hugo-sustain/static/css/fonts.css diff --git a/static/css/tomorrow-9.7.0.min.css b/themes/hugo-sustain/static/css/tomorrow-9.7.0.min.css similarity index 100% rename from static/css/tomorrow-9.7.0.min.css rename to themes/hugo-sustain/static/css/tomorrow-9.7.0.min.css diff --git a/static/fonts/source-sans-pro-v11-latin-200.eot b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.eot similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-200.eot rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.eot diff --git a/static/fonts/source-sans-pro-v11-latin-200.svg b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.svg similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-200.svg rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.svg diff --git a/static/fonts/source-sans-pro-v11-latin-200.ttf b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.ttf similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-200.ttf rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.ttf diff --git a/static/fonts/source-sans-pro-v11-latin-200.woff b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.woff similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-200.woff rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.woff diff --git a/static/fonts/source-sans-pro-v11-latin-200.woff2 b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.woff2 similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-200.woff2 rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-200.woff2 diff --git a/static/fonts/source-sans-pro-v11-latin-regular.eot b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.eot similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-regular.eot rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.eot diff --git a/static/fonts/source-sans-pro-v11-latin-regular.svg b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.svg similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-regular.svg rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.svg diff --git a/static/fonts/source-sans-pro-v11-latin-regular.ttf b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.ttf similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-regular.ttf rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.ttf diff --git a/static/fonts/source-sans-pro-v11-latin-regular.woff b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.woff similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-regular.woff rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.woff diff --git a/static/fonts/source-sans-pro-v11-latin-regular.woff2 b/themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.woff2 similarity index 100% rename from static/fonts/source-sans-pro-v11-latin-regular.woff2 rename to themes/hugo-sustain/static/fonts/source-sans-pro-v11-latin-regular.woff2 diff --git a/static/js/bootstrap-3.3.7.min.js b/themes/hugo-sustain/static/js/bootstrap-3.3.7.min.js similarity index 100% rename from static/js/bootstrap-3.3.7.min.js rename to themes/hugo-sustain/static/js/bootstrap-3.3.7.min.js diff --git a/static/js/highlight-9.7.0.min.js b/themes/hugo-sustain/static/js/highlight-9.7.0.min.js similarity index 100% rename from static/js/highlight-9.7.0.min.js rename to themes/hugo-sustain/static/js/highlight-9.7.0.min.js diff --git a/static/js/jquery-1.11.3.min.js b/themes/hugo-sustain/static/js/jquery-1.11.3.min.js similarity index 100% rename from static/js/jquery-1.11.3.min.js rename to themes/hugo-sustain/static/js/jquery-1.11.3.min.js