mirror of
https://github.com/ipfs/awesome-ipfs.git
synced 2024-10-01 01:35:37 -04:00
feat: clean up (a lot) (#247)
License: MIT Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
parent
6f15e77ed6
commit
a89015da98
2
.gitignore
vendored
2
.gitignore
vendored
@ -27,9 +27,7 @@ stroke*.svg
|
|||||||
public
|
public
|
||||||
dist
|
dist
|
||||||
/src/resources
|
/src/resources
|
||||||
/src/data
|
|
||||||
/src/content
|
/src/content
|
||||||
/src/layouts/partials/indexes
|
|
||||||
/src/static/fonts
|
/src/static/fonts
|
||||||
/src/static/app.css
|
/src/static/app.css
|
||||||
/src/static/app.js
|
/src/static/app.js
|
||||||
|
6
Makefile
6
Makefile
@ -1,6 +0,0 @@
|
|||||||
build:
|
|
||||||
npm --version
|
|
||||||
node --version
|
|
||||||
npm install
|
|
||||||
npm run lint
|
|
||||||
npm run build
|
|
34
package.json
34
package.json
@ -3,9 +3,9 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ipfs-css": "^0.5.2",
|
"ipfs-css": "^0.12.0",
|
||||||
"lunr": "^2.3.0",
|
"lunr": "^2.3.6",
|
||||||
"tachyons": "^4.10.0"
|
"tachyons": "^4.11.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./scripts/dev.js",
|
"start": "node ./scripts/dev.js",
|
||||||
@ -18,24 +18,22 @@
|
|||||||
"build:css": "postcss --no-map --use postcss-import cssnano -o src/static/app.css src/css/*.css",
|
"build:css": "postcss --no-map --use postcss-import cssnano -o src/static/app.css src/css/*.css",
|
||||||
"build:js": "browserify -g uglifyify src/js/app.js -o src/static/app.js",
|
"build:js": "browserify -g uglifyify src/js/app.js -o src/static/app.js",
|
||||||
"build:data": "node ./scripts/make-data.js",
|
"build:data": "node ./scripts/make-data.js",
|
||||||
"build:hugo": "hugo -s src -d ../public --cleanDestinationDir",
|
"build:hugo": "hugo -s src -d ../public --cleanDestinationDir --minify --gc"
|
||||||
"build:minify": "html-minifier --input-dir=./public --output-dir=./public --file-ext=html --collapse-whitespace --remove-comments"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^8.2.6",
|
"babel-eslint": "^10.0.1",
|
||||||
"browserify": "^16.2.2",
|
"browserify": "^16.2.3",
|
||||||
"chokidar": "^2.0.4",
|
"chokidar": "^2.1.5",
|
||||||
"cssnano": "^4.0.1",
|
"cssnano": "^4.1.10",
|
||||||
"ecstatic": "^3.2.1",
|
"ecstatic": "^4.1.2",
|
||||||
"fs-extra": "^6.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
"html-minifier": "^3.5.19",
|
"hugo-bin": "^0.43.4",
|
||||||
"hugo-bin": "^0.29.0",
|
"node-yaml": "^3.2.0",
|
||||||
"node-yaml": "^3.1.1",
|
"npm-run-all": "^4.1.5",
|
||||||
"npm-run-all": "^4.1.3",
|
"postcss-cli": "^6.1.2",
|
||||||
"postcss-cli": "^5.0.1",
|
"postcss-import": "^12.0.1",
|
||||||
"postcss-import": "^11.1.0",
|
|
||||||
"shx": "^0.3.2",
|
"shx": "^0.3.2",
|
||||||
"standard": "^11.0.1",
|
"standard": "^12.0.1",
|
||||||
"uglifyify": "^5.0.1",
|
"uglifyify": "^5.0.1",
|
||||||
"watch": "^1.0.2"
|
"watch": "^1.0.2"
|
||||||
},
|
},
|
||||||
|
@ -1,23 +1,34 @@
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const { join } = require('path')
|
||||||
const yaml = require('node-yaml')
|
const yaml = require('node-yaml')
|
||||||
const { sortAbc } = require('./utils')
|
const { sortAbc, sortInv, slugify } = require('./utils')
|
||||||
const dataDir = path.join(__dirname, '../data')
|
|
||||||
|
|
||||||
|
const dir = join(__dirname, '../data')
|
||||||
const trimIfExists = (str) => str ? str.trim() : undefined
|
const trimIfExists = (str) => str ? str.trim() : undefined
|
||||||
|
|
||||||
const files = fs.readdirSync(dataDir)
|
module.exports = fs.readdirSync(dir)
|
||||||
.map(file => path.join(dataDir, file))
|
.map(file => join(dir, file))
|
||||||
.map(file => yaml.readSync(file))
|
.map(file => yaml.readSync(file))
|
||||||
.map(file => {
|
.map(file => {
|
||||||
file.content = file.content.map(({ title, description, ...file }) => ({
|
file.slug = slugify(file.title)
|
||||||
|
file.type = 'category'
|
||||||
|
|
||||||
|
file.content = file.content.map(({ title, description, ...meta }, i) => ({
|
||||||
|
...meta,
|
||||||
title: trimIfExists(title),
|
title: trimIfExists(title),
|
||||||
description: trimIfExists(description),
|
description: trimIfExists(description),
|
||||||
...file
|
category: file.slug,
|
||||||
|
color: file.color,
|
||||||
|
index: i
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
let sort = (a, b) => sortAbc(a.title, b.title)
|
||||||
|
|
||||||
|
if (file.slug === 'articles') {
|
||||||
|
sort = (a, b) => sortInv(a.date, b.date)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.content = file.content.sort(sort)
|
||||||
return file
|
return file
|
||||||
})
|
})
|
||||||
.sort((a, b) => sortAbc(a.title, b.title))
|
.sort((a, b) => sortAbc(a.title, b.title))
|
||||||
|
|
||||||
module.exports = files
|
|
||||||
|
@ -1,126 +1,50 @@
|
|||||||
const lunr = require('lunr')
|
const lunr = require('lunr')
|
||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const path = require('path')
|
const { join } = require('path')
|
||||||
const { slugify, capitalize, sortAbc } = require('./utils')
|
|
||||||
|
|
||||||
const dataDir = path.join(__dirname, '../src/data')
|
function getData () {
|
||||||
const contentDir = path.join(__dirname, '../src/content')
|
let data = require('./data')
|
||||||
const indexesDir = path.join(__dirname, '../src/layouts/partials/indexes')
|
|
||||||
|
|
||||||
const processDataType = (data) => {
|
data.push({
|
||||||
const content = data.content.map(info => {
|
title: 'Awesome IPFS',
|
||||||
const { website, ...more } = info
|
slug: '_index',
|
||||||
|
content: data
|
||||||
return {
|
.reduce((arr, cat) => arr.concat(cat.content), [])
|
||||||
website: website,
|
.map((el, i) => ({
|
||||||
categories: [data.title.toLowerCase()],
|
...el,
|
||||||
...more
|
index: i
|
||||||
}
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
delete data.content
|
data.forEach(makeIndex)
|
||||||
|
return data
|
||||||
return {
|
|
||||||
info: { ...data },
|
|
||||||
content: content
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const writeContentFile = (data) => {
|
function makeIndex (category) {
|
||||||
const basename = slugify(data.title)
|
const data = category.content.map(({ index, title, description = '', tags = [], category = '' }) => ({
|
||||||
const filename = path.join(contentDir, `${basename}.md`)
|
|
||||||
|
|
||||||
fs.writeFileSync(filename, JSON.stringify(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
const makeIndex = (data) => {
|
|
||||||
const indexes = { 'index': [] }
|
|
||||||
|
|
||||||
const checkField = (field, el) => {
|
|
||||||
if (Array.isArray(el[field])) {
|
|
||||||
el[field].forEach(t => {
|
|
||||||
const key = `${field}_${t}`
|
|
||||||
|
|
||||||
if (indexes[key]) {
|
|
||||||
indexes[key].push(el.index)
|
|
||||||
} else {
|
|
||||||
indexes[key] = [el.index]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.forEach(el => {
|
|
||||||
indexes.index.push(el.index)
|
|
||||||
checkField('tags', el)
|
|
||||||
checkField('categories', el)
|
|
||||||
})
|
|
||||||
|
|
||||||
data = data.map(({index, title, description = '', tags = [], categories = []}) => ({
|
|
||||||
ref: index,
|
ref: index,
|
||||||
data: `${title} ${description} ${tags.join(' ')} ${categories.join(' ')}`
|
data: `${title} ${description} ${tags.join(' ')} ${category}`
|
||||||
}))
|
}))
|
||||||
|
|
||||||
for (const index in indexes) {
|
category.index = lunr(function () {
|
||||||
const idx = lunr(function () {
|
|
||||||
this.ref('ref')
|
this.ref('ref')
|
||||||
this.field('data')
|
this.field('data')
|
||||||
|
data.forEach(this.add.bind(this))
|
||||||
indexes[index].map(i => data[i]).forEach(this.add.bind(this))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const file = path.join(indexesDir, index + '.html')
|
|
||||||
const json = JSON.stringify(idx).replace(`'`, `\\'`)
|
|
||||||
|
|
||||||
fs.writeFileSync(file, `<script>var idx = JSON.parse(\`${json}\`);</script>`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const process = () => {
|
const process = () => {
|
||||||
fs.ensureDirSync(dataDir)
|
const dir = join(__dirname, '../src/content')
|
||||||
fs.ensureDirSync(contentDir)
|
fs.ensureDirSync(dir)
|
||||||
fs.ensureDirSync(indexesDir)
|
fs.emptyDirSync(dir)
|
||||||
fs.emptyDirSync(dataDir)
|
|
||||||
fs.emptyDirSync(contentDir)
|
|
||||||
fs.emptyDirSync(indexesDir)
|
|
||||||
|
|
||||||
let data = []
|
const data = getData()
|
||||||
let types = []
|
|
||||||
let typesObj = {}
|
|
||||||
|
|
||||||
require('./data')
|
for (const { index, slug, ...meta } of data) {
|
||||||
.map(processDataType)
|
const filename = join(dir, slug + '.md')
|
||||||
.forEach(({info, content}) => {
|
fs.writeFileSync(filename, `${JSON.stringify(meta)}
|
||||||
types.push(info)
|
<script>var idx = JSON.parse(\`${JSON.stringify(index).replace(`'`, `\\'`)}\`);</script>`)
|
||||||
data.push(content)
|
|
||||||
})
|
|
||||||
|
|
||||||
data = data.reduce((a, v) => a.concat(v), [])
|
|
||||||
.sort((a, b) => sortAbc(a.title, b.title))
|
|
||||||
.map((v, i) => { v.index = i; return v })
|
|
||||||
|
|
||||||
data.forEach(writeContentFile)
|
|
||||||
makeIndex(data)
|
|
||||||
|
|
||||||
types = types.map(t => {
|
|
||||||
t.title = capitalize(t.title)
|
|
||||||
return t
|
|
||||||
}).sort((a, b) => {
|
|
||||||
if (a.weight < b.weight) {
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.weight > b.weight) {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}).forEach(type => {
|
|
||||||
typesObj[type.title.toLowerCase()] = type
|
|
||||||
})
|
|
||||||
|
|
||||||
const pt = path.join(dataDir, 'categories.json')
|
|
||||||
fs.writeFileSync(pt, JSON.stringify(typesObj))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process()
|
process()
|
||||||
|
@ -3,18 +3,12 @@ const path = require('path')
|
|||||||
const files = require('./data')
|
const files = require('./data')
|
||||||
const readme = path.join(__dirname, '../README.md')
|
const readme = path.join(__dirname, '../README.md')
|
||||||
const template = path.join(__dirname, 'readme-template.md')
|
const template = path.join(__dirname, 'readme-template.md')
|
||||||
const { slugify, sortInv, sortAbc } = require('./utils')
|
const { slugify } = require('./utils')
|
||||||
|
|
||||||
const toc = files.map(cat => `- [${cat.title}](#${slugify(cat.title)})`).join('\n')
|
const toc = files.map(cat => `- [${cat.title}](#${slugify(cat.title)})`).join('\n')
|
||||||
|
|
||||||
const sections = files.map(category => {
|
const sections = files.map(category => {
|
||||||
let sort = (a, b) => sortAbc(a.title, b.title)
|
const content = category.content.map(item => {
|
||||||
|
|
||||||
if (category.title === 'Articles') {
|
|
||||||
sort = (a, b) => sortInv(a.date, b.date)
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = category.content.sort(sort).map(item => {
|
|
||||||
let block = '- '
|
let block = '- '
|
||||||
let mainUrl = ''
|
let mainUrl = ''
|
||||||
|
|
||||||
|
@ -20,12 +20,9 @@ const slugify = (text) => text.toString()
|
|||||||
.replace(/^-+/, '')
|
.replace(/^-+/, '')
|
||||||
.replace(/-+$/, '')
|
.replace(/-+$/, '')
|
||||||
|
|
||||||
const capitalize = (text) => `${text.charAt(0).toUpperCase()}${text.slice(1).toLowerCase()}`
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
sort,
|
sort,
|
||||||
sortInv,
|
sortInv,
|
||||||
sortAbc,
|
sortAbc,
|
||||||
slugify,
|
slugify
|
||||||
capitalize
|
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,11 @@
|
|||||||
<h1 class="f3 white">Awesome IPFS</h1>
|
<h1 class="f3 white">Awesome IPFS</h1>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{{ $site := .Site }}
|
{{ range (where .Site.Pages "Type" "category") }}
|
||||||
{{ range $name, $taxonomy := .Site.Taxonomies.categories }}
|
<a href="{{ .RelPermalink }}"
|
||||||
{{ $color := (index $site.Data.categories $name).color }}
|
class="flex-grow-1 flex items-center justify-center white no-underline pa2 bg-animate dib bg-{{ .Params.color }}-muted hover-bg-{{ .Params.color }}">
|
||||||
{{ $icon := print (index $site.Data.categories $name).icon ".svg" }}
|
<span class="w2 h2 fill-white mr2">{{ partial (print "icons/" .Params.icon ".svg" ) }}</span>
|
||||||
<a href="/categories/{{ $name | urlize }}"
|
{{ .Title }}
|
||||||
class="flex-grow-1 flex items-center justify-center white no-underline pa2 bg-animate dib bg-{{ $color }}-muted hover-bg-{{ $color }}">
|
|
||||||
<span class="w2 h2 fill-white mr2">{{ partial (print "icons/" $icon ) }}</span>
|
|
||||||
{{ $name }}
|
|
||||||
</a>
|
</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
{{ define "main" }}
|
|
||||||
|
|
||||||
{{- $p1 := (print .Data.Plural "_") -}}
|
|
||||||
{{- $p2 := lower .Title -}}
|
|
||||||
{{- $partial := print $p1 $p2 -}}
|
|
||||||
{{- partial "list" .Data.Pages -}}
|
|
||||||
{{- partial (print "indexes/" $partial) -}}
|
|
||||||
|
|
||||||
{{ end }}
|
|
3
src/layouts/_default/single.html
Normal file
3
src/layouts/_default/single.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
{{ partial "list" . }}
|
||||||
|
{{ end }}
|
@ -1,7 +1,3 @@
|
|||||||
{{ define "main" }}
|
{{ define "main" }}
|
||||||
|
{{ partial "list" . }}
|
||||||
{{ partial "list" .Pages }}
|
|
||||||
{{ partial "indexes/index" }}
|
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
@ -12,74 +12,75 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<main class="CardContainer mv4 flex flex-wrap justify-between" >
|
<main class="CardContainer mv4 flex flex-wrap justify-between" >
|
||||||
{{ range (sort . "Params.index") -}}
|
{{ range (sort .Params.content "index") -}}
|
||||||
<article data-ref="{{ .Params.index }}" class="Card flex flex-column bg-white shadow-4 grow2 br1 dark-gray b--black-10 flex-grow-1 ma2">
|
<article data-ref="{{ .index }}" class="Card flex flex-column bg-white shadow-4 grow2 br1 dark-gray b--black-10 flex-grow-1 ma2">
|
||||||
{{ $cat := index .Params.categories 0 }}
|
<div class="bg-navy ttu fw6 tracked montserrat bg-{{ .color }}-muted br1 br--top white pv1 ph2 ph3-ns f7 b w-100">
|
||||||
{{ $color := (index .Site.Data.categories $cat).color }}
|
{{ humanize .category }}
|
||||||
<div class="bg-navy ttu fw6 tracked montserrat bg-{{ $color }}-muted br1 br--top white pv1 ph2 ph3-ns f7 b w-100">
|
|
||||||
{{ humanize $cat }}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pa2 ph3-ns pb3-ns flex flex-column flex-grow-1">
|
<div class="pa2 ph3-ns pb3-ns flex flex-column flex-grow-1">
|
||||||
<div class="dt w-100 mt1">
|
<div class="dt w-100 mt1">
|
||||||
<div class="dtc">
|
<div class="dtc">
|
||||||
<a target="_blank" class="no-underline charcoal" href="{{ if .Params.website }}{{ .Params.website }}{{ else if .Params.source }}{{ .Params.source }}{{ else if .Params.demo }}{{ .Params.demo }}{{ end }}">
|
<a target="_blank" class="no-underline charcoal" href="{{ if .website }}{{ .website }}{{ else if .source }}{{ .source }}{{ else if .demo }}{{ .demo }}{{ end }}">
|
||||||
<h1 class="f5 mw5 f4-ns mv0">{{- .Title -}}</h1>
|
<h1 class="f5 mw5 f4-ns mv0">{{- .title -}}</h1>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{- if isset .Params "date" -}}
|
{{- if isset . "date" -}}
|
||||||
{{ template "text" .Date.Format "January 2, 2006" }}
|
{{ template "text" dateFormat "January 2, 2006" .date }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if isset .Params "description" -}}
|
{{- if isset . "description" -}}
|
||||||
{{ template "text" .Params.description }}
|
{{ template "text" .description }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if isset .Params "size" -}}
|
{{- if isset . "size" -}}
|
||||||
{{ template "text" (print "Size: " .Params.size) }}
|
{{ template "text" (print "Size: " .size) }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if isset .Params "hash" -}}
|
{{- if isset . "hash" -}}
|
||||||
<div class="mt2 mw5">
|
<div class="mt2 mw5">
|
||||||
<a href="https://ipfs.io{{ .Params.hash }}" target="_blank" alt="Website" title="Website" class="aqua hover-teal">
|
<a href="https://ipfs.io{{ .hash }}" target="_blank" alt="Website" title="Website" class="aqua hover-teal">
|
||||||
<abbr title="{{ .Params.hash }}">
|
<abbr title="{{ .hash }}">
|
||||||
{{ $length := sub (len .Params.hash) 5 }}
|
{{ $length := sub (len .hash) 5 }}
|
||||||
<code>{{ substr .Params.hash 0 10 }}...{{ substr .Params.hash $length 5 }}</code>
|
<code>{{ substr .hash 0 10 }}...{{ substr .hash $length 5 }}</code>
|
||||||
</abbr>
|
</abbr>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if isset .Params "picture" -}}
|
{{- if isset . "picture" -}}
|
||||||
<div class="mt2 mw5">
|
<div class="mt2 mw5">
|
||||||
<a target="_blank" class="no-underline charcoal" href="{{ if .Params.website }}{{ .Params.website }}{{ else if .Params.source }}{{ .Params.source }}{{ else if .Params.demo }}{{ .Params.demo }}{{ end }}">
|
<a target="_blank" class="no-underline charcoal" href="{{ if .website }}{{ .website }}{{ else if .source }}{{ .source }}{{ else if .demo }}{{ .demo }}{{ end }}">
|
||||||
<img class="br2" src="{{ .Site.BaseURL }}{{ .Params.picture }}" >
|
<img class="br2" src="{{ .picture | relURL }}" >
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
<div class="flex pt2 mt-auto align-center justify-begin">
|
<div class="flex pt2 mt-auto align-center justify-begin">
|
||||||
{{- if isset .Params "website" -}}
|
{{- if isset . "website" -}}
|
||||||
<a href="{{ .Params.website }}" target="_blank" alt="Website" title="Website">
|
<a href="{{ .website }}" target="_blank" alt="Website" title="Website">
|
||||||
{{ partial "icons/globe.svg" }}
|
{{ partial "icons/globe.svg" }}
|
||||||
</a>
|
</a>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if isset .Params "source" -}}
|
{{- if isset . "source" -}}
|
||||||
<a href="{{ .Params.source }}" target="_blank" alt="Source Code" title="Source Code">
|
<a href="{{ .source }}" target="_blank" alt="Source Code" title="Source Code">
|
||||||
{{ partial "icons/code.svg" }}
|
{{ partial "icons/code.svg" }}
|
||||||
</a>
|
</a>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if isset .Params "demo" -}}
|
{{- if isset . "demo" -}}
|
||||||
<a href="{{ .Params.demo }}" target="_blank" alt="Demo" title="Demo">
|
<a href="{{ .demo }}" target="_blank" alt="Demo" title="Demo">
|
||||||
{{ partial "icons/flask.svg" }}
|
{{ partial "icons/flask.svg" }}
|
||||||
</a>
|
</a>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
{{ .Content }}
|
Loading…
Reference in New Issue
Block a user