You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2021/02/17 01:26:58 UTC

[skywalking-website] branch master updated: Integrate project documentations into the website (#215)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-website.git


The following commit(s) were added to refs/heads/master by this push:
     new 1f03fd1  Integrate project documentations into the website (#215)
1f03fd1 is described below

commit 1f03fd1fb8400ad9f7f64919dd7f5abcae06d478
Author: Juntao Zhang <jt...@163.com>
AuthorDate: Wed Feb 17 09:26:52 2021 +0800

    Integrate project documentations into the website (#215)
---
 .github/workflows/deploy.yaml                      |   6 +-
 .gitignore                                         |   4 +-
 data/docSidebar/.gitkeep                           |   0
 data/docs.yml                                      |  10 +-
 doc.sh                                             |  33 ++++
 docs.js                                            | 175 +++++++++++++++++++++
 package.json                                       |   8 +-
 themes/docsy/assets/scss/_custom_downloads.scss    |   2 +-
 themes/docsy/assets/scss/_custom_project_doc.scss  | 101 ++++++++++++
 themes/docsy/assets/scss/_sidebar-toc.scss         |  13 +-
 themes/docsy/assets/scss/_styles_project.scss      |   1 +
 themes/docsy/layouts/partials/sidebar-recurse.html |  21 +++
 themes/docsy/layouts/partials/sidebar.html         |   4 +-
 themes/docsy/layouts/projectDoc/baseof.html        |  45 ++++++
 themes/docsy/layouts/projectDoc/content.html       |  28 ++++
 themes/docsy/layouts/projectDoc/list.html          |  37 +++++
 themes/docsy/layouts/projectDoc/single.html        |   3 +
 17 files changed, 475 insertions(+), 16 deletions(-)

diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml
index e62dcce..83fea33 100644
--- a/.github/workflows/deploy.yaml
+++ b/.github/workflows/deploy.yaml
@@ -33,13 +33,9 @@ jobs:
           wget https://github.com/gohugoio/hugo/releases/download/v0.74.3/hugo_extended_0.74.3_Linux-64bit.tar.gz
           tar xvf hugo_extended_0.74.3_Linux-64bit.tar.gz
           sudo mv hugo /usr/bin/
-          npm install -D --save postcss-cli
-          npm install -D --save autoprefixer	
-          npm install -D --save postcss
-          npm i
 
       - name: Build
-        run: hugo
+        run: npm run build-with-docs
 
       - name: Deploy
         uses: peaceiris/actions-gh-pages@v3
diff --git a/.gitignore b/.gitignore
index d78da1e..aa93e8e 100755
--- a/.gitignore
+++ b/.gitignore
@@ -26,4 +26,6 @@
 /static/js
 /static/css
 
-/tmp
\ No newline at end of file
+/tmp
+/data/docSidebar/*
+!.gitkeep
\ No newline at end of file
diff --git a/data/docSidebar/.gitkeep b/data/docSidebar/.gitkeep
new file mode 100755
index 0000000..e69de29
diff --git a/data/docs.yml b/data/docs.yml
index 52fbb3a..04a0e50 100644
--- a/data/docs.yml
+++ b/data/docs.yml
@@ -6,13 +6,17 @@
       description: The documentation including core concepts, protocols, Java agent, OAP backend, and UI
       user: apache
       repo: skywalking
+      repoUrl: https://github.com/apache/skywalking.git
       docs:
         - version: v8.4.0
-          link: https://github.com/apache/skywalking/tree/v8.4.0/docs
+          link: /docs/main/v8.4.0/readme/
+          commitId: ca978d0f8c6de4673009c5f100955035ddae9ecf
         - version: v8.3.0
-          link: https://github.com/apache/skywalking/tree/8.3.0/docs-hotfix/docs
+          link: /docs/main/v8.3.0/readme/
+          commitId: da70cd824647705916af16c92b6865ac7d0c11b2
         - version: v8.2.0
-          link: https://github.com/apache/skywalking/tree/v8.2.0/docs
+          link: /docs/main/v8.2.0/readme/
+          commitId: af02b66bbdde53380633a564b98353b66a5dc04d
 
     - name: Rocketbot UI
       icon: R
diff --git a/doc.sh b/doc.sh
new file mode 100755
index 0000000..0399397
--- /dev/null
+++ b/doc.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+
+repo=$1
+repoUrl=$2
+commitId=$3
+localPath=$4
+menuFileName=$5
+
+
+if [ ! -d "./tmp" ]; then
+  mkdir ./tmp
+fi
+cd ./tmp
+
+if [ -d "./${repo}" ]; then
+  rm -rf ./${repo}
+fi
+
+mkdir ./${repo}
+cd ./${repo}
+git init
+git remote add origin ${repoUrl}
+git fetch origin ${commitId}
+git reset --hard FETCH_HEAD
+
+if [ -d "../../${localPath}" ]; then
+  rm -rf ../../${localPath}
+fi
+mkdir -p ../../${localPath}
+cp -rf ./docs/* ../../${localPath}
+cp ./docs/menu.yml ../../data/docSidebar/${menuFileName}.yml
+
diff --git a/docs.js b/docs.js
new file mode 100644
index 0000000..4e37132
--- /dev/null
+++ b/docs.js
@@ -0,0 +1,175 @@
+const fs = require("fs");
+const path = require("path");
+const YAML = require('yamljs');
+const {execSync} = require("child_process");
+const {promises} = fs;
+const docConfig = './data/docs.yml';
+const layoutTemplateFile = '/themes/docsy/layouts/projectDoc/baseof.html';
+
+
+traverseDocsConfig()
+
+function readDirSync(path, docInfo, replaceMarkdownText) {
+  const pa = fs.readdirSync(path);
+  pa.forEach(function (ele) {
+    const info = fs.statSync(path + "/" + ele);
+    if (info.isDirectory()) {
+      readDirSync(path + "/" + ele, docInfo, replaceMarkdownText);
+    } else {
+      const filePath = path + "/" + ele;
+      const fileNameReg = /\.md/g;
+      let shouldFormat = fileNameReg.test(filePath);
+      if (shouldFormat) {
+        readFile(filePath, docInfo, replaceMarkdownText);
+      }
+    }
+  });
+}
+
+function readFile(filePath, docInfo, replaceMarkdownText) {
+  fs.readFile(filePath, function (err, data) {
+    if (err) {
+      console.log("happen an error when read file , error is " + err);
+    } else {
+      let codeTxt = data.toString();
+      codeTxt = replaceMarkdownText(codeTxt, docInfo, filePath)
+      writeFile(filePath, codeTxt);
+    }
+  });
+}
+
+function replaceMarkdownText(codeTxt, docInfo, filePath) {
+  if (!/^([\s]*)(---[\s\S]*---)/.test(codeTxt)) {
+    const {repoUrl, commitId} = docInfo;
+    const prefix = repoUrl.replace('.git', '/tree') + `/${commitId}`;
+    const depth = filePath.split('/docs')[1].match(/\//g).length - 2;
+
+    let title = codeTxt.trim().split('\n')[0]
+    title = title.match(/(?<=([ ])).*/g)[0];
+    title = title.replace(/:/g, ':')
+
+    codeTxt =
+        `---
+title: ${title}
+type: projectDoc
+layout: baseof
+---\n` + codeTxt;
+    codeTxt = codeTxt
+        .replace(/(\[[\s\S]*?\])\(([\s\S]*?)\)/g, function (match, p1, p2) {
+          if (p2 && p2.startsWith('http')) {
+            return match
+          }
+          const str = p2
+              .toLowerCase()
+              .replace(/\.md/g, '')
+
+          if (str.startsWith('#')) {
+            return `${p1}(${str})`
+          }
+          if (str.startsWith('./')) {
+            return `${p1}(./../${str})`
+          }
+          if (str.startsWith('../')) {
+            const parentDepth = str.match(/\.\.\//g).length;
+            if (parentDepth >= depth) {
+              const url = str.replace(/\.\.\//g, '')
+              return `${p1}(${prefix}/${url})`
+            }
+          }
+          return `${p1}(../${str})`
+        })
+  }
+  return codeTxt
+}
+
+function writeFile(filePath, codeTxt) {
+  fs.writeFile(filePath, codeTxt, function (err) {
+    if (err) {
+      console.log("happen an error when write file , error is " + err);
+    }
+  });
+}
+
+
+async function traverseDocsConfig() {
+  let tpl = '';
+  const docsInfo = []
+  const targetPath = path.join(__dirname, layoutTemplateFile)
+  const result = await loadYaml(docConfig)
+  result.forEach(data => {
+    data.list.forEach(item => {
+      item.docs && item.docs.forEach(({version, commitId}) => {
+        if (commitId) {
+          const {repo, repoUrl} = item;
+          const docName = repo === 'skywalking' ? 'main' : repo;
+          const localPath = `/content/docs/${docName}/${version}`;
+          const menuFileName = `${docName}${version}`.replace(/v|\./g, '_');
+          docsInfo.push({localPath, repoUrl, commitId})
+
+          tpl += `{{ if in .File.Path "${localPath.split('/content/')[1]}" }}
+                    <h5>Documentation: {{.Site.Data.docSidebar.${menuFileName}.version}}</h5>
+                    {{ partial "sidebar-recurse.html" .Site.Data.docSidebar.${menuFileName} }}
+                    <div class="commit-id">Commit Id: {{.Site.Data.docSidebar.${menuFileName}.commitId}}</div>
+                    {{ end }}\n`
+
+          execSync(`"./doc.sh" ${repo} ${repoUrl} ${commitId} ${localPath} ${menuFileName}`);
+
+          handleMenuFiles(`./data/docSidebar/${menuFileName}.yml`, {version, commitId}, `/docs/${docName}/${version}`)
+        }
+      })
+    })
+
+  })
+  await generateLayoutTemplate(targetPath, tpl)
+  handleDocsFiles(docsInfo)
+
+}
+
+async function generateLayoutTemplate(targetPath, tpl) {
+  let codeTxt = await promises.readFile(targetPath, 'utf8');
+  codeTxt = codeTxt.toString()
+  codeTxt = codeTxt.replace(/(td-sidebar">)([\s\S]*)(<\/div>[\s\S]*<div id="toc")/, function (match, p1, p2, p3) {
+    return `${p1}\n${tpl}\n${p3}`
+  })
+  await promises.writeFile(targetPath, codeTxt, 'utf8');
+}
+
+function handleDocsFiles(docsInfo) {
+  docsInfo.forEach((docInfo) => {
+
+    const {localPath} = docInfo
+    const root = path.join(__dirname, localPath);
+    readDirSync(root, docInfo, replaceMarkdownText);
+  })
+}
+
+async function handleMenuFiles(menuFilePath, docInfo, localPath) {
+  const nativeObject = await loadYaml(menuFilePath);
+  const {version, commitId} = docInfo
+  nativeObject.version = version;
+  nativeObject.commitId = commitId.slice(0, 7);
+
+  handleMenuPath(nativeObject.catalog, localPath)
+  const yamlString = YAML.stringify(nativeObject, 2);
+  await promises.writeFile(menuFilePath, yamlString, 'utf8');
+}
+
+function handleMenuPath(list, localPath) {
+  list.forEach(item => {
+    const pagePath = item.path;
+    if (pagePath) {
+      item.path = pagePath.startsWith('http') ? pagePath : localPath + pagePath;
+    }
+    if (item.catalog) {
+      handleMenuPath(item.catalog, localPath)
+    }
+  })
+}
+
+function loadYaml(filePath) {
+  return new Promise((resolve) => {
+    YAML.load(filePath, function (result) {
+      resolve(result)
+    });
+  })
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 10810da..76cf163 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,9 @@
   "description": "Hugo theme for technical documentation.",
   "main": "none.js",
   "scripts": {
+    "build": "npm install && hugo",
+    "build-with-docs": "npm install && npm run docs && hugo",
+    "docs": "node ./docs.js",
     "test": "echo \"Error: no test specified\" && exit 1"
   },
   "repository": {
@@ -20,10 +23,11 @@
   "devDependencies": {
     "autoprefixer": "^9.8.6",
     "cssnano": "^4.1.10",
-    "postcss-cli": "^8.3.0",
+    "postcss-cli": "^8.3.1",
+    "postcss": "^8.2.6",
     "postcss-cssnext": "^3.1.0",
     "postcss-import": "^12.0.1",
     "postcss-loader": "^3.0.0",
-    "sugarss": "^2.0.0"
+    "yamljs": "^0.3.0"
   }
 }
diff --git a/themes/docsy/assets/scss/_custom_downloads.scss b/themes/docsy/assets/scss/_custom_downloads.scss
index 45d12a7..67cf500 100644
--- a/themes/docsy/assets/scss/_custom_downloads.scss
+++ b/themes/docsy/assets/scss/_custom_downloads.scss
@@ -89,7 +89,7 @@
 
     .dropdown-menu {
       min-width: 6rem;
-      //width: 100%;
+      z-index: 10000;
     }
 
     .dropdown-header {
diff --git a/themes/docsy/assets/scss/_custom_project_doc.scss b/themes/docsy/assets/scss/_custom_project_doc.scss
new file mode 100644
index 0000000..85a614f
--- /dev/null
+++ b/themes/docsy/assets/scss/_custom_project_doc.scss
@@ -0,0 +1,101 @@
+.project-doc {
+  .td-content {
+    #overview, #community {
+       padding: 0;
+       text-align: left;
+       margin-bottom: 1rem;
+    }
+  }
+
+  .td-sidebar {
+    font-weight: 300;
+    padding-top: 5.5rem;
+    padding-right: 5px;
+    height: 100vh;
+    overflow-y: scroll;
+    position: sticky;
+    position: -webkit-sticky;
+    top: 0px;
+
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+
+    &::-webkit-scrollbar-thumb {
+      background-color: #999 !important;
+      border-radius: 5px;
+    }
+
+    h6, div {
+      padding-top: 0.2rem;
+      margin-bottom: 0.6rem;
+      color: #495057;
+      font-weight: 300;
+    }
+
+    h5 {
+      padding-top: 0;
+      font-weight: 350;
+      font-size: 16px;
+    }
+
+    ul {
+      padding-left: 0;
+
+      a {
+        color: #495057;
+
+        &:hover {
+          color: #72A1E5;
+        }
+
+        &.active {
+          font-weight: 600;
+        }
+      }
+    }
+
+    li li {
+      margin-left: 0.8rem;
+      line-height: 1.1 !important;
+      padding-bottom: 0.6em;
+
+      &:last-child {
+        padding-bottom: 0em;
+
+      }
+    }
+
+    li {
+      list-style: none;
+      display: block;
+    }
+  }
+
+  .td-main .td-toc {
+    .fix {
+      box-shadow: none;
+    }
+
+    #TableOfContents {
+      width: auto;
+    }
+  }
+
+  .commit-id {
+    padding-top: 0.5rem !important;
+    border-top: 1px solid #cccccca1;
+    word-break: break-all;
+    font-size: 13px;
+  }
+
+
+}
+
+@media (max-width: 768px) {
+  .project-doc {
+    .td-sidebar {
+      display: none;
+    }
+  }
+}
diff --git a/themes/docsy/assets/scss/_sidebar-toc.scss b/themes/docsy/assets/scss/_sidebar-toc.scss
index 96e7abb..2a954c8 100644
--- a/themes/docsy/assets/scss/_sidebar-toc.scss
+++ b/themes/docsy/assets/scss/_sidebar-toc.scss
@@ -19,16 +19,25 @@
     a {
         display: block;
         font-weight: $font-weight-light;
-        padding-bottom: .25rem;
     }
 
     li {
         list-style: none;
         display: block;
+        line-height: 1.2;
+        padding: 0.25rem 0;
+        &:last-child{
+            padding-bottom: 0;
+        }
     }
 
     li li {
-        margin-left: 0.5rem;
+        margin-left: 1rem;
+        line-height: 1.2;
+        padding: 0.25rem;
+        &:last-child{
+            padding-bottom: 0;
+        }
     }
 
     .td-page-meta {
diff --git a/themes/docsy/assets/scss/_styles_project.scss b/themes/docsy/assets/scss/_styles_project.scss
index 140c491..eafa48f 100644
--- a/themes/docsy/assets/scss/_styles_project.scss
+++ b/themes/docsy/assets/scss/_styles_project.scss
@@ -10,6 +10,7 @@ assets/scss/_styles_project.scss
 @import "custom_docs.scss";
 @import "custom_downloads.scss";
 @import "custom_tags.scss";
+@import "custom_project_doc.scss";
 //common
 html, body {
   font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
diff --git a/themes/docsy/layouts/partials/sidebar-recurse.html b/themes/docsy/layouts/partials/sidebar-recurse.html
new file mode 100644
index 0000000..53f505d
--- /dev/null
+++ b/themes/docsy/layouts/partials/sidebar-recurse.html
@@ -0,0 +1,21 @@
+<ul class="">
+    {{ range .catalog }}
+
+    <li>
+        {{if .catalog}}
+
+            {{if .path}}
+            <div ><a href="{{ .path }}">{{ .name }}</a></div>
+
+            {{else}}
+            <div >{{ .name }}</div>
+            {{end}}
+
+            {{ partial "sidebar-recurse.html" . }}
+        {{else}}
+            <a href="{{ .path }}">{{ .name }}</a>
+        {{end}}
+    </li>
+
+    {{ end }}
+</ul>
\ No newline at end of file
diff --git a/themes/docsy/layouts/partials/sidebar.html b/themes/docsy/layouts/partials/sidebar.html
index bf568e2..5e83d8c 100644
--- a/themes/docsy/layouts/partials/sidebar.html
+++ b/themes/docsy/layouts/partials/sidebar.html
@@ -4,8 +4,8 @@
 {{ $mid := printf "m-%s" (.RelPermalink | anchorize) }}
 <script>
  $(function() {
- $("#td-sidebar-menu #{{ $mid }}").toggleClass("active"); 
- $("#td-sidebar-menu").toggleClass("d-none"); 
+ $("#td-sidebar-menu #{{ $mid }}").toggleClass("active");
+ $("#td-sidebar-menu").toggleClass("d-none");
 });
 </script>
 {{ partialCached "sidebar-tree.html" . .CurrentSection.RelPermalink }}
diff --git a/themes/docsy/layouts/projectDoc/baseof.html b/themes/docsy/layouts/projectDoc/baseof.html
new file mode 100644
index 0000000..7f3a988
--- /dev/null
+++ b/themes/docsy/layouts/projectDoc/baseof.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<html lang="{{ .Site.Language.Lang }}" class="no-js">
+  <head>
+    {{ partial "head.html" . }}
+    <title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{ . }} | {{ end }}{{ .Site.Title }}{{ end }}</title>
+  </head>
+  <body class="td-{{ .Kind }}  project-doc">
+    <header>
+      {{ partial "navbar.html" . }}
+    </header>
+    <div class="container-fluid td-outer">
+
+      <div class="td-main">
+        <div class="row flex-xl-nowrap">
+          <div class="col-12 col-md-3 col-xl-2 d-print-none td-sidebar">
+
+          </div>
+          <div id="toc" class="d-none d-xl-block col-xl-2 td-toc d-print-none">
+            {{ partial "toc.html" . }}
+          </div>
+          <main class="col-12 col-md-9 col-xl-8 pl-md-5 pr-md-4" role="main">
+            <br>
+            {{ block "main" . }}{{ end }}
+          </main>
+        </div>
+      </div>
+
+      {{ partial "footer.html" . }}
+    </div>
+    {{ partial "lightbox.html" . }}
+    {{ partial "sidebar-skywalking.html" . }}
+    {{ partial "scripts.html" . }}
+  </body>
+  <script>
+    $(function (){
+      var path = window.location.pathname;
+      $('.td-sidebar a').each(function (e){
+        console.log($(this).attr('href'));
+        if($(this).attr('href')+'/'==path){
+          $(this).addClass('active')
+        }
+      })
+    })
+  </script>
+</html>
diff --git a/themes/docsy/layouts/projectDoc/content.html b/themes/docsy/layouts/projectDoc/content.html
new file mode 100644
index 0000000..e86a00e
--- /dev/null
+++ b/themes/docsy/layouts/projectDoc/content.html
@@ -0,0 +1,28 @@
+<div class="td-content">
+<!--	<h1>{{ .Title }}</h1>-->
+<!--	{{ with .Params.description }}<div class="lead">{{ . | markdownify }}</div>{{ end }}-->
+<!--	<div class="td-byline mb-4">-->
+<!--		{{ with .Params.author }}{{ T "post_byline_by" }} <b>{{ . | markdownify }}</b> |{{ end}}-->
+<!--		<time datetime="{{  $.Date.Format "2006-01-02" }}" class="text-muted">{{ $.Date.Format $.Site.Params.time_format_blog  }}</time>-->
+
+
+<!--		{{ with .Params.tags }}-->
+<!--		<p class="mt-1 tags-box">-->
+<!--			<i class="fas fa-tags" aria-hidden="true"></i>Tags |-->
+<!--			{{ range . }}-->
+<!--			<span> <a href="{{ "tags" | absURL }}/{{ . | urlize }}">{{ . }}</a></span>-->
+<!--			{{ end }}-->
+<!--		</p>-->
+<!--		{{ end }}-->
+
+
+<!--	</div>-->
+	{{ .Content }}
+<!--	{{ if (.Site.DisqusShortname) }}-->
+<!--		<br />-->
+<!--		{{ partial "disqus-comment.html" . }}-->
+<!--		<br />-->
+<!--	{{ end }}-->
+
+<!--	{{ partial "pager.html" . }}-->
+</div>
diff --git a/themes/docsy/layouts/projectDoc/list.html b/themes/docsy/layouts/projectDoc/list.html
new file mode 100644
index 0000000..4b32394
--- /dev/null
+++ b/themes/docsy/layouts/projectDoc/list.html
@@ -0,0 +1,37 @@
+{{ define "main" }}
+{{ if .Parent.IsHome }}
+{{ $.Scratch.Set "blog-pages" (where .Site.RegularPages "Section" .Section) }}
+{{ else }}
+{{$.Scratch.Set "blog-pages" .Pages }}
+{{ end }}
+{{ $pag := .Paginate (( $.Scratch.Get "blog-pages").GroupByDate (i18n "year" ))}}
+{{ $pageGroups := $pag.PageGroups}}
+{{ if eq $pag.PageNumber 1 }}
+{{ end }}
+<div class="row">
+	<div class="col-12">
+		{{ range $pageGroups }}
+		<h2>{{ T "post_posts_in" }} {{ .Key }}</h2>
+		<ul class="list-unstyled mt-4">
+			{{ range .Pages }}
+			<li class="media mb-4">
+				<div class="media-body">
+					<h5 class="mt-0 mb-1"><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h5>
+					<p class="mb-2 mb-md-3"><small class="text-muted">{{ .Date.Format ($.Param "time_format_blog") }} {{ T "ui_in"}} {{ .CurrentSection.LinkTitle }}</small></p>
+					{{ partial "featured-image.html" (dict "p" . "w" 250 "h" 125 "class" "float-left mr-3 pt-1 d-none d-md-block") }}
+					<p class="pt-0 mt-0">{{ .Plain | safeHTML | truncate 250 }}</p>
+					<p class="pt-0 mt-0">{{ .Description }}</p>
+					<p class="pt-0"><a href="{{ .RelPermalink }}">{{ T "ui_read_more"}}</a></p>
+				</div>
+			</li>
+			{{ end }}
+		</ul>
+		{{ end }}
+	</div>
+</div>
+<div class="row pl-2 pt-2">
+	<div class="col">
+		{{ template "_internal/pagination.html" . }}
+	</div>
+</div>
+{{ end }}
diff --git a/themes/docsy/layouts/projectDoc/single.html b/themes/docsy/layouts/projectDoc/single.html
new file mode 100644
index 0000000..00cb3ab
--- /dev/null
+++ b/themes/docsy/layouts/projectDoc/single.html
@@ -0,0 +1,3 @@
+{{ define "main" }}
+{{ .Render "content" }}
+{{ end }}
\ No newline at end of file