Como criar um site usando Node.js e Express


0

Como criar um site usando Node.js e Express

Aplicativo da web Node.js

Este exemplo cria um site usando Node.js para fornecer um comportamento lógico do site. Usando a estrutura Express.js, o site é implementado como um aplicativo da web, com roteamento lógico para outras seções do site.

O HTML e CSS são baseados no design de nosso site responsivo usando CSS Grid e Flexbox. O HTML é refatorado como um modelo, portanto, o código de layout pode ser reutilizado ao adicionar novas páginas.

Nó de instalação

Node.js, também chamado de Node, é um ambiente de tempo de execução para escrever aplicativos do lado do servidor em JavaScript.

Observação

Se o Node já estiver instalado em seu computador, você pode pular esta seção e prosseguir para fazer um novo aplicativo Express.

Baixe o instalador do Node do site oficial de downloads do Node.js. Escolha a versão LTS (suporte de longo prazo) para o seu sistema operacional.

Windows e macOS

Abra e execute o instalador do Node (.msi no Windows, .pkg no macOS).

No Windows, na tela de instalação denominada Ferramentas para Módulos Nativos, marque a caixa Instalar automaticamente as ferramentas necessárias.

Linux

Em sistemas Linux, você pode instalar o Node usando seu gerenciador de pacotes, instalar os binários compilados manualmente ou construir o Node a partir da fonte. Para obter informações detalhadas, consulte o wiki oficial de instalação do Node.js.

Todos os sistemas operacionais

Quando a instalação for concluída, abra um terminal ou janela de prompt de comando. Execute o seguinte comando para atualizar o npm, o gerenciador de pacotes do Node. A opção -g (global) especifica que o software é instalado em todo o sistema, não apenas no aplicativo Node atual.

janelas

npm install -g npm

Linux e macOS

sudo npm install -g npm

Por fim, use o npm para instalar globalmente o aplicativo express-generator.

janelas

npm install -g express-generator

Linux e macOS

sudo npm install -g express-generator

Faça um novo aplicativo Express

Em um terminal ou janela de prompt de comando, gere um novo aplicativo Express.js. Em nosso exemplo, o nome do aplicativo é myapp e o mecanismo de visualização é especificado como pug.

express myapp --view="pug"

Mude o diretório para o novo aplicativo Express.

cd myapp

No diretório do aplicativo Express, use npm install para baixar e instalar as dependências necessárias, conforme listado no arquivo package.json.

npm install

Se alguma atualização de segurança estiver disponível para as dependências instaladas, uma notificação será exibida.

found 1 low severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details

Em caso afirmativo, aplique as atualizações de segurança.

npm audit fix

Instale o nodemon

No diretório do aplicativo Express, instale o nodemon. A opção –save-dev indica que o nodemon é uma dependência de desenvolvimento. Não é usado no próprio aplicativo, mas é uma ferramenta usada durante o desenvolvimento.

npm install --save-dev nodemon

Adicionar um script de inicialização de desenvolvimento

Um script de inicialização de desenvolvimento fornece uma maneira de iniciar seu aplicativo da web com opções que ajudam a desenvolver o aplicativo, como mensagens de erro detalhadas.

Em um editor de texto, abra o arquivo package.json no diretório do aplicativo. Este arquivo JSON especifica as dependências usadas pelo seu aplicativo Node. Além disso, ele contém scripts de inicialização nomeados que iniciam o aplicativo de maneiras diferentes.

Em package.json, localize a entrada “scripts”. Por padrão, ele contém apenas um script (“iniciar”).

  "scripts": {
    "start": "node ./bin/www"
  },

Adicione uma nova linha que defina um script devstart como segue.

Linux e macOS

  "scripts": {
    "start": "node ./bin/www",
    "devstart": "DEBUG=myapp:* nodemon ./bin/www"
  },

janelas

  "scripts": {
    "start": "node ./bin/www",
    "devstart": "SET DEBUG=myapp:* & nodemon ./bin/www"
  },

Esses scripts (“start” e “devstart”) podem ser executados executando o comando npm run scriptname.

O comando npm run devstart inicia o aplicativo com dois recursos de desenvolvimento adicionais habilitados.

  • A variável de ambiente DEBUG é definida, especificando que o log do console e as páginas de erro, como HTTP 404, exibem informações adicionais, como um rastreamento de pilha.
  • Além disso, o nodemon monitora certos arquivos importantes do site. Se você modificar esses arquivos, como redesenhar uma página ou modificar o conteúdo estático, o nodemon reinicia automaticamente o servidor para refletir as mudanças.

Inicie o servidor da web no modo de desenvolvimento.

npm run devstart
Gorjeta

Se o Firewall do Windows bloquear o aplicativo do servidor web, clique em Permitir acesso.

Visualize o aplicativo da web

Quando o aplicativo está em execução, seu computador atua como um servidor web, servindo HTTP na porta 3000.

Para visualizar o site, abra um navegador da web no endereço localhost: 3000.

Aplicativo Express.js padrão

Qualquer dispositivo conectado à sua rede local pode visualizar o aplicativo no endereço ipaddress: 3000, onde ipaddress é o endereço IP local do computador que executa o aplicativo.

Gorjeta

Se você não tiver certeza de qual é o endereço IP local do computador, consulte: Como encontrar meu endereço IP.

Para visualizar o site em um dispositivo móvel, conecte seu Wi-Fi à rede local e abra o endereço em um navegador.

Express.js no celular

Modelos HTML

Nosso exemplo usa CSS, JavaScript e HTML de como criar um site responsivo usando CSS Grid e Flexbox. O CSS e o JavaScript são usados ​​literalmente. O HTML é refatorado para uma linguagem de modelos.

Usando uma linguagem de modelos, o código de layout é escrito apenas uma vez e herdado por outras páginas.

O software que converte um modelo em seu formato final é chamado de processador de modelo. No contexto do HTML, um processador de template é chamado de view engine.

Express.js oferece suporte a vários mecanismos de visualização, incluindo Pug.

Visão geral do Pug

A linguagem Pug descreve documentos HTML de uma forma que fornece benefícios e recursos adicionais. Os arquivos Pug são renderizados em HTML quando o usuário os solicita.

A sintaxe da linguagem do Pug elimina a necessidade de as tags serem fechadas ou entre colchetes. Ele também oferece suporte a modelos herdados, iteração, condicionais e avaliação de JavaScript.

Exemplo de conversão de HTML para Pug

Estas são as primeiras linhas do HTML de como criar um site responsivo usando CSS Grid e Flexbox.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="utf-8">
    <title>Title</title>
    <link rel="stylesheet" href="index.css">
    <script src="index.js"></script>
  </head>
  <body>
    <div id="menu">
      <section id="menuitems">
        <div class="menubutton">
          <h1 onclick="menuToggle('hide')" class="menubutton">&#9776;</h1>

No Pug, o mesmo HTML pode ser escrito assim.

doctype html
html
  head
    meta(name="viewport" content="width=device-width, initial-scale=1")
    meta(charset="utf-8")
    title Title
    link(rel="stylesheet", href="index.css")
    script(src="index.js")
  body
    #menu
      section#menuitems
        .menubutton
          h1.menubutton(onclick="menuToggle('hide')") &#9776;

As tags de elemento são escritas sem colchetes. Os elementos filhos são recuados. O nível de recuo determina o escopo de um elemento, portanto, as tags de fechamento não são necessárias.

Os seletores CSS “id” e “class” podem ser escritos como element # id, element.class, element # id.class, etc. Se nenhum elemento for especificado, o elemento será considerado um div. Por exemplo,

em HTML pode ser escrito como .foo em Pug.

Após o nome do elemento e seus seletores, os atributos podem ser especificados entre parênteses, como uma lista delimitada por vírgulas. Por exemplo:

HTML

<div class="button" onmouseover="glow()" onclick="start()">

Pug

.button(onmouseover="glow()", onclick="start()")

Listando vários elementos em uma linha

Se o elemento for seguido por dois-pontos (:), ele pode ser seguido por um elemento filho na mesma linha. As duas seções a seguir do Pug produzem a mesma saída HTML.

a(href="/home")
  p Home
a(href="https://www.computerhope.com/home"): p Home

Ambos os itens acima são processados ​​no seguinte HTML.

<a href="https://www.computerhope.com/home"><p>Home</p></a>

Avaliando JavaScript

Se o elemento for seguido por um sinal de igual (=), tudo o que segue nessa linha é interpretado como código em buffer. O código é avaliado como JavaScript e a saída é “armazenada em buffer” (incluída como o conteúdo do elemento). Em sua forma mais simples, o código em buffer pode ser o nome de uma variável, passada pelo aplicativo.

Por exemplo, o roteador de aplicativo da página inicial, index.js, passa a variável title com o valor “Our Farm Stand” para o método express.Router (), que o passa para Pug. Quando Pug renderiza layout.pug, a seguinte linha:

title= pagetitle

… é interpretado como:

title Our Farm Stand

… que é processado como o seguinte HTML:

<title>Our Farm Stand</title>

Herança de modelo

Os documentos Pug podem herdar outros documentos Pug usando as palavras-chave extends e block.

Por exemplo, você pode criar um layout básico de site, layout.pug, com elementos compartilhados da página.

doctype html
html
  head
    title Page Title
  body
    p Content
    block foo

A instrução block foo diz “insira um bloco de conteúdo aqui, denominado foo, especificado em outro documento Pug que herda este modelo.”

Os documentos que herdam layout.pug devem começar com a instrução extends layout e conter uma instrução block foo no nível de recuo superior (no início de uma nova linha). Os filhos desta instrução “block foo” são inseridos no modelo na localização do bloco correspondente.

Um documento Pug pode herdar layout.pug como o seguinte.

extends layout
block foo
  p This is the home page.

Quando o documento é renderizado, o mecanismo Pug carrega o arquivo layout.pug. O bloco de linha foo em layout.pug é substituído por p Esta é a página inicial.

Visão geral do aplicativo Express padrão

A estrutura padrão do aplicativo Express está listada aqui, com descrições de cada arquivo e diretório.

myapp\/                 (Contains the entire Express app)
&boxvr;&boxh; app.js               The core logic of the Express app.
&boxvr;&boxh; bin\/                (Contains the app's executable scripts)
&boxv;  &boxur;&boxh; www               A wrapper that runs app.js.
&boxvr;&boxh; node_modules\/       (Contains dependencies installed by npm)
&boxvr;&boxh; package-lock.json    JSON manifest of installed dependencies.
&boxvr;&boxh; package.json         JSON of dependencies and config specific to your app.
&boxvr;&boxh; public\/             (Files downloaded by the user's web browser)
&boxv;  &boxvr;&boxh; images\/          (Contains client-accessible image files)
&boxv;  &boxvr;&boxh; javascripts\/     (Contains client-accessible JavaScript files)
&boxv;  &boxur;&boxh; stylesheets\/     (Contains client-accessible CSS)
&boxv;     &boxur;&boxh; style.css      The site's CSS stylesheet.
&boxvr;&boxh; routes\/             (Contains logic for individual site routes)
&boxv;  &boxvr;&boxh; index.js          Logic of the "index" route (/).
&boxv;  &boxur;&boxh; users.js          Logic of the "users" route (/users).
&boxur;&boxh; views\/              (Contains HTML templates)
   &boxvr;&boxh; error.pug         View displayed for error pages, such as HTML 404.
   &boxvr;&boxh; index.pug         View displayed for the site root (/).
   &boxur;&boxh; layout.pug        View template of layout shared by all pages.

A funcionalidade principal do site é definida em app.js. As rotas são nomeadas e especificadas neste arquivo.

Uma rota é uma página ou seção do site com um caminho exclusivo no URL, como www.example.com/search, www.example.com/login, etc. Essas rotas são nomeadas e associadas a scripts de lógica de rota, em app.js.

Os scripts de lógica de rota são armazenados na pasta de rotas. Quando um usuário solicita uma rota, seu script de lógica de rota processa os dados da solicitação HTTP e envia uma resposta.

A pasta de visualizações contém os modelos HTML, chamados de visualizações, que são processados ​​pelo mecanismo de visualização (Pug).

Implementação: JavaScript, CSS e Pug

O código a seguir implementa o aplicativo da web Express.

Estrutura de arquivo do aplicativo

myapp/
&boxvr;&boxh; app.js               App core logic
&boxvr;&boxh; bin/
&boxv;  &boxur;&boxh; www
&boxvr;&boxh; node_modules/
&boxvr;&boxh; package-lock.json
&boxvr;&boxh; package.json
&boxvr;&boxh; public/
&boxv;  &boxvr;&boxh; images/
&boxv;  &boxvr;&boxh; javascripts/
&boxv;  &boxv;  &boxur;&boxh; menu.js        Implements menu toggle
&boxv;  &boxur;&boxh; stylesheets/
&boxv;     &boxur;&boxh; style.css      Stylesheet
&boxvr;&boxh; routes/
&boxv;  &boxvr;&boxh; about.js          Logic for route /about
&boxv;  &boxvr;&boxh; advice.js         Logic for route /advice
&boxv;  &boxvr;&boxh; contact.js        Logic for route /contact
&boxv;  &boxvr;&boxh; index.js          Logic for route /
&boxv;  &boxvr;&boxh; recipes.js        Logic for route /recipes
&boxv;  &boxvr;&boxh; tips.js           Logic for route /tips
&boxv;  &boxur;&boxh; users.js          Not used, can be deleted
&boxur;&boxh; views/
   &boxvr;&boxh; about.pug         View for route /about
   &boxvr;&boxh; advice.pug        View for route /advice
   &boxvr;&boxh; contact.pug       View for route /contact
   &boxvr;&boxh; error.pug
   &boxvr;&boxh; index.pug         View for route /
   &boxvr;&boxh; layout.pug        View template shared by all pages
   &boxvr;&boxh; recipes.pug       View for route /recipes
   &boxur;&boxh; tips.pug          View for route /tips
blue = modified, green = new, red = not used

myapp \/app.js

A lógica do aplicativo principal é essencialmente a mesma do aplicativo Express padrão, com rotas adicionais definidas. A rota de “usuários” é removida.

/\/core dependencies
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
/\/create route objectsvar indexRouter = require('./routes/index');var aboutRouter = require('./routes/about');var contactRouter = require('./routes/contact');var tipsRouter = require('./routes/tips');var recipesRouter = require('./routes/recipes');var adviceRouter = require('./routes/advice');
/\/the app object
var app = express();
/\/view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
/\/app config
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
/\/tell the app to use these routesapp.use("https://www.computerhope.com/", indexRouter);app.use('/about', aboutRouter);app.use('/contact', contactRouter);app.use('/tips', tipsRouter);app.use('/recipes', recipesRouter);app.use('/advice', adviceRouter);
/\/catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});
/\/error handler
app.use(function(err, req, res, next) {
  /\/set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};
  /\/render the error page
  res.status(err.status || 500);
  res.render('error');
});
/\/expose this app to scripts that require it, i.e. myapp/bin/www
module.exports = app;

myapp \/routes \/layout.pug

O arquivo layout.pug contém o layout principal da página, que é compartilhado por todas as páginas do site. Ele contém tudo o que é necessário para exibir uma página, exceto o conteúdo mainbody (bloco mainbody).

doctype html
html
  head
    title= pagetitle
    meta(charset="utf-8")
    meta(name="viewport" content="width=device-width, initial-scale=1")
    script(src="/javascripts/menu.js")
    link(rel="stylesheet", href="/stylesheets/style.css")
  body
    #menu
      section#menuitems
        .menubutton
          h1.menubutton(onclick="menuToggle('hide')") &#9776;
        a(href="/")
          h3.menuhead Our Farm Stand
        a(href="/tips")
          h3.sectrule Tips for living well
        a(href="/recipes")
          h3 Recipes
        a(href="/advice")
          h3 Homesteading advice
        a(href="/about")
          h3.sectrule About Us
        a(href="/contact")
          h3 Contact Us
    #container
      #header
        a(href="/")
          h1.logo Our Farm Stand
        .headspace
        h1.menubutton(onclick="menuToggle('show')") &#9776;
        h1.placeholder &#9776;
        h2.navitem
          a(href="/about")
            .clickable-area About Us
        h2.navitem
          a(href="/contact")
            .clickable-area Contact Us
      #panel.left
        section#sections
          .sectionlink
            a(href="/tips")
              .clickable-area Tips for living well
          .sectionlink
            a(href="/recipes")
              .clickable-area Recipes
          .sectionlink
            a(href="/advice")
              .clickable-area Homesteading advice
      block mainbody
      #panel.right
        h3 Our friends
        section#partners.tall
          .partnerlink
            a(href="/")
              .clickable-area Green Valley Greens
          .partnerlink
            a(href="/")
              .clickable-area Turkey Hill Farm
          .partnerlink
            a(href="/")
              .clickable-area Burt's Maple Syrup
          .partnerlink
            a(href="/")
              .clickable-area Only Organic Seeds
      #footer
        p Copyright &copy; 2020 Alice &amp; Bob's Farm Stand

myapp \/views \/index.pug

O arquivo index.pug estende layout.pug e contém conteúdo principal para a rota /.

extends layout
block mainbody
  #mainbody
    section.mainbodyitems
      h3 Announcements
      section.announcements
        .announceitem
          h4.title Open for business
          p.date Jan. 15
          p Renovations of our new storefront are complete, and we're open for business.
      h3 Items for sale
      section.forsaleitems
        table
          tr
            th Item
            th Description
            th Price
            th.qty Qty
          tr
            td Milk
            td Good source of calcium.
            td.price $2
              span.perunit  \/half gal.
            td.qty 3
          tr
            td Eggs
            td Great for breakfast and baking.
            td.price $4
              span.perunit  \/doz.
            td.qty 6
          tr
            td Whole chicken
            td Perfect for roasting.
            td.price $5
              span.perunit  \/lb.
            td.qty 4
      h3 Upcoming events
      section
        .eventitem
          h4.title Cider Fest
          p.date October 20, 2pm&ndash;6pm
          p Celebrate the season with fresh-pressed cider from our orchards.
        .eventitem
          h4.title Bread baking workshop
          p.date December 13, 9am&ndash;noon
          p Learn how to create and cultivate a sourdough starter.
      h3 Message of the day
      section
        .motditem
          p Eat better food. Support your local farm stand.
        h3#partners.wide Our friends
        section#partners.wide
          .partnerlink.wide
            a(href="")
              .clickable-area Green Valley Greens
          .partnerlink.wide
            a(href="")
              .clickable-area Turkey Hill Farm
          .partnerlink.wide
            a(href="/")
              .clickable-area Burt's Maple Syrup
          .partnerlink.wide
            a(href="")
              .clickable-area Only Organic Seeds
        .bodyspace

myapp \/routes \/index.js

O arquivo index.js contém lógica para a rota /.

var express = require('express');
var router = express.Router();
router.get("https://www.computerhope.com/", function(req, res, next) {
  res.render('index', { pagetitle: 'Our Farm Stand' });
});
module.exports = router;

O arquivo menu.js contém o JavaScript do exemplo Grid e Flexbox. Ele implementa a função de alternância do menu.

function menuToggle(state) {
  var ele = document.getElementById('menu');
  switch(state) {
    case 'show':
      ele.style.opacity=1;
      ele.style.color="rgb(96, 96, 96)";
      ele.style.visibility='visible';
      ele.style.transition='visibility 0s, opacity 0.3s';
      break;
    case 'hide':
      ele.style.opacity=0;
      ele.style.color="black";
      ele.style.visibility='hidden';
      ele.style.transition='visibility 0.3s, opacity 0.3s'; 
      break;
  }
}

myapp \/public \/stylesheets \/style.css

O arquivo style.css contém o CSS do exemplo Grid e Flexbox.

/* element styles */
* {
  margin: 0;     /* by default, all elements (selector *) have no margin */
}
html {
  width: 100%;                    /* 100% width of parent (root) element */
  height: 100vh;                              /* 100% height of viewport */
  background: rgb(0, 0, 0, 0.1);                            /* 10% black */
  font-size: 1.0em;                                /* our root font size */
  font-family: Arial, Helvetica, sans-serif;             /* default font */
}
body {
  min-height: 100%;
}
section {
  padding: 0.5rem;
  flex-grow: 1;         /* in a flexbox, sections expand along flex axis */
}
h1 {                                           /* Website name in header */
  font-size: 2.0rem;
  font-weight: normal;
}
h2 {                                                   /* About, Contact */
  font-size: 1.25rem;
}
h3 {                                                 /* Section headings */
  font-size: 1.2rem;
  padding: 0.5rem;
}
h4 {                                               /* Section item title */
  font-weight: normal;
  padding: 0.5rem;
}
p {                                                 /* Section item body */
  padding: 0.5rem;
}
a:link, a:visited {            /* anchor links, and visited anchor links */
  color: black;
  text-decoration: none;                            /* disable underline */
}
a:hover {                                 /* when anchor link is hovered */
  color: rgb(25, 25, 25);
}
a:active {                                /* when anchor link is clicked */
  color: rgb(96, 96, 96);
}
/* component styles */
#container {
  display: grid;
  height: 100vh;
  grid-template-columns:
    [left] 10rem auto 10rem [right];
  grid-template-rows:
    [top] 5rem auto 5rem [bottom];     /* header height fits its content */
  grid-template-areas:
    "head head head"
    "panleft mainbody panright"
    "foot foot foot";
}
#header {
  grid-area: head;                    /* corresponds to name in template */
  background: rgb(0, 0, 0, 0.2);                            /* 20% black */
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: baseline;  /* site name and nav item text aligns baseline */
  padding: 1.0rem;
}
#panel {                                       /* for element id="panel" */
  display: flex;                     /* this element is a flexbox parent */
  flex-direction: column;          /* its child elements flex vertically */
  padding: 0.5rem;
  background: rgb(0, 0, 0, 0.1);                            /* 10% black */
}
#panel.left {                 /* for element id="panel" and class="left" */
  grid-area: panleft;                  /* this element fills a grid area */
}
#panel.right {
  grid-area: panright;
}
#footer {
  grid-area: foot;
  display: flex;                     /* this element is a flexbox parent */
  flex-direction: column;          /* its child elements flex vertically */
  justify-content: center;           /* horizontal center footer content */
  align-items: center;                 /* vertical center footer content */
  padding: 0.5rem;
  background: rgb(0, 0, 0, 0.2);
}
#mainbody {                                 /* for element id="mainbody" */
  display: flex;                     /* this element is a flexbox parent */
  flex-direction: column;          /* its child elements flex vertically */
  grid-area: mainbody;
  justify-self: center;          /* fixed-width mainbody always centered */
  width: 100%;
  min-width: 22.5rem;            /* mainbody width can't go < 22.5rem */
}
div#panel,
div#mainbody {                               /* extra space under header */
  padding-top: 0.5rem;
}
#partners, #sections {     /* for element id="partners" or id="sections" */
  display: flex;                     /* this element is a flexbox parent */
  flex-direction: row;           /* its child elements flex horizontally */
  flex-wrap: wrap;           /* its child elements can wrap to next line */
  align-content: flex-start;       /* child elements start in upper left */
}
#partners.wide {           /* for element id="partners" and class="wide" */
  display: none;              /* by default, do not display this element */
}
#menu {
  position: absolute;      /* menu position unaffected by other elements */
  right: 0;                       /* zero pixels from the right boundary */
  background: rgb(239, 239, 239);
  border: 0.15rem solid rgb(0, 0, 0, 0.4);
  visibility: hidden;        /* visibility property supports transitions */
  opacity: 0;      /* opacity + visibility transition = menu fade effect */
  z-index: 1;              /* ensure menu appears over all other content */
}
#menuitems {               /* menu is implemented as a flexbox container */
  display: flex;
  flex-direction: column;
  padding: 1rem;
}
#menuitems h3 {
  border-top: 0.15rem solid rgb(0, 0, 0, 0.1);  /* light horizontal rule */
}
#menuitems .sectrule {
  border-color: rgb(0, 0, 0, 0.25);            /* darker horizontal rule */
}
#menuitems .menuhead {
  border-top: none;
}
#menuitems h3:hover {
  background-color: rgb(0, 0, 0, 0.1);     /* gray of rollover menuitems */
}
.menubutton {
  text-align: right;
  cursor: pointer;            /* indicates it can be clicked like a link */
  user-select: none;            /* user cannot select the button as text */
}
#menuitems .alignright {
  text-align: right;            /* right-aligned menu item text (unused) */
}
#header h1.menubutton {
  display: none;        /* in default view (landscape), hide menu button */
  border: 0.15rem solid rgb(0, 0, 0, 0);   /* (invisible) alignment shim */
}
#header .placeholder {    /* this invisible button is rendered when menu */
  color: rgb(0, 0, 0, 0); /* button is hidden, so header height matches. */
  user-select: none;       /* user can't select text of invisible button */
}
.sectionlink, .partnerlink {
  border-radius: 0.25rem;     /* give this element a slight rounded edge */
  font-weight: normal;
  font-size: 1.1rem;
  padding: 0.5rem;
  width: 7rem;                            /* fixed width for these items */
  margin-bottom: 1rem;                  /* slight margin for readability */
  background: rgb(0, 0, 0, 0.1);
}
.sectionlink:hover, .partnerlink:hover {
  background-color: rgb(0, 0, 0, 0.065);   /* brighten bg on mouse hover */
}
.partnerlink {
  height: 7rem;        /* partner elements are additionally fixed height */
}
.partnerlink.wide {
  margin: 0.5rem 1rem 0.5rem 0;      /* margins for spacing if they wrap */
}
.clickable-area {      /* use whenever a clickable area excludes margins */
  height: 100%;                 /* clickable area spans height of parent */
}
.eventitem, .announceitem, .motditem {
  margin-bottom: 0.5rem;                /* slight margin for readability */
}
.title {                                    /* e.g., "Open for business" */
  font-style: italic;
  font-weight: normal;
  font-size: 1.1rem;
}
.date, .ingredient {                                         /* e.g., January 1, 2021 */
  font-style: italic;
  font-size: 0.9rem;
  padding: 0 0 0.01rem 0.5rem;
  color: rgb(0, 0, 0, 0.5);
}
.navitem {                                             /* About, Contact */
  font-weight: normal;
  padding: 0 0.5rem 0 1rem;
}
.headspace, .panspace, .footspace, .bodyspace {
  flex-grow: 1;      /* these elements expand on flex axis to fill space */
}
/* table styles ("items for sale") */
table {
  border-collapse: collapse;               /* pixel-adjacent table cells */
  width: 100%;
  margin-bottom: 1rem;
}
th {
  text-align: left;
}
tr {
  margin: 4rem 0 0 0;
  border-bottom: 0.15rem solid rgb(0, 0, 0, 0.2);     /* horizontal rule */
}
td, th {
  padding: 0.5rem;
  vertical-align: top;
}
td.price {
  white-space: nowrap;        /* white space in price does not wrap line */
}
td.qty, th.qty {
  text-align: center;
}
span.perunit {
  opacity: 0.5;
}
/* responsive styles applied in portrait mode */
@media screen and (max-width: 45rem) {      /* if viewport width < 45rem */
  #panel.left {
    grid-column-end: left;         /* panel grid area shrinks to nothing */
  }
  #panel.right {
    grid-column-start: right;      /* panel grid area shrinks to nothing */
  }
  #partners.tall {
    display: none;  /* hide partners in panel (overwrites display: flex) */
  }
  #partners.wide {
    display: flex;   /* show partners in body (overwrites display: none) */
  }
  #panel,                                 /* these disappear from layout */
  #header .placeholder,
  .navitem {
    display: none;
  }
  #mainbody {
    grid-column-start: left;         /* mainbody now starts at left edge */
    grid-column-end: right;           /* mainbody now ends at right edge */
  }
  #header h1.menubutton {              /* display the header menu button */
    display: inline;                         /* overwrites display: none */
  }
}

Rotas secundárias

Os arquivos a seguir contêm a lógica para rotas secundárias – Sobre, Conselho, Contato, etc.

myapp \/routes \/about.js

var express = require('express');
var router = express.Router();
router.get("https://www.computerhope.com/", function(req, res, next) {
  res.render('about', { pagetitle: 'About Us' });
});
module.exports = router;

myapp \/routes \/advis.js

var express = require('express');
var router = express.Router();
router.get("https://www.computerhope.com/", function(req, res, next) {
  res.render('advice', { pagetitle: 'Homesteading Advice' });
});
module.exports = router;

myapp \/routes \/contact.js

var express = require('express');
var router = express.Router();
router.get("https://www.computerhope.com/", function(req, res, next) {
  res.render('contact', { pagetitle: 'Contact Us' });
});
module.exports = router;

myapp \/routes \/recipes.js

var express = require('express');
var router = express.Router();
router.get("https://www.computerhope.com/", function(req, res, next) {
  res.render('recipes', { pagetitle: 'Recipes' });
});
module.exports = router;

myapp \/routes \/tips.js

var express = require('express');
var router = express.Router();
router.get("https://www.computerhope.com/", function(req, res, next) {
  res.render('tips', { pagetitle: 'Tips For Living Well' });
});
module.exports = router;

Vistas secundárias

As visualizações a seguir herdam layout.pug.

myapp \/views \/about.pug

extends layout
block mainbody
  #mainbody
    section#mainbodyitems
      p Alice &amp; Bob have been operating their farm stand since 1992.

myapp \/views \/advis.pug

extends layout
block mainbody
  #mainbody
    section#mainbodyitems
      h3 Homesteading Advice
      p Never, ever stand behind a heifer.

myapp \/views \/contact.pug

extends layout
block mainbody
  #mainbody
    section#mainbodyitems
      h3 Alice &amp; Bob
      p 1344 Chattanooga Way
      p Homestead, VT 05401
      p (802) 555-5555

myapp \/views \/recipes.pug

extends layout
block mainbody
  #mainbody
    section#mainbodyitems
      h3 Alice's Recipes
      p
        b No-knead next-day dutch oven bread
      p.ingredient 1/4 tsp active dry yeast
      p.ingredient 3 cups all-purpose flour
      p.ingredient 1 1/2 tsp salt
      p.ingredient Cornmeal or wheat bran for dusting
      p In a large bowl, dissolve yeast in water.
      p Add the flour and salt, stirring until blended.
      p Cover bowl. Let rest at least 8 hours, preferably 12 to 18, at warm room temperature, about 70 degrees.
      p When the surface of the dough is dotted with bubbles, it's ready to be folded. Lightly flour a work surface. Sprinkle flour on the dough and fold it over on itself once or twice. Cover loosely and let it rest about 15 minutes.
      p Using just enough flour to keep the dough from sticking, gently shape it into a ball. Generously coat a clean dish towel with flour, wheat bran, or cornmeal. Put the seam side of the dough on the towel. Cover with another towel and let rise for 1 to 2 hours.
      p Heat oven to 475&deg;. Cover and bake for 30 minutes.

myapp \/views \/tips.pug

extends layout
block mainbody
  #mainbody
    section#mainbodyitems
      h3 Alice's Tips
      p Always rise before the sun.
      p Never use fake maple syrup.
      p If the bear is black, be loud, attack.
      p If the bear is brown, play dead, lie down.

Aparência

No modo retrato, as rotas secundárias são acessadas no menu.

Vista de retrato

No modo paisagem, eles são acessíveis no cabeçalho e no painel esquerdo.

Vista de paisagem


Like it? Share with your friends!

0

What's Your Reaction?

hate hate
0
hate
confused confused
0
confused
fail fail
0
fail
fun fun
0
fun
geeky geeky
0
geeky
love love
0
love
lol lol
0
lol
omg omg
0
omg
win win
0
win
Rubem Rego

0 Comments

Your email address will not be published. Required fields are marked *