aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTelérico Jones <[email protected]>2021-05-29 21:09:08 -0300
committerTelérico Jones <[email protected]>2021-05-29 21:09:08 -0300
commitcade848b78d7f06b69a195f5a543b23c25eedd14 (patch)
tree6f6b4f766a58ccd61452da7a32830f051a89003e
downloadblog.sh-cade848b78d7f06b69a195f5a543b23c25eedd14.tar.bz2
blog.sh-cade848b78d7f06b69a195f5a543b23c25eedd14.zip
blog.sh project start
-rw-r--r--.gitignore1
-rwxr-xr-xfooter.sh18
-rw-r--r--header.sh106
-rw-r--r--index.html9
-rwxr-xr-xindex.sh95
-rwxr-xr-xnav.sh91
-rwxr-xr-xpages/article.sh52
-rw-r--r--pages/contato.sh13
-rwxr-xr-xpages/home.sh25
-rw-r--r--styles.css279
10 files changed, 689 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..eb2c80d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/pages/articles/*
diff --git a/footer.sh b/footer.sh
new file mode 100755
index 0000000..a7125bb
--- /dev/null
+++ b/footer.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+cat <<FOOTER
+<style>
+ footer {
+ text-align: center;
+ }
+</style>
+
+<footer>
+ <div class="separator-wrap"><div class="separator"></div></div>
+ <p>
+ Servidor HTTP: $SERVER_SOFTWARE <br />
+ Gateway: $GATEWAY_INTERFACE <br />
+ Pré-processador HTML: GNU Bash $BASH_VERSION
+ </p>
+</footer>
+FOOTER
diff --git a/header.sh b/header.sh
new file mode 100644
index 0000000..2e9f467
--- /dev/null
+++ b/header.sh
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+cat <<HEADER
+<style>
+ header h1, header h2 {
+ text-align: left;
+ line-break: anywhere;
+ }
+
+ header .separator-wrap {
+ margin-top: 15px;
+ }
+
+ .cursor {
+ background-color: var(--primary-fg);
+ animation-name: blink-animation;
+ animation-duration: 500ms;
+ animation-iteration-count: infinite;
+ animation-timing-function: cubic-bezier(0.83,-0.22, 0.54, 0.55);
+ }
+
+ @keyframes blink-animation {
+ to {
+ opacity: 0;
+ }
+ }
+
+ .mobile { display: none; }
+
+ @media screen and (max-width: 769px) {
+ .mobile { display: block; }
+ .desktop { display: none; }
+ }
+</style>
+
+<script type="text/javascript">
+ let mobileText = '$HEADER_TITLE_MOBILE';
+ let desktopText = '$HEADER_TITLE';
+ let isMobile = window.innerWidth < 769;
+
+ function hideContent() {
+ let mainContainer = document.querySelector('main');
+ let footer = document.querySelector('footer');
+ let headerSeparator = document.querySelector('header > .separator-wrap');
+ mainContainer.style.opacity = '0';
+ footer.style.opacity = '0';
+ headerSeparator.style.opacity = '0';
+ }
+
+ function showContent() {
+ let mainContainer = document.querySelector('main');
+ let footer = document.querySelector('footer');
+ let headerSeparator = document.querySelector('header > .separator-wrap');
+ mainContainer.style.transition = '500ms';
+ mainContainer.style.opacity = '1';
+ footer.style.transition = '500ms';
+ footer.style.opacity = '1';
+ headerSeparator.style.transition = '500ms';
+ headerSeparator.style.opacity = '1';
+
+ }
+
+ function typingAnimation(el, text, index, cb) {
+ let char = text[index];
+ if (char == ';') {
+ el.innerHTML += '<br />';
+ } else if (char == ' ') {
+ el.innerHTML += '&ensp;';
+ } else {
+ el.innerText += char;
+ }
+
+ if (index < text.length - 1) {
+ setTimeout(() => typingAnimation(el, text, index + 1, cb), 30);
+ } else {
+ cb();
+ }
+ }
+
+ document.addEventListener('DOMContentLoaded', function(event) {
+ hideContent();
+ let titleMobile = document.querySelector("#header-title-mobile > .text");
+ let titleDesktop = document.querySelector('#header-title > .text');
+
+ if (isMobile) {
+ titleMobile.innerHTML = '';
+ } else {
+ titleDesktop.innerHTML = '';
+ }
+
+ setTimeout(() => {
+ if (isMobile) {
+ typingAnimation(titleMobile, mobileText, 0, showContent);
+ } else {
+ typingAnimation(titleDesktop, desktopText, 0, showContent);
+ }
+ }, 200);
+ });
+</script>
+
+<header>
+ <h1 id="header-title" class="desktop">$ <span class="text">echo "Jefferson Julio" >> ./programadores</span><span class="cursor">&ensp;</span></h1>
+ <h1 id="header-title-mobile" class="mobile">$ <span class="text">echo "Jefferson Julio" \\<br/> >> ./programadores</span><span class="cursor">&ensp;</span></h1>
+ <div class="separator-wrap"><div class="separator"></div></div>
+</header>
+HEADER
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..0660d29
--- /dev/null
+++ b/index.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>jefferson.sh - dev</title>
+ </head>
+ <body>
+ <h1>dev - golo golo</h1>
+ </body>
+</html>
diff --git a/index.sh b/index.sh
new file mode 100755
index 0000000..16eb31c
--- /dev/null
+++ b/index.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+
+if [ "$REQUEST_URI" = '/favicon.ico' ]; then
+ exit 0
+fi
+
+RESPONSE_CONTENT_TYPE="text/html"
+STATUS=200
+
+HEADER_TITLE='source ./programadores/Jefferson Júlio/site/home.sh'
+HEADER_TITLE_MOBILE='cd ./programadores/ && \\ ;> source Jefferson Júlio/\\ ;> site/home.sh'
+
+urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
+
+html () {
+ cat <<HTML
+<html lang="pt-br">
+ <head>
+ <meta charset="utf-8" />
+ <title>jefferson.sh</title>
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
+
+ <style>
+ $(cat ./styles.css)
+ </style>
+ </head>
+
+ <body>
+ $(source ./nav.sh)
+ $(source ./header.sh)
+
+ <main>
+ $BODY
+ </main>
+
+ $(source ./footer.sh)
+ </body>
+</html>
+HTML
+}
+
+router () {
+ REQUEST_URI=$(urldecode "$REQUEST_URI")
+
+ case "$REQUEST_URI" in
+ /)
+ BODY=$(source ./pages/home.sh)
+ ;;
+ /contato)
+ HEADER_TITLE="source ./pages/contato.sh"
+ HEADER_TITLE_MOBILE="$HEADER_TITLE"
+ BODY=$(source ./pages/contato.sh)
+ ;;
+ /artigo/*.txt)
+ ARTICLE_FILE=./pages/articles/${REQUEST_URI/\/artigo\//}
+ HEADER_TITLE="cat $ARTICLE_FILE"
+ HEADER_TITLE_MOBILE="$HEADER_TITLE"
+ BODY=$(source ./pages/article.sh)
+ ;;
+ /json)
+ RESPONSE_CONTENT_TYPE="application/json"
+ STATUS=200
+ BODY=$(cat <<JSON
+{
+ "teste": "JSON"
+}
+JSON
+)
+ ;;
+ *)
+ STATUS=404
+ HEADER_TITLE="cat .$REQUEST_URI"
+ HEADER_TITLE_MOBILE="$HEADER_TITLE"
+ BODY="<p class='err-404'>cat: .$REQUEST_URI: Arquivo ou diretório inexistente</p>"
+ ;;
+ esac
+}
+
+router
+
+case "$RESPONSE_CONTENT_TYPE" in
+ "text/html")
+ RESPONSE_BODY=$(html)
+ ;;
+ *)
+ RESPONSE_BODY=$BODY
+esac
+
+
+cat <<INDEX
+Content-Type: $RESPONSE_CONTENT_TYPE
+Status: $STATUS
+
+$RESPONSE_BODY
+INDEX
diff --git a/nav.sh b/nav.sh
new file mode 100755
index 0000000..5881bb3
--- /dev/null
+++ b/nav.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+cat <<NAV
+<style>
+ .top-nav {
+ position: relative;
+ display: inline-flex;
+ background-color: var(--primary-fg);
+ height: 40px;
+ width: 100%;
+ align-items: center;
+ }
+
+ .nav-header {
+ padding-left: 25px;
+ padding-right: 25px;
+ }
+
+ .nav-header a {
+ color: black;
+ text-shadow: #e0e0e0 1px 1px 0;
+ font-size: 1.4rem;
+ text-decoration: none;
+ }
+
+ .nav-links {
+ padding: 0px 20px 0px 20px;
+ align-self: center;
+ }
+
+ .nav-links li {
+ position: relative;
+ height: 100%;
+ padding-left: 5px;
+ padding-right: 5px;
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .nav-links a {
+ color: var(--primary-bg);
+ text-decoration: none;
+ }
+
+ .nav-links li:hover {
+ background-color: var(--primary-bg);
+ }
+
+ .nav-links li:hover a {
+ text-decoration: underline;
+ color: var(--primary-fg);
+ }
+
+ @media screen and (max-width: 601px) {
+ .top-nav {
+ flex-direction: column;
+ height: auto;
+ padding-bottom: 10px;
+ }
+
+ .nav-header {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ }
+
+ .nav-header a {
+ font-size: 1.6rem;
+ }
+
+ .top-nav ul {
+ display: contents;
+ }
+
+ .top-nav ul > li {
+ width: 100%;
+ height: 25px;
+ justify-content: center;
+ }
+ }
+</style>
+
+<nav class="top-nav">
+ <span class="nav-header">
+ <a href="https://jefferson.sh">jefferson.sh</a>
+ </span>
+ <ul class="nav-links">
+ <li> <a href="/">Início</a> </li>
+ <li> <a href="/contato">Contato</a> </li>
+ </ul>
+</nav>
+NAV
diff --git a/pages/article.sh b/pages/article.sh
new file mode 100755
index 0000000..9832a76
--- /dev/null
+++ b/pages/article.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+ARTICLE_TITLE=$(basename "$ARTICLE_FILE")
+
+# Pick all file content
+ARTICLE_FILE_CONTENT=$(cat "$ARTICLE_FILE")
+
+# The first 3 lines of the file are metadata information
+ARTICLE_METADATA=$(echo "$ARTICLE_FILE_CONTENT" | head -n 3)
+
+# Skip file metadata, first 3 lines
+ARTICLE_CONTENT=$(echo "$ARTICLE_FILE_CONTENT" | tail -n +3)
+
+# Tags are placed on the first line of the file, delimited by commas
+IFS=',' read -ra ARTICLE_TAGS <<< "$(echo "$ARTICLE_METADATA" | head -n 1)"
+
+ARTICLE_TIME=$(stat --format="Criado em: %w<br/>Última atualização: %z" "$ARTICLE_FILE")
+ARTICLE_BYTES=$(stat --format="%o bytes" "$ARTICLE_FILE")
+
+if [ $? -gt 0 ]; then
+ STATUS=404
+ cat <<ERR
+<p class="err-404">cat: $ARTICLE_FILE: Arquivo ou diretório inexistente</p>
+ERR
+ exit 0
+fi
+
+cat <<ARTICLE
+<article class="container">
+ <section>
+ <div class="post-header">
+ <h4 class="post-title">stat -c "%o %w %z" $ARTICLE_FILE</h4>
+ <small>$ARTICLE_BYTES</small> <br/>
+ <time>$ARTICLE_TIME</time> <br/>
+
+ <ul class="tags">
+ $(
+ for i in "${ARTICLE_TAGS[@]}"; do
+ echo "<li class="tag">$i</li>"
+ done
+ )
+ </ul>
+ </div>
+
+ <div class="post-content">
+ <p>
+ ${ARTICLE_CONTENT}
+ </p>
+ </div>
+ </section>
+</article>
+ARTICLE
diff --git a/pages/contato.sh b/pages/contato.sh
new file mode 100644
index 0000000..74d1ad4
--- /dev/null
+++ b/pages/contato.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+cat <<PAGE
+<style>
+ @media screen and (max-width: 600px) {
+ .contato-page {
+ text-align: center;
+ }
+ }
+</style>
+
+<article class="contato-page container">
+</article>
+PAGE
diff --git a/pages/home.sh b/pages/home.sh
new file mode 100755
index 0000000..ebb399d
--- /dev/null
+++ b/pages/home.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+print-all-articles () {
+ for i in $(find ./pages/articles -type f -name '*.txt'); do
+ ARTICLE_CONTENT=$(tail -n +3 $i)
+ cat <<POST
+<section class="post-preview">
+ <div class="post-header-preview">
+ <h5 class="post-title">stat -c "%w %z" $i</h5>
+ <time>$(stat --format="Criado em: %w<br/>Última atualização: %z" $i)</time>
+ </div>
+
+ <p>$(echo "$ARTICLE_CONTENT" | head -c 120)...</p>
+
+ <a href="/artigo/$(basename $i)">Ler artigo completo</a>
+</section>
+POST
+ done
+}
+
+cat <<PAGE
+<article class="home-feed container">
+ $(print-all-articles)
+</article>
+PAGE
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..b17d72f
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,279 @@
+/* normalize.css */
+html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+body {
+ margin: 0;
+}
+main {
+ display: block;
+}
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+a {
+ background-color: transparent;
+}
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+b,
+strong {
+ font-weight: bolder;
+}
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+small {
+ font-size: 80%;
+}
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+sub {
+ bottom: -0.25em;
+}
+sup {
+ top: -0.5em;
+}
+img {
+ border-style: none;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+button,
+input { /* 1 */
+ overflow: visible;
+}
+button,
+select { /* 1 */
+ text-transform: none;
+}
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+progress {
+ vertical-align: baseline;
+}
+textarea {
+ overflow: auto;
+}
+[type="checkbox"],
+[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+details {
+ display: block;
+}
+summary {
+ display: list-item;
+}
+template {
+ display: none;
+}
+[hidden] {
+ display: none;
+}
+
+/* jefferson.sh */
+
+@import url('https://fonts.googleapis.com/css2?family=VT323&display=swap');
+
+html {
+ --primary-bg: #2b2b2b;
+ --primary-fg: #65d84a;
+ background-color: var(--primary-bg);
+ color: var(--primary-fg);
+ font-family: 'VT323', monospace;
+ font-size: 14px;
+}
+
+
+.separator-wrap {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+}
+
+.separator-wrap.left {
+ justify-content: flex-start;
+}
+
+.separator {
+ border-top: 1px solid var(--primary-fg);
+ width: 25px;
+ margin-left: 25px;
+ margin-right: 25px;
+}
+
+a {
+ color: var(--primary-fg);
+}
+
+ul {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+nav > * {
+ display: inline-block;
+}
+
+ul > li {
+ display: inline-block;
+}
+
+header, footer {
+ margin: 25px;
+}
+
+header > h1,
+header > h2 {
+ margin: 0;
+}
+
+@media screen and (max-width: 600px) {
+ h1 {
+ font-size: 1.4rem;
+ }
+}
+
+[class^=err-] {
+ text-align: left;
+ font-size: 2rem;
+ margin: 40px;
+}
+
+.container {
+ padding-left: 25px;
+ padding-right: 25px;
+}
+
+@media screen and (min-width: 1000px) {
+ .container {
+ padding-left: 215px;
+ padding-right: 215px;
+ }
+}
+
+.post-header {
+ border-left: 1px solid;
+ padding-left: 15px;
+}
+
+.post-title {
+ font-size: 1.4rem;
+ margin: 0;
+ margin-bottom: 10px;
+ line-break: anywhere;
+}
+
+.post-preview {
+ border-left: 1px solid;
+ padding-left: 10px;
+ margin: 25px 0px;
+}
+
+.post-header time,
+.post-header small {
+ font-size: 0.9rem;
+}
+
+.post-header-preview time,
+.post-header-preview small {
+ font-size: 0.9rem;
+}
+
+.post-header-preview .post-title {
+ margin: 0;
+ font-size: 1.1rem;
+}
+.post-header-preview time {
+ font-size: 0.8rem;
+}
+
+.tags {
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+
+.tag {
+ background-color: var(--primary-fg);
+ color: var(--primary-bg);
+ padding-left: 4px;
+ padding-right: 4px;
+ padding-top: 1.5px;
+ padding-bottom: 1.5px;
+}