├── LICENSE ├── README.md ├── archetypes ├── default.md └── post-bundle │ ├── image.jpeg │ └── index.md ├── assets ├── js │ ├── fuse.basic.min.js │ └── search.js └── scss │ ├── article.scss │ ├── external │ └── reset.scss │ ├── footer.scss │ ├── header.scss │ ├── pagination.scss │ ├── post.scss │ ├── profile.scss │ ├── search.scss │ ├── style.scss │ └── tags.scss ├── go.mod ├── images ├── screenshot.png └── tn.png ├── layouts ├── 404.html ├── _default │ ├── _markup │ │ └── render-codeblock.html │ ├── baseof.html │ ├── index.json │ ├── list.html │ ├── search.html │ ├── single.html │ └── summary.html ├── index.html └── partials │ ├── footer.html │ ├── head.html │ ├── header.html │ ├── icons.html │ ├── pagination.html │ └── profile.html └── theme.toml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 nightswinger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hugo Theme Coyote 2 | 3 | ## Demo 4 | 5 | [Example Site](https://nightswinger.github.io/hugo-theme-coyote/) 6 | 7 | ## Quick Start 8 | 9 | ### Install 10 | 11 | Clone this repo to `themes` folder: 12 | 13 | ```bash 14 | git clone https://github.com/nightswinger/hugo-theme-coyote.git themes/coyote --depth=1 15 | ``` 16 | 17 | Then, add the theme to your site config: 18 | 19 | ```bash 20 | echo theme = \"coyote\" >> config.toml 21 | ``` 22 | 23 | ### Add Search Page 24 | 25 | Add the following to your `config.toml` 26 | 27 | ```toml 28 | [outputs] 29 | home = ['HTML', 'JSON'] 30 | ``` 31 | 32 | Create a file with `search.md` in `content` directory 33 | 34 | ```text 35 | --- 36 | title: "Search" 37 | layout: "search" 38 | --- 39 | ``` 40 | 41 | ### Create Content 42 | 43 | You can create a new content file using archetype template 44 | 45 | ```bash 46 | hugo new --kind post-bundle posts/my-first-post 47 | ``` 48 | 49 | ## Features 50 | 51 | * **Search** supported by [Fuse.js](https://github.com/krisk/Fuse) 52 | * **Google Analytics** supported 53 | -------------------------------------------------------------------------------- /archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | # tags: 6 | # - tagA 7 | # - tagB 8 | --- 9 | -------------------------------------------------------------------------------- /archetypes/post-bundle/image.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightswinger/hugo-theme-coyote/4f77317d777c19102cba2f6f271a94645b70ad26/archetypes/post-bundle/image.jpeg -------------------------------------------------------------------------------- /archetypes/post-bundle/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | image: "image.jpeg" 5 | draft: true 6 | # tags: 7 | # - tagA 8 | # - tagB 9 | --- 10 | -------------------------------------------------------------------------------- /assets/js/fuse.basic.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fuse.js v6.6.2 - Lightweight fuzzy-search (http://fusejs.io) 3 | * 4 | * Copyright (c) 2022 Kiro Risk (http://kiro.me) 5 | * All Rights Reserved. Apache Software License 2.0 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | */ 9 | var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(_).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),a=parseFloat(Math.round(o*r)/r);return n.set(i,a),a},clear:function(){n.clear()}}}var O=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?L.getFn:n,o=t.fieldNormWeight,a=void 0===o?L.fieldNormWeight:o;r(this,e),this.norm=S(a,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,u(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();u(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?L.getFn:r,o=n.fieldNormWeight,a=void 0===o?L.fieldNormWeight:o,c=new O({getFn:i,fieldNormWeight:a});return c.setKeys(e.map(k)),c.setSources(t),c.create(),c}function j(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,a=t.expectedLocation,c=void 0===a?0:a,s=t.distance,h=void 0===s?L.distance:s,u=t.ignoreLocation,l=void 0===u?L.ignoreLocation:u,d=r/e.length;if(l)return d;var f=Math.abs(c-o);return h?d+f/h:f?1:d}function E(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:L.minMatchCharLength,n=[],r=-1,i=-1,o=0,a=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}var I=32;function F(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,a=void 0===o?L.location:o,c=i.threshold,s=void 0===c?L.threshold:c,h=i.distance,u=void 0===h?L.distance:h,l=i.includeMatches,d=void 0===l?L.includeMatches:l,f=i.findAllMatches,v=void 0===f?L.findAllMatches:f,g=i.minMatchCharLength,y=void 0===g?L.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?L.isCaseSensitive:p,b=i.ignoreLocation,k=void 0===b?L.ignoreLocation:b;if(r(this,e),this.options={location:a,threshold:s,distance:u,includeMatches:d,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:k},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var M=function(e,t){n.chunks.push({pattern:e,alphabet:F(e),startIndex:t})},w=this.pattern.length;if(w>I){for(var x=0,_=w%I,S=w-_;x3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?L.location:i,a=r.distance,c=void 0===a?L.distance:a,s=r.threshold,h=void 0===s?L.threshold:s,u=r.findAllMatches,l=void 0===u?L.findAllMatches:u,d=r.minMatchCharLength,f=void 0===d?L.minMatchCharLength:d,v=r.includeMatches,g=void 0===v?L.includeMatches:v,y=r.ignoreLocation,m=void 0===y?L.ignoreLocation:y;if(t.length>I)throw new Error(p(I));for(var b,k=t.length,M=e.length,w=Math.max(0,Math.min(o,M)),x=h,_=w,S=f>1||g,O=S?Array(M):[];(b=e.indexOf(t,_))>-1;){var A=j(t,{currentLocation:b,expectedLocation:w,distance:c,ignoreLocation:m});if(x=Math.min(A,x),_=b+k,S)for(var F=0;F=T;R-=1){var U=R-1,B=n[e.charAt(U)];if(S&&(O[U]=+!!B),J[R]=(J[R+1]<<1|1)&B,$&&(J[R]|=(C[R+1]|C[R])<<1|1|C[R+1]),J[R]&W&&(N=j(t,{errors:$,currentLocation:U,expectedLocation:w,distance:c,ignoreLocation:m}))<=x){if(x=N,(_=U)<=w)break;T=Math.max(1,2*w-_)}}if(j(t,{errors:$+1,currentLocation:w,expectedLocation:w,distance:c,ignoreLocation:m})>x)break;C=J}var V={isMatch:_>=0,score:Math.max(.001,N)};if(S){var q=E(O,f);q.length?g&&(V.indices=q):V.isMatch=!1}return V}(e,n,i,{location:a+o,distance:s,threshold:h,findAllMatches:u,minMatchCharLength:l,includeMatches:r,ignoreLocation:d}),m=y.isMatch,b=y.score,k=y.indices;m&&(g=!0),v+=b,m&&k&&(f=[].concat(c(f),c(k)))}));var y={isMatch:g,score:g?v/this.chunks.length:1};return g&&r&&(y.indices=f),y}}]),e}(),N=[];function P(e,t){for(var n=0,r=N.length;n-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function D(e,t){t.score=e.score}function K(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?L.includeMatches:r,o=n.includeScore,a=void 0===o?L.includeScore:o,c=[];return i&&c.push($),a&&c.push(D),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return c.length&&c.forEach((function(t){t(e,r)})),r}))}var T=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;if(r(this,e),this.options=t(t({},L),i),this.options.useExtendedSearch)throw new Error(y);this._keyStore=new b(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof O))throw new Error("Incorrect 'index' type");this._myIndex=t||A(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){f(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.limit,r=void 0===n?-1:n,i=this.options,o=i.includeMatches,a=i.includeScore,c=i.shouldSort,s=i.sortFn,h=i.ignoreFieldNorm,d=u(e)?u(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return W(d,{ignoreFieldNorm:h}),c&&d.sort(s),l(r)&&r>-1&&(d=d.slice(0,r)),K(d,this._docs,{includeMatches:o,includeScore:a})}},{key:"_searchStringList",value:function(e){var t=P(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(f(n)){var a=t.searchIn(n),c=a.isMatch,s=a.score,h=a.indices;c&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:h}]})}})),r}},{key:"_searchLogical",value:function(e){throw new Error("Logical search is not available")}},{key:"_searchObjectList",value:function(e){var t=this,n=P(e,this.options),r=this._myIndex,i=r.keys,o=r.records,a=[];return o.forEach((function(e){var r=e.$,o=e.i;if(f(r)){var s=[];i.forEach((function(e,i){s.push.apply(s,c(t._findMatches({key:e,value:r[i],searcher:n})))})),s.length&&a.push({idx:o,item:r,matches:s})}})),a}},{key:"_findMatches",value:function(e){var t=e.key,n=e.value,r=e.searcher;if(!f(n))return[];var i=[];if(h(n))n.forEach((function(e){var n=e.v,o=e.i,a=e.n;if(f(n)){var c=r.searchIn(n),s=c.isMatch,h=c.score,u=c.indices;s&&i.push({score:h,key:t,value:n,idx:o,norm:a,indices:u})}}));else{var o=n.v,a=n.n,c=r.searchIn(o),s=c.isMatch,u=c.score,l=c.indices;s&&i.push({score:u,key:t,value:o,norm:a,indices:l})}return i}}]),e}();return T.version="6.6.2",T.createIndex=A,T.parseIndex=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?L.getFn:n,i=t.fieldNormWeight,o=void 0===i?L.fieldNormWeight:i,a=e.keys,c=e.records,s=new O({getFn:r,fieldNormWeight:o});return s.setKeys(a),s.setIndexRecords(c),s},T.config=L,T},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); -------------------------------------------------------------------------------- /assets/js/search.js: -------------------------------------------------------------------------------- 1 | let fuse 2 | const fuseOptions = { 3 | shouldSort: true, 4 | includeMatches: true, 5 | threshold: 0.0, 6 | tokenize:true, 7 | ignoreLocation: true, 8 | distance: 100, 9 | maxPatternLength: 32, 10 | minMatchCharLength: 1, 11 | keys: [ 12 | {name:"title",weight:0.8}, 13 | {name:"contents",weight:0.5}, 14 | {name:"tags",weight:0.3}, 15 | {name:"categories",weight:0.3} 16 | ] 17 | } 18 | 19 | window.onload = function () { 20 | fetch('../index.json') 21 | .then(resp => resp.json()) 22 | .then(data => { 23 | fuse = new Fuse(data, fuseOptions) 24 | }) 25 | } 26 | 27 | const input = document.getElementById('searchInput') 28 | const results = document.getElementById('searchResults') 29 | 30 | input.addEventListener('keyup', (e) => { 31 | const items = fuse.search(e.target.value) 32 | 33 | if (items.length > 0) { 34 | let itemList = '' 35 | 36 | for (let i in items) { 37 | itemList += `
` 38 | + `
` 39 | + `
` 40 | + `

${items[i].item.title}

` 41 | + `` 42 | + `
` 43 | + `
` 44 | } 45 | 46 | results.innerHTML = itemList 47 | } else { 48 | results.innerHTML = '' 49 | } 50 | }) 51 | 52 | // Prevent search clears 53 | input.addEventListener('keydown', (e) => { 54 | if (e.key === "Enter") { 55 | e.preventDefault() 56 | } 57 | }) 58 | -------------------------------------------------------------------------------- /assets/scss/article.scss: -------------------------------------------------------------------------------- 1 | .article-list { 2 | display: grid; 3 | gap: 2.4rem 1.6rem; 4 | grid-template-columns: repeat(2, 1fr); 5 | padding: 3.2rem 1.6rem; 6 | 7 | @media screen and (min-width: 768px) { 8 | grid-template-columns: repeat(3, 1fr); 9 | } 10 | } 11 | 12 | .article { 13 | position: relative; 14 | display: flex; 15 | flex-direction: column; 16 | border-radius: 8px; 17 | box-shadow: 0 4px 8px -2px #000a3c1a; 18 | background-color: #fff; 19 | overflow: hidden; 20 | transition: box-shadow .2s; 21 | 22 | &:hover { 23 | box-shadow: 0 6px 12px -4px #001b4433; 24 | } 25 | 26 | &__inner { 27 | color: #111111; 28 | text-decoration: none; 29 | flex: 1; 30 | } 31 | 32 | &__header { 33 | position: relative; 34 | padding-top: 50%; 35 | } 36 | 37 | &__image { 38 | position: absolute; 39 | top: 0; 40 | left: 0; 41 | max-width: none; 42 | width: 100%; 43 | height: 100%; 44 | object-fit: cover; 45 | } 46 | 47 | &__text { 48 | padding-top: 1.2rem; 49 | padding-right: 1.6rem; 50 | padding-left: 1.6rem; 51 | } 52 | 53 | &__title { 54 | font-size: 1.6rem; 55 | font-weight: 700; 56 | line-height: 1.5; 57 | overflow: hidden; 58 | } 59 | 60 | &__footer { 61 | padding: 1rem 1.4rem 1.6rem; 62 | color: #93a5b1; 63 | font-size: 1.1rem; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /assets/scss/external/reset.scss: -------------------------------------------------------------------------------- 1 | /* Box sizing rules */ 2 | *, 3 | *::before, 4 | *::after { 5 | box-sizing: border-box; 6 | } 7 | 8 | /* Remove default margin */ 9 | body, 10 | h1, 11 | h2, 12 | h3, 13 | h4, 14 | p, 15 | figure, 16 | blockquote, 17 | dl, 18 | dd { 19 | margin: 0; 20 | } 21 | 22 | /* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */ 23 | ul[role="list"], 24 | ol[role="list"] { 25 | list-style: none; 26 | } 27 | 28 | /* Set core root defaults */ 29 | html:focus-within { 30 | scroll-behavior: smooth; 31 | } 32 | 33 | /* Set core body defaults */ 34 | body { 35 | min-height: 100vh; 36 | text-rendering: optimizeSpeed; 37 | line-height: 1.5; 38 | } 39 | 40 | /* A elements that don't have a class get default styles */ 41 | a:not([class]) { 42 | text-decoration-skip-ink: auto; 43 | } 44 | 45 | /* Make images easier to work with */ 46 | img, 47 | picture { 48 | max-width: 100%; 49 | display: block; 50 | } 51 | 52 | /* Inherit fonts for inputs and buttons */ 53 | input, 54 | button, 55 | textarea, 56 | select { 57 | font: inherit; 58 | } 59 | 60 | /* Remove all animations and transitions for people that prefer not to see them */ 61 | @media (prefers-reduced-motion: reduce) { 62 | html:focus-within { 63 | scroll-behavior: auto; 64 | } 65 | *, 66 | *::before, 67 | *::after { 68 | animation-duration: 0.01ms !important; 69 | animation-iteration-count: 1 !important; 70 | transition-duration: 0.01ms !important; 71 | scroll-behavior: auto !important; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /assets/scss/footer.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | text-align: center; 3 | color: #6c6c6c; 4 | padding: 1.6rem 2.4rem; 5 | font-size: 1.1rem; 6 | } 7 | -------------------------------------------------------------------------------- /assets/scss/header.scss: -------------------------------------------------------------------------------- 1 | .header { 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | max-width: 1200px; 6 | margin-right: auto; 7 | margin-left: auto; 8 | margin-bottom: 2.5rem; 9 | padding: 0 1.6rem; 10 | 11 | &__title { 12 | font-size: 2.8rem; 13 | font-family: 'Eczar', serif; 14 | margin: 1.6rem 0; 15 | } 16 | } 17 | 18 | .headerNav { 19 | &__items { 20 | list-style: none; 21 | 22 | > li { 23 | font-size: 1.4rem; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /assets/scss/pagination.scss: -------------------------------------------------------------------------------- 1 | .pagination { 2 | display: flex; 3 | justify-content: center; 4 | gap: 1.6rem; 5 | margin: 1.6rem auto 3.2rem; 6 | 7 | &__item { 8 | text-align: center; 9 | } 10 | 11 | &__link { 12 | display: block; 13 | min-width: 40px; 14 | padding: 12px; 15 | color: #111; 16 | background-color: #ebeef2; 17 | border-radius: 8px; 18 | 19 | &--current { 20 | background-color: #5486cc; 21 | color: #fff; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /assets/scss/post.scss: -------------------------------------------------------------------------------- 1 | .post { 2 | max-width: 768px; 3 | padding: 1.6rem 3.2rem; 4 | margin: 0 auto; 5 | 6 | &__header { 7 | position: relative; 8 | padding-top: 50%; 9 | border-radius: 8px; 10 | overflow: hidden; 11 | } 12 | 13 | &__image { 14 | position: absolute; 15 | top: 0; 16 | left: 0; 17 | width: 100%; 18 | height: 100%; 19 | object-fit: cover; 20 | } 21 | 22 | h1 { 23 | & + p { 24 | margin-top: 0.3em; 25 | } 26 | } 27 | 28 | h1, 29 | h2 { 30 | margin-top: 2.3em; 31 | margin-bottom: 0.5em; 32 | } 33 | h3, 34 | h4, 35 | h5, 36 | h6 { 37 | margin-top: 2.25em; 38 | margin-bottom: 0.5em; 39 | } 40 | 41 | h1 { 42 | padding-bottom: 0.5rem; 43 | font-size: 2.7rem; 44 | position: relative; 45 | border-bottom: solid 1px #5c93bb2b 46 | } 47 | h2 { 48 | font-size: 2.4rem; 49 | } 50 | h3 { 51 | font-size: 2.1rem; 52 | } 53 | h4 { 54 | font-size: 1.8rem; 55 | } 56 | h5 { 57 | font-size: 1.6rem; 58 | } 59 | h6 { 60 | font-size: 1.5rem; 61 | } 62 | 63 | p { 64 | font-size: 1.5rem; 65 | line-height: 1.8; 66 | } 67 | p + p { 68 | margin-top: 1.5em; 69 | } 70 | 71 | p > a { 72 | color: #0f83fd; 73 | 74 | &:hover { 75 | text-decoration: underline; 76 | } 77 | } 78 | 79 | blockquote { 80 | font-size: 0.97em; 81 | margin: 1.4rem 0; 82 | border-left: solid 3px #9dacb7; 83 | padding: 2px 0 2px 0.7em; 84 | color: #505c64; 85 | p { 86 | margin: 1rem 0; 87 | } 88 | & > :first-child { 89 | margin-top: 0; 90 | } 91 | 92 | & > :last-child { 93 | margin-bottom: 0; 94 | } 95 | } 96 | 97 | code { 98 | padding: 0.2em 0.4em; 99 | background: rgba(33, 90, 160, 0.07); 100 | font-size: 0.85em; 101 | border-radius: 4px; 102 | vertical-align: 0.08em; 103 | } 104 | 105 | table { 106 | margin: 2rem auto; 107 | width: auto; 108 | border-collapse: collapse; 109 | font-size: 1.4rem; 110 | line-height: 1.5; 111 | word-break: normal; 112 | display: block; 113 | overflow: auto; 114 | -webkit-overflow-scrolling: touch; 115 | } 116 | th, 117 | td { 118 | padding: 0.8rem; 119 | border: solid 1px #cfdce6; 120 | background: #fff; 121 | } 122 | th { 123 | font-weight: 700; 124 | background: #edf2f7; 125 | } 126 | 127 | pre { 128 | margin: 1.6rem 0; 129 | background: #1a2638; 130 | overflow-x: auto; 131 | -webkit-overflow-scrolling: touch; 132 | border-radius: 8px; 133 | box-shadow: 0 4px 6px -1px rgba(0, 14, 30, 0.15); 134 | word-break: normal; 135 | word-wrap: normal; 136 | display: flex; 137 | &:after { 138 | content: ''; 139 | width: 8px; 140 | flex-shrink: 0; 141 | } 142 | code { 143 | margin: 0; 144 | padding: 0; 145 | background: transparent; 146 | font-size: 1.4rem; 147 | color: #fff; 148 | } 149 | & > code { 150 | display: block; 151 | padding: 1.6rem; 152 | } 153 | } 154 | .code-block-container { 155 | position: relative; 156 | margin: 1.3rem 0; 157 | pre { 158 | margin: 0; 159 | } 160 | } 161 | .code-block-filename { 162 | display: table; 163 | max-width: 100%; 164 | background: #323e52; 165 | color: rgba(255, 255, 255, 0.9); 166 | font-size: 1.2rem; 167 | line-height: 1.3; 168 | border-radius: 8px 8px 0 0; 169 | padding: 6px 12px 20px; 170 | margin-bottom: -16px; 171 | } 172 | .code-block-filename-container + pre { 173 | border-top-left-radius: 0; 174 | } 175 | 176 | ol, 177 | ul { 178 | font-size: 1.5rem; 179 | margin: 2.2rem 0; 180 | line-height: 1.8; 181 | } 182 | ol, 183 | ul { 184 | margin: 0; 185 | } 186 | } 187 | 188 | .post__tags { 189 | display: flex; 190 | flex-flow: row wrap; 191 | gap: 8px; 192 | margin: 1.6rem 0; 193 | 194 | + .post__content { 195 | #title { 196 | margin-top: 3.2rem; 197 | } 198 | } 199 | } 200 | .post__tag { 201 | font-size: 1.3rem; 202 | color: #fff; 203 | background-color: #35475c; 204 | padding: 0.6rem 1.2rem; 205 | display: inline-block; 206 | border-radius: 6px; 207 | } 208 | -------------------------------------------------------------------------------- /assets/scss/profile.scss: -------------------------------------------------------------------------------- 1 | .profile { 2 | &__inner { 3 | padding: 3.2rem 1.6rem; 4 | display: flex; 5 | } 6 | 7 | &__name { 8 | font-size: 1.8rem; 9 | } 10 | 11 | &__description { 12 | color: #bababa; 13 | font-size: 1.4rem; 14 | margin-top: 0.6rem; 15 | margin-bottom: 0.6rem; 16 | } 17 | } -------------------------------------------------------------------------------- /assets/scss/search.scss: -------------------------------------------------------------------------------- 1 | .search-container { 2 | max-width: 720px; 3 | padding: 3.2rem 1.6rem; 4 | margin: 0 auto; 5 | } 6 | 7 | .search { 8 | position: relative; 9 | display: flex; 10 | align-items: center; 11 | border: 1px solid #e6e3ed; 12 | border-radius: 20px; 13 | margin-bottom: 3.2rem; 14 | 15 | &__label { 16 | position: absolute; 17 | left: 1.6rem; 18 | color: #93a5b1; 19 | } 20 | 21 | &__input { 22 | width: 100%; 23 | padding: 1.2rem 1.2rem 1.2rem 4.8rem; 24 | font-size: 1.5rem; 25 | line-height: 2rem; 26 | border: 0; 27 | border-radius: inherit; 28 | outline: none; 29 | } 30 | } 31 | 32 | .results { 33 | display: flex; 34 | flex-direction: column; 35 | gap: 2.4rem; 36 | } 37 | 38 | .resultItem { 39 | display: flex; 40 | 41 | &__media { 42 | width: 80px; 43 | height: 80px; 44 | background-position: center; 45 | background-size: cover; 46 | border-radius: 8px; 47 | } 48 | 49 | &__body { 50 | padding: 0 1.6rem; 51 | } 52 | 53 | &__title { 54 | font-size: 1.8rem; 55 | font-weight: 700; 56 | margin-bottom: 0.4rem; 57 | } 58 | 59 | &__footer { 60 | color: #93a5b1; 61 | font-size: 1.1rem; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /assets/scss/style.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Eczar:wght@700&display=swap'); 2 | 3 | @import "external/reset.scss"; 4 | @import "article.scss"; 5 | @import "footer.scss"; 6 | @import "header.scss"; 7 | @import "post.scss"; 8 | @import "profile.scss"; 9 | @import "pagination.scss"; 10 | @import "search.scss"; 11 | @import "tags.scss"; 12 | 13 | html { 14 | font-size: 62.50%; 15 | } 16 | a { 17 | color: #1e1e1e; 18 | text-decoration: none; 19 | } 20 | .container { 21 | max-width: 960px; 22 | margin: 0 auto; 23 | } 24 | .main { 25 | min-height: calc(100vh - 87px - 48.5px); 26 | } 27 | .not-found { 28 | height: 70vh; 29 | display: flex; 30 | flex-direction: column; 31 | justify-content: center; 32 | align-items: center; 33 | font-size: 12rem; 34 | 35 | span { 36 | font-size: 2.4rem; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /assets/scss/tags.scss: -------------------------------------------------------------------------------- 1 | .tags { 2 | max-width: 768px; 3 | padding: 1.6rem 3.2rem; 4 | margin: 0 auto; 5 | 6 | &__header { 7 | display: flex; 8 | align-items: center; 9 | gap: 4px; 10 | margin-bottom: 4.8rem; 11 | } 12 | 13 | &__title { 14 | font-size: 1.8rem; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nightswinger/hugo-theme-coyote 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightswinger/hugo-theme-coyote/4f77317d777c19102cba2f6f271a94645b70ad26/images/screenshot.png -------------------------------------------------------------------------------- /images/tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightswinger/hugo-theme-coyote/4f77317d777c19102cba2f6f271a94645b70ad26/images/tn.png -------------------------------------------------------------------------------- /layouts/404.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |

404

4 | page not found 5 |
6 | {{ end }} 7 | -------------------------------------------------------------------------------- /layouts/_default/_markup/render-codeblock.html: -------------------------------------------------------------------------------- 1 |
2 | {{- $name := .Attributes.name -}} 3 |
4 | {{ with $name }}{{ . }}{{ end }} 5 |
6 |
7 | {{- highlight (.Inner | safeHTML) .Type .Options }} 8 |
9 |
-------------------------------------------------------------------------------- /layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{- partial "head.html" . -}} 5 | 6 | 7 | 8 | {{- partial "header.html" . -}} 9 |
10 |
11 | {{ block "main" . }} 12 | 13 | {{ end }} 14 |
15 | 16 | {{- partialCached "footer.html" . }} 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /layouts/_default/index.json: -------------------------------------------------------------------------------- 1 | {{- $.Scratch.Add "index" slice -}} 2 | {{- range site.RegularPages -}} 3 | {{- if and (not .Params.searchHidden) (ne .Layout `archives`) (ne .Layout `search`) }} 4 | {{- $.Scratch.Add "index" (dict "title" .Title "content" .Plain "permalink" .Permalink "summary" .Summary "date" (.Date.Format "2006/01/02") "image" ((print .Permalink .Params.image) | absURL)) -}} 5 | {{- end }} 6 | {{- end -}} 7 | {{- $.Scratch.Get "index" | jsonify -}} 8 | -------------------------------------------------------------------------------- /layouts/_default/list.html: -------------------------------------------------------------------------------- 1 | {{- define "main" }} 2 |
3 |
4 |

{{ .Title }}

5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 | {{- $pages := union .RegularPages .Sections }} 14 | {{ range $pages }} 15 |
16 |
17 |
18 |

{{ .Title }}

19 | 20 |
21 |
22 | {{ end }} 23 |
24 |
25 | {{- end }} 26 | -------------------------------------------------------------------------------- /layouts/_default/search.html: -------------------------------------------------------------------------------- 1 | {{- define "main" }} 2 |
3 | 13 | 14 |
15 |
16 | {{ end }} 17 | -------------------------------------------------------------------------------- /layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 | {{ $image := .Resources.GetMatch .Params.image }} 5 | 6 |
7 | 8 | {{ with .Params.tags }} 9 | 14 | {{ end }} 15 | 16 |
17 |

{{ .Title }}

18 |
19 |
20 | {{ .Content }} 21 |
22 |
23 |
24 |
25 | {{ end }} 26 | -------------------------------------------------------------------------------- /layouts/_default/summary.html: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /layouts/index.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{- partial "profile.html" }} 3 | 4 | {{- $pages := where site.RegularPages "Type" "in" site.Params.mainSections }} 5 | {{- $paginator := .Paginate $pages }} 6 | 7 |
8 | {{ range $paginator.Pages }} 9 | {{ .Render "summary"}} 10 | {{ end }} 11 |
12 | 13 | {{- if gt $paginator.TotalPages 1 }} 14 | {{- partial "pagination.html" . -}} 15 | {{- end }} 16 | 17 | {{ end }} 18 | -------------------------------------------------------------------------------- /layouts/partials/footer.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /layouts/partials/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ template "_internal/google_analytics.html" . }} 5 | 6 | {{ if not .IsHome }}{{ if .Title }}{{ .Title }} - {{ end }}{{ end }}{{ .Site.Title }} 7 | 8 | {{ $sass := resources.Get "scss/style.scss" }} 9 | {{ $style := $sass | resources.ToCSS | minify | resources.Fingerprint "sha256" }} 10 | 11 | 12 | {{- if (eq .Layout "search") }} 13 | {{ $fusejs := resources.Get "js/fuse.basic.min.js" }} 14 | {{ $search := resources.Get "js/search.js" }} 15 | {{ $js := slice $fusejs $search | resources.Concat "js/bundle.js" | resources.Fingerprint "sha512" }} 16 | 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /layouts/partials/header.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 | 17 |
18 |
19 | -------------------------------------------------------------------------------- /layouts/partials/icons.html: -------------------------------------------------------------------------------- 1 | {{- if (eq .name "github") -}} 2 | 3 | 4 | 5 | {{- else if (eq .name "instagram") -}} 6 | 7 | 8 | 9 | {{- else if (eq .name "twitter") -}} 10 | 11 | 12 | 13 | {{- end -}} 14 | -------------------------------------------------------------------------------- /layouts/partials/pagination.html: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /layouts/partials/profile.html: -------------------------------------------------------------------------------- 1 |
2 | {{- with site.Params.profile }} 3 | {{ if .enabled }} 4 |
5 |
6 |

{{ .name }}

7 |

{{ .description }}

8 | 15 |
16 |
17 | {{ end }} 18 | {{- end }} 19 |
20 | -------------------------------------------------------------------------------- /theme.toml: -------------------------------------------------------------------------------- 1 | name = "Coyote" 2 | license = "MIT" 3 | licenselink = "https://github.com/nightswinger/hugo-theme-coyote/blob/main/LICENSE" 4 | description = "Card-based blog theme for Hugo" 5 | 6 | # The home page of the theme, where the source can be found. 7 | homepage = "https://github.com/nightswinger/hugo-theme-coyote" 8 | 9 | # If you have a running demo of the theme. 10 | demosite = "https://nightswinger.github.io/hugo-theme-coyote/" 11 | 12 | tags = ["blog"] 13 | features = ["awesome", "card"] 14 | 15 | min_version = "0.101.0" 16 | 17 | # If the theme has a single author 18 | [author] 19 | name = "nightswinger" 20 | homepage = "https://github.com/nightswinger" 21 | --------------------------------------------------------------------------------