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 %}