Project 3: Portfolio: Creating an individual project page (+159, -2)
styles.css (+95, -0)
From:
curriculum/section12/lectures/09_creating_a_project_page/start/portfolio/static/css/styles.css
To:
curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/static/css/styles.css
index eca1d2f..5d1ab8f 100644
--- a/curriculum/section12/lectures/09_creating_a_project_page/start/portfolio/static/css/styles.css
+++ b/curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/static/css/styles.css
@@ -36,10 +36,13 @@ body {
}
.main {
+ display: flex;
+ justify-content: center;
margin: 0 auto;
}
.main--about {
+ flex-direction: column;
max-width: 500px;
padding: 0 1rem;
line-height: 150%;
@@ -153,6 +156,98 @@ body {
margin: 0 0.25rem;
}
+.hero {
+ width: 100%;
+ margin-bottom: 1.5rem;
+}
+
+.project {
+ display: flex;
+ flex-direction: column;
+ font-size: 1.2rem;
+ max-width: 50rem;
+ padding: 0 1rem;
+}
+
+.project__content {
+ margin-bottom: 1rem;
+ line-height: 150%;
+}
+
+@media (min-width: 48.75em) {
+ .project {
+ flex-direction: row;
+ padding: 0;
+ }
+
+ .project__content {
+ flex: 7;
+ margin-right: 3rem;
+ padding: 0;
+ }
+}
+
+.project__heading {
+ margin: 0;
+ font-size: 2rem;
+ line-height: 150%;
+}
+
+.project__heading--meta {
+ font-size: inherit;
+ margin-bottom: 1rem;
+}
+
+.project__meta-group {
+ margin-bottom: 1rem;
+}
+
+.project__meta-group,
+.cta {
+ padding: 1rem;
+ background-color: #d4eafa;
+ border-radius: 6px;
+}
+
+.cta {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ color: #1c2023;
+ text-decoration: none;
+}
+
+.cta:hover {
+ text-decoration: underline;
+}
+
+.cta__icon {
+ margin-right: 0.5rem;
+ transform: translateY(1px);
+}
+
+.technology-list {
+ list-style: none;
+ padding-left: 0.75rem;
+ margin: 0;
+ line-height: 1.75;
+}
+
+.technology-list__item:before {
+ content: "";
+ display: inline-block;
+ height: 1rem;
+ width: 1rem;
+ background-image: url("/static/img/list-check.svg");
+ background-size: contain;
+ background-repeat: no-repeat;
+ margin-right: 0.5rem;
+
+ /* necessary for vertical centering */
+ transform: translateY(2px);
+}
+
/* Utility class to remove link styles */
.u-bare-link {
text-decoration: none;
__init__.py (+16, -1)
From:
curriculum/section12/lectures/09_creating_a_project_page/start/portfolio/__init__.py
To:
curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/__init__.py
index 0488446..936e351 100644
--- a/curriculum/section12/lectures/09_creating_a_project_page/start/portfolio/__init__.py
+++ b/curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/__init__.py
@@ -1,4 +1,4 @@
-from flask import Flask, render_template
+from flask import Flask, render_template, abort
app = Flask(__name__)
projects = [
@@ -26,6 +26,8 @@ projects = [
},
]
+slug_to_project = {project["slug"]: project for project in projects}
+
@app.route("/")
def home():
@@ -40,3 +42,16 @@ def about():
@app.route("/contact")
def contact():
return render_template("contact.html")
+
+
+# Two ways to do this:
+# - either store everything about a project in Python and populate a generic `project.html` template.
+# - or as done here, have separate templates for each project
+# At the end of the day, we have to write the project info somewhere, and HTML is a great tool for that.
+# This allows each project to be slightly different as we choose,
+# And with Jinja2 we can always reuse parts of the code as macros (more on that, later!)
+@app.route("/project/<string:slug>")
+def project(slug):
+ if slug not in slug_to_project:
+ abort(404)
+ return render_template(f"project_{slug}.html", project=slug_to_project[slug])
home.html (+1, -1)
From:
curriculum/section12/lectures/09_creating_a_project_page/start/portfolio/templates/home.html
To:
curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/templates/home.html
index 618d226..df5adfc 100644
--- a/curriculum/section12/lectures/09_creating_a_project_page/start/portfolio/templates/home.html
+++ b/curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/templates/home.html
@@ -3,7 +3,7 @@
<main class="main main--home">
<section class="projects">
{% for project in projects %}
- <a class="u-bare-link" href="#">
+ <a class="u-bare-link" href="{{ url_for('project', slug=project['slug']) }}">
<article class="project-card">
<img
class="project-card__image"
project_habit-tracking.html (+47, -0)
From:
curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/templates/project_habit-tracking.html
To:
curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/templates/project_habit-tracking.html
new file mode 100644
index 0000000..5fdbc6f
--- /dev/null
+++ b/curriculum/section12/lectures/09_creating_a_project_page/end/portfolio/templates/project_habit-tracking.html
@@ -0,0 +1,47 @@
+{% extends 'base.html' %}
+{% block content %}
+ <main class="main main--project">
+ <div>
+ <img
+ class="hero"
+ src="{{ url_for('static', filename=project['hero']) }}"
+ alt="A hand holding a pen, about to write something in a project planner."
+ />
+
+ <article class="project">
+ <article class="project__content">
+ <h2 class="project__heading">{{ project['name'] }}</h2>
+
+ <p>
+ Hi, I'm Bob! I love helping students learn to code and master software development.
+ I've been teaching online for over 6 years, and I founded Teclado to bring software
+ development to everyone—my objective is for you to truly understand everything
+ that goes on behind the scenes.
+ </p>
+ <p>
+ Coding is extremely rewarding. As you learn, things start to click and make sense.
+ You can join the dots of all the things that weren't quite clear before.
+ I'm here to make that journey quick and painless!
+ </p>
+ </article>
+
+ <section>
+ <article class="project__meta-group">
+ <h3 class="project__heading project__heading--meta">Technologies used</h3>
+
+ <ul class="technology-list">
+ <li class="technology-list__item">Python</li>
+ <li class="technology-list__item">HTML</li>
+ <li class="technology-list__item">CSS</li>
+ </ul>
+ </article>
+
+ <a class="cta" href="{{ project['prod'] }}">
+ <img class="cta__icon" src="{{ url_for('static', filename='img/pointer.svg') }}">
+ View in production
+ </a>
+ </section>
+ </article>
+ </div>
+ </main>
+{% endblock %}