Merge pull request #107 from cisagov/ik/setup-uswds

Setup USWDS
This commit is contained in:
Igor Korenfeld 2022-09-13 11:29:49 -04:00 committed by GitHub
commit b7200cc9cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 11756 additions and 17 deletions

7
.gitignore vendored
View file

@ -2,6 +2,7 @@
docs/research/data/**
static/
public/
credentials*
### The usual garbage files ###
@ -148,3 +149,9 @@ cython_debug/
# Node
node_modules
# Mac
.DS_Store
# Vim
*.swp

View file

@ -61,3 +61,13 @@ Linters:
```shell
docker-compose exec app ./manage.py lint
```
## USWDS and styling
We use the U.S. Web Design System (USWDS) for building and styling our applications. Additionally, we utilize the [uswds-compile tool](https://designsystem.digital.gov/documentation/getting-started/developers/phase-two-compile/) from USWDS to compile and package the static assets.
When you run `docker-compose up` the `node` service in the container will begin to watch for changes in the `registrar/assets` folder, and will recompile once any changes are made.
Within the `registrar/assets` folder, the `_theme` folder contains three files initially generated by `uswds-compile`:
1. `_uswds-theme-custom-styles` contains all the custom styles created for this application
2. `_uswds-theme` contains all the custom theme settings (e.g. primary colors, fonts, banner color, etc..)
3. `styles.css` a entry point or index for the styles, forwards all of the other style files used in the project (i.e. the USWDS source code, the settings, and all custom stylesheets).
You can also compile the sass at any time using `npx gulp compile`. Similarly, you can copy over other static assets (images and javascript files), using `npx gulp copyAssets`.

View file

@ -36,10 +36,16 @@ Binding the database in `manifest-<ENVIRONMENT>.json` automatically inserts the
# Deploy
We have two environments: `unstable` and `staging`. Developers can deploy locally to unstable whenever they want. However, only our CD service can deploy to `staging`, and it does so on every commit to `main`. This is to ensure that we have a "golden" environment to point to, and can still test things out in an unstable space. To deploy locally to `unstable`:
We have two environments: `unstable` and `staging`. Developers can deploy locally to unstable whenever they want. However, only our CD service can deploy to `staging`, and it does so on every commit to `main`. This is to ensure that we have a "golden" environment to point to, and can still test things out in an unstable space. To deploy locally to `unstable`:
```bash
cf target -o cisa-getgov-prototyping -s unstable
cf push getgov-unstable -f ops/manifests/manifest-unstable.yaml
cf run-task getgov-unstable --command 'python manage.py migrate' --name migrate
```
## Serving static assets
We are using [WhiteNoise](http://whitenoise.evans.io/en/stable/index.html) plugin to serve our static assets on cloud.gov. This plugin is added to the `MIDDLEWARE` list in our apps `settings.py`.
Note that its a good idea to run `collectstatic` locally or in the docker container before pushing files up to `unstable`. This is because `collectstatic` relies on timestamps when deciding to whether to overwrite the existing assets in `/public`. Due the way files are uploaded, the compiled css in the `/assets/css` folder on `unstable` will have a slightly earlier timestamp than the files in `/public/css`, and consequently running `collectstatic` on`unstable` will not update `public/css` as you may expect.

View file

@ -8,7 +8,7 @@ applications:
memory: 512M
stack: cflinuxfs3
timeout: 180
command: gunicorn registrar.config.wsgi -t 60
command: ./run.sh
health-check-type: http
health-check-http-endpoint: /health
env:
@ -20,4 +20,4 @@ applications:
- route: getgov-unstable.app.cloud.gov
services:
- getgov-credentials
- getgov-unstable-database
- getgov-unstable-database

View file

@ -11,6 +11,7 @@ django-csp = "*"
environs = {extras=["django"]}
gunicorn = "*"
psycopg2-binary = "*"
whitenoise = "*"
[dev-packages]
django-debug-toolbar = "*"
@ -19,4 +20,4 @@ bandit = "*"
black = "*"
flake8 = "*"
mypy = "*"
types-requests = "*"
types-requests = "*"

28
src/Pipfile.lock generated
View file

@ -46,11 +46,11 @@
},
"django": {
"hashes": [
"sha256:031ccb717782f6af83a0063a1957686e87cb4581ea61b47b3e9addf60687989a",
"sha256:032f8a6fc7cf05ccd1214e4a2e21dfcd6a23b9d575c6573cacc8c67828dbe642"
"sha256:a153ffd5143bf26a877bfae2f4ec736ebd8924a46600ca089ad96b54a1d4e28e",
"sha256:acb21fac9275f9972d81c7caf5761a89ec3ea25fe74545dd26b8a48cb3a0203e"
],
"index": "pypi",
"version": "==4.1"
"version": "==4.1.1"
},
"django-allow-cidr": {
"hashes": [
@ -196,11 +196,11 @@
},
"python-dotenv": {
"hashes": [
"sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f",
"sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"
"sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5",
"sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"
],
"markers": "python_version >= '3.5'",
"version": "==0.20.0"
"markers": "python_version >= '3.7'",
"version": "==0.21.0"
},
"setuptools": {
"hashes": [
@ -225,6 +225,14 @@
],
"markers": "python_version >= '3.5'",
"version": "==0.4.2"
},
"whitenoise": {
"hashes": [
"sha256:8e9c600a5c18bd17655ef668ad55b5edf6c24ce9bdca5bf607649ca4b1e8e2c2",
"sha256:8fa943c6d4cd9e27673b70c21a07b0aa120873901e099cd46cab40f7cc96d567"
],
"index": "pypi",
"version": "==6.2.0"
}
},
"develop": {
@ -291,11 +299,11 @@
},
"django": {
"hashes": [
"sha256:031ccb717782f6af83a0063a1957686e87cb4581ea61b47b3e9addf60687989a",
"sha256:032f8a6fc7cf05ccd1214e4a2e21dfcd6a23b9d575c6573cacc8c67828dbe642"
"sha256:a153ffd5143bf26a877bfae2f4ec736ebd8924a46600ca089ad96b54a1d4e28e",
"sha256:acb21fac9275f9972d81c7caf5761a89ec3ea25fe74545dd26b8a48cb3a0203e"
],
"index": "pypi",
"version": "==4.1"
"version": "==4.1.1"
},
"django-debug-toolbar": {
"hashes": [

View file

@ -40,3 +40,12 @@ services:
- POSTGRES_DB=app
- POSTGRES_USER=user
- POSTGRES_PASSWORD=feedabee
node:
image: node
volumes:
- .:/app
working_dir: /app
stdin_open: true
tty: true
command: ./run_node_watch.sh

35
src/gulpfile.js Normal file
View file

@ -0,0 +1,35 @@
/* gulpfile.js */
const uswds = require('@uswds/compile');
/**
* USWDS version
* Set the version of USWDS you're using (2 or 3)
*/
uswds.settings.version = 3;
/**
* Path settings
* Set as many as you need
*/
const ASSETS_DIR = './registrar/assets/';
uswds.paths.dist.css = ASSETS_DIR + 'css';
uswds.paths.dist.sass = ASSETS_DIR + 'sass';
uswds.paths.dist.theme = ASSETS_DIR + 'sass/_theme';
uswds.paths.dist.fonts = ASSETS_DIR + 'fonts';
uswds.paths.dist.js = ASSETS_DIR + 'js';
uswds.paths.dist.img = ASSETS_DIR + 'img';
/**
* Exports
* Add as many as you need
*/
exports.init = uswds.init;
exports.compile = uswds.compile;
exports.watch = uswds.watch;
exports.copyAssets = uswds.copyAssets

11301
src/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

18
src/package.json Normal file
View file

@ -0,0 +1,18 @@
{
"name": "getgov",
"version": "1.0.0",
"description": "========================",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@uswds/uswds": "^3.1.0",
"sass": "^1.54.8"
},
"devDependencies": {
"@uswds/compile": "^1.0.0-beta.3"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

@ -0,0 +1,28 @@
/*
* * * * * ==============================
* * * * * ==============================
* * * * * ==============================
* * * * * ==============================
========================================
========================================
========================================
----------------------------------------
USWDS THEME CUSTOM STYLES
----------------------------------------
!! Copy this file to your project's
sass root. Don't edit the version
in node_modules.
----------------------------------------
Custom project SASS goes here.
i.e.
@include u-padding-right('05');
----------------------------------------
*/
@use "uswds-core" as *;
// Test custom style
p {
color: color('blue-10v');
}

View file

@ -0,0 +1,22 @@
/*
----------------------------------------
USWDS with settings overrides
----------------------------------------
Uncomment the following lines and add a list of changed settings
in the form $setting: value,
----------------------------------------
*/
//
// @use "uswds-core" with (
// $setting: value,
// $setting: value
// );
//
@use "uswds-core" with (
$theme-banner-background-color: "ink",
$theme-banner-link-color: "primary-light",
$theme-banner-max-width: "none",
$theme-show-notifications: false,
$theme-hero-image: "../img/registrar/dotgov_banner.png"
)

View file

@ -0,0 +1,11 @@
/*--------------------------------------------------
--- USWDS Settings --------------------------------*/
@forward "uswds-theme";
/*--------------------------------------------------
--- USWDS Source ----------------------------------*/
@forward "uswds";
/*--------------------------------------------------
--- Custom Styles ---------------------------------*/
@forward "uswds-theme-custom-styles";

View file

@ -88,6 +88,8 @@ INSTALLED_APPS = [
MIDDLEWARE = [
# django-allow-cidr: enable use of CIDR IP ranges in ALLOWED_HOSTS
"allow_cidr.middleware.AllowCIDRMiddleware",
# serve static assets in production
"whitenoise.middleware.WhiteNoiseMiddleware",
# provide security enhancements to the request/response cycle
"django.middleware.security.SecurityMiddleware",
# store and retrieve arbitrary data on a per-site-visitor basis
@ -130,7 +132,11 @@ WSGI_APPLICATION = "registrar.config.wsgi.application"
# will place static files for deployment.
# Do not use this directory for permanent storage -
# it is for Django!
STATIC_ROOT = BASE_DIR / "static"
STATIC_ROOT = BASE_DIR / "public"
STATICFILES_DIRS = [
BASE_DIR / "assets",
]
# TODO: decide on template engine and document in ADR
TEMPLATES = [

View file

@ -8,9 +8,13 @@ from django.conf import settings
from django.contrib import admin
from django.urls import include, path
from registrar.views import health
from registrar.views import health, index
urlpatterns = [path("admin/", admin.site.urls), path("health/", health.health)]
urlpatterns = [
path("admin/", admin.site.urls),
path("", index.index),
path("health/", health.health),
]
if settings.DEBUG:
import debug_toolbar

View file

@ -0,0 +1,215 @@
<!doctype html>{# keep this on the first line #}
{% load i18n static %}
<html class="no-js" lang="{{ LANGUAGE_CODE }}">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>
{% block title %}{% endblock %}
{{ site.name }}
{% block extra_title %}{% endblock %}
</title>
<meta name="description" content="{% block description %}{% endblock %}">
{% block viewport_meta %}
<meta name="viewport" content="width=device-width, initial-scale=1">
{% endblock %}
{% block extra_meta %}{% endblock extra_meta %}
{# TO-DO: Determine if <link rel="manifest" href="site.webmanifest"> is desirable #}
{# TO-DO: set defaults for these #}
<link rel="shortcut icon" href="{% static 'img/favicon.png' %}">
<link rel="apple-touch-icon" href="{% static 'img/touch-icon.png' %}">
{% block css %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
<script src="{% static 'js/uswds-init.min.js' %}" defer></script>
{% endblock %}
{% block canonical %}
<link rel="canonical" href="{{ current_path }}">
{% endblock %}
{% block feeds %}{% endblock %}
{% block extra_head %}{% endblock %}
{# hat tip to USWDS... #}
<!-- * * * * * ======================= -->
<!-- * * * * * ======================= -->
<!-- * * * * * ======================= -->
<!-- * * * * * ======================= -->
<!-- ================================= -->
<!-- ================================= -->
<!-- ================================= -->
</head>
<body id="{% block body_id %}default{% endblock %}" class="{% block body_class %}section_front{% endblock %}">
<script src="{% static 'js/uswds.min.js' %}" defer></script>
<a class="usa-skipnav" href="#main-content">Skip to main content</a>
<section class="usa-banner" aria-label="Official government website">
<div class="usa-accordion">
<header class="usa-banner__header">
<div class="usa-banner__inner">
<div class="grid-col-auto">
<img
class="usa-banner__header-flag"
src="{% static 'img/us_flag_small.png' %}"
alt="U.S. flag"
/>
</div>
<div class="grid-col-fill tablet:grid-col-auto">
<p class="usa-banner__header-text">
An official website of the United States government
</p>
<p class="usa-banner__header-action" aria-hidden="true">
Heres how you know
</p>
</div>
<button
class="usa-accordion__button usa-banner__button"
aria-expanded="false"
aria-controls="gov-banner-default-default"
>
<span class="usa-banner__button-text">Heres how you know</span>
</button>
</div>
</header>
<div
class="usa-banner__content usa-accordion__content"
id="gov-banner-default-default"
>
<div class="grid-row grid-gap-lg">
<div class="usa-banner__guidance tablet:grid-col-6">
<img
class="usa-banner__icon usa-media-block__img"
src="{% static 'img/icon-dot-gov.svg' %}"
role="img"
alt=""
aria-hidden="true"
/>
<div class="usa-media-block__body">
<p>
<strong>Official websites use .gov</strong><br />A
<strong>.gov</strong> website belongs to an official government
organization in the United States.
</p>
</div>
</div>
<div class="usa-banner__guidance tablet:grid-col-6">
<img
class="usa-banner__icon usa-media-block__img"
src="{% static 'img/icon-https.svg' %}"
role="img"
alt=""
aria-hidden="true"
/>
<div class="usa-media-block__body">
<p>
<strong>Secure .gov websites use HTTPS</strong><br />A
<strong>lock</strong> (
<span class="icon-lock"
><svg
xmlns="http://www.w3.org/2000/svg"
width="52"
height="64"
viewBox="0 0 52 64"
class="usa-banner__lock-image"
role="img"
aria-labelledby="banner-lock-title-default banner-lock-description-default"
focusable="false"
>
<title id="banner-lock-title-default">Lock</title>
<desc id="banner-lock-description-default">A locked padlock</desc>
<path
fill="#000000"
fill-rule="evenodd"
d="M26 0c10.493 0 19 8.507 19 19v9h3a4 4 0 0 1 4 4v28a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V32a4 4 0 0 1 4-4h3v-9C7 8.507 15.507 0 26 0zm0 8c-5.979 0-10.843 4.77-10.996 10.712L15 19v9h22v-9c0-6.075-4.925-11-11-11z"
/>
</svg> </span
>) or <strong>https://</strong> means youve safely connected to
the .gov website. Share sensitive information only on official,
secure websites.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
{% block banner %}
<header class="usa-header usa-header-extended" role="banner">
<div class="usa-navbar">
{% block logo %}
<div class="usa-logo" id="extended-logo">
<em class="usa-logo-text">
<a href="/"
title="Home"
aria-label="Home">
{% block site_name %}{{ site.name }}{% endblock %}
</a>
</em>
</div>
{% endblock %}
<button class="usa-menu-btn">Menu</button>
</div>
{% block usa_nav %}
{% block usa_nav_secondary %}{% endblock %}
{% endblock %}
</header>
{% endblock banner %}
{% block usa_overlay %}<div class="usa-overlay"></div>{% endblock %}
<div id="wrapper">
{% block messages %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
{{ message }}
</li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}
{% block section_nav %}{% endblock %}
<main id="main-content">
{% block hero %}{% endblock %}
{% block content %}{% endblock %}
</main>
<div role="complementary">{% block complementary %}{% endblock %}</div>
{% block content_bottom %}{% endblock %}
</div>
<footer id="footer" role="contentinfo">
{% block footer_nav %}
{% endblock %}
{% block footer %}
<div>
<p class="copyright">&copy; {{ now.year }} {{ site.name }}</p>
</div>
{% endblock %}
</footer>
</div> <!-- /#wrapper -->
{% block init_js %}{% endblock %}{# useful for vars and other initializations #}
{% block site_js %}
{% endblock %}
{% block app_js %}{% endblock %}
{% block extrascript %}{% endblock %}
{# asynchronous analytics #}
<script async id="_fed_an_ua_tag" src="https://dap.digitalgov.gov/Universal­Federated­Analytics­M
in.js?agency={{ AGENCY }}"></script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!-- Test page -->
{% extends 'base.html' %}
{% block title %} Hello {% endblock %}
{% block hero %}
<section class="usa-hero">
<div class="usa-grid">
<div class="usa-hero-callout usa-section-dark">
<h2>
<span class="usa-hero-callout-alt">This is sample content.</span>
This is only sample content.
</h2>
<p> {{ name }} You'll want to replace it with content of your own.</p>
<button class="usa-button usa-button--accent-cool">Click a usa button</button>
</div>
</div>
</section>
{% endblock %}

View file

@ -0,0 +1,6 @@
from django.shortcuts import render
def index(request):
context = {"name": "World!"}
return render(request, "whoami.html", context)

19
src/run.sh Executable file
View file

@ -0,0 +1,19 @@
#/bin/bash
set -o errexit
set -o pipefail
# Only run migrations on the zeroth index when in a cloud.gov environment
if [[ -v CF_INSTANCE_INDEX && $CF_INSTANCE_INDEX == 0 ]]
then
python manage.py migrate --settings=registrar.config.settings --noinput
else
echo "Migrations did not run."
if [[ -v CF_INSTANCE_INDEX ]]
then
echo "CF Instance Index is ${CF_INSTANCE_INDEX}."
fi
fi
python manage.py collectstatic --settings=registrar.config.settings --noinput
gunicorn registrar.config.wsgi -t 60

15
src/run_node_watch.sh Executable file
View file

@ -0,0 +1,15 @@
#!/bin/bash
npm install
npm rebuild
dir=./registrar/assets
if [ -d "$dir" ]
then
echo "Compiling USWDS assets"
npx gulp copyAssets
npx gulp compile
else
echo "Initial USWDS assets build"
npx gulp init
npx gulp compile
fi
npx gulp watch