diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6472996..4d7633f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,39 +1,53 @@ -name: Deploy site to Pages +name: Deploy site to GitHub Pages on: + # Runs on pushes targeting the default branch push: branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab workflow_dispatch: +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" - cancel-in-progress: true + cancel-in-progress: false jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Setup Ruby + uses: ruby/setup-ruby@v1.180.1 + with: + bundler-cache: true + - name: Build Site + run: bundle exec ruby build.rb + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: _build/ + + # Deployment job deploy: environment: name: github-pages - url: $! + url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest + needs: build steps: - - uses: actions/checkout@v3 - - uses: DeterminateSystems/nix-installer-action@v9 - - uses: DeterminateSystems/magic-nix-cache-action@v2 - - uses: cachix/cachix-action@v15 - with: - name: aleksrutins - - uses: actions/configure-pages@v2 - - name: Build Site - run: 'nix build .' - - name: Upload artifact - uses: actions/upload-pages-artifact@v1 - with: - path: './result' - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v1 \ No newline at end of file + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index c17e135..c6a151b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -cheetah.toml _build/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/biocircuits.iml b/.idea/biocircuits.iml new file mode 100644 index 0000000..f92546a --- /dev/null +++ b/.idea/biocircuits.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..335b1ec --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..29ddb7a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..65f9e5b --- /dev/null +++ b/Gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# gem "rails" +gem "phlex", "~> 1.11" +gem "phlexite", "~> 0.1.3" +gem "kramdown", "~> 2.5" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..3337a09 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,22 @@ +GEM + remote: https://rubygems.org/ + specs: + kramdown (2.5.1) + rexml (>= 3.3.9) + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + phlex (1.11.0) + phlexite (0.1.3) + rexml (3.4.0) + +PLATFORMS + x64-mingw-ucrt + +DEPENDENCIES + kramdown (~> 2.5) + kramdown-parser-gfm (~> 1.1) + phlex (~> 1.11) + phlexite (~> 0.1.3) + +BUNDLED WITH + 2.5.22 diff --git a/assets/math.js b/assets/math.js index a6f142e..ff44f1e 100644 --- a/assets/math.js +++ b/assets/math.js @@ -1,3 +1,18 @@ +document.addEventListener("DOMContentLoaded", function() { + renderMathInElement(document.body, { + // customised options + // • auto-render specific keys, e.g.: + delimiters: [ + {left: '$$', right: '$$', display: true}, + {left: '$', right: '$', display: false}, + {left: '\\(', right: '\\)', display: false}, + {left: '\\[', right: '\\]', display: true} + ], + // • rendering keys, e.g.: + throwOnError : false + }); +}); + function defineVars(vars) { const data = new Map(vars); diff --git a/assets/site.css b/assets/site.css index 5ee6b0a..9f62570 100644 --- a/assets/site.css +++ b/assets/site.css @@ -172,4 +172,143 @@ i.cite { margin: 10px; border-top: 1px solid; opacity: 0.8; -} \ No newline at end of file +} + +/* */ +nav.nav-links { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.nav-links a { + display: block; + color: var(--color-theme-1); + text-decoration: none; + border-bottom: 1px solid transparent; + transition-property: border-color; + transition-duration: .5s; +} + +.nav-links a:hover { + border-color: var(--color-theme-1); +} +/* */ + +/* */ + +a.section-link { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 10px; + margin-top: 10px; + margin-bottom: 10px; + text-decoration: none !important; + text-transform: uppercase; + color: inherit; + --bg-hover: black; + background-image: linear-gradient(135deg, + var(--bg-hover) 0%, + var(--bg-hover) 50%, + transparent 50%, + transparent 100% + ); + background-size: 250%; + background-position: 90% 90%; + border: 2px solid; + transition-property: color, border-color, background-position, background-color, background-image; + transition-duration: .75s; +} +a.section-link span, a.section-link svg { + display: block; +} +a.section-link:hover { + color: white; + background-position: 0% 0%; + border-color: black; +} +a.section-link:active { + --bg-hover: var(--color-theme-1); + border-color: var(--color-theme-1); + color: var(--color-theme-1); + background-position: -75% -75%; +} + +/* */ + +/* */ +@keyframes fade { + 0% { + opacity: 0; + pointer-events: none; + } + 100% { + opacity: 1; + pointer-events: all; + } +} +.fade { + opacity: 0; + pointer-events: none; + animation: fade .5s linear 0s 1 forwards normal; +} +.fade2 { + animation-delay: 2s; +} +.fade3 { + animation-delay: 4s; +} +.fade4 { + animation-delay: 4.25s; +} +.fade5 { + animation-delay: 4.5s; +} +.fade.no-delay { + animation-delay: 0s !important; +} + +h1 { + width: 100%; +} + +.welcome { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + position: relative; + width: 100%; +} + +.welcome img { + display: block; + opacity: 0.7; +} + +.tagline { + align-self: center; + font-style: italic; + margin-top: -10px; +} + +.under-construction { + padding: 10px; + margin-top: 10px; + margin-bottom: 10px; + text-transform: uppercase; + color: inherit; + border: 2px solid; + opacity: 0.9; + text-align: center; + background: repeating-linear-gradient( + 45deg, + rgba(0, 0, 0, 0), + rgba(0, 0, 0, 0) 10px, + rgba(0, 0, 0, 0.1) 10px, + rgba(0, 0, 0, 0.1) 20px + ); +} +/* */ \ No newline at end of file diff --git a/build.rb b/build.rb new file mode 100644 index 0000000..d75f834 --- /dev/null +++ b/build.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'phlex' +require 'phlexite' +require 'kramdown' + +require_relative 'views/base_layout' +require_relative 'views/nav_links' +require_relative 'views/section_link' +require_relative 'views/page_layout' +require_relative 'views/pages/index' +require_relative 'views/pages/markdown_page' + +def pages = [ + ['concepts', 'Concepts of Biocircuits'], + ['simplest-circuit', "The Simplest Circuit"], + ['repressors', 'Repressors & Leaks'], + ['activators', 'Activators'], + ['hill-functions', 'Ultrasensitivity & the Hill Function'], + ['activators-vs-repressors', 'Choosing Between Activators & Repressors'], +] + +Phlexite::Site.new do |s| + s.mount 'assets', on: '/assets' + + s.page 'index.html', BC::Views::Pages::Index.new + + pages.each_index { |idx| + page = pages[idx] + prev = idx <= 0 ? nil : "/#{pages[idx - 1][0]}.html" + fwd = idx >= pages.length - 1 ? nil : "/#{pages[idx + 1][0]}.html" + s.page "#{page[0]}.html", BC::Views::Pages::MarkdownPage.new(File.read("./views/pages/#{page[0]}.md"), page[1], prev, fwd) + } +end \ No newline at end of file diff --git a/components/nav-links.html b/components/nav-links.html deleted file mode 100644 index c0b6916..0000000 --- a/components/nav-links.html +++ /dev/null @@ -1,29 +0,0 @@ - - - \ No newline at end of file diff --git a/components/section-link.html b/components/section-link.html deleted file mode 100644 index e9c9830..0000000 --- a/components/section-link.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/flake.lock b/flake.lock deleted file mode 100644 index d090f65..0000000 --- a/flake.lock +++ /dev/null @@ -1,245 +0,0 @@ -{ - "nodes": { - "cheetah": { - "inputs": { - "naersk": "naersk", - "nixpkgs": "nixpkgs_2", - "packsnap": "packsnap", - "utils": "utils" - }, - "locked": { - "lastModified": 1717535613, - "narHash": "sha256-nyppnrB7J1RaeqCaH6O22QsC/c+N0LTNXw3XgsPzxFg=", - "rev": "1b42da203e960f6cad517ad80e0e2dcf5625e884", - "revCount": 67, - "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/aleksrutins/cheetah/0.2.3/018fe51b-41d1-7c39-af34-e6ff00a655b2/source.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://flakehub.com/f/aleksrutins/cheetah/0.2.3.tar.gz" - } - }, - "flake-utils": { - "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "naersk": { - "inputs": { - "nixpkgs": "nixpkgs" - }, - "locked": { - "lastModified": 1698420672, - "narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=", - "owner": "nix-community", - "repo": "naersk", - "rev": "aeb58d5e8faead8980a807c840232697982d47b9", - "type": "github" - }, - "original": { - "owner": "nix-community", - "ref": "master", - "repo": "naersk", - "type": "github" - } - }, - "naersk_2": { - "inputs": { - "nixpkgs": "nixpkgs_3" - }, - "locked": { - "lastModified": 1698420672, - "narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=", - "owner": "nix-community", - "repo": "naersk", - "rev": "aeb58d5e8faead8980a807c840232697982d47b9", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "naersk", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1703499205, - "narHash": "sha256-lF9rK5mSUfIZJgZxC3ge40tp1gmyyOXZ+lRY3P8bfbg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1703499205, - "narHash": "sha256-lF9rK5mSUfIZJgZxC3ge40tp1gmyyOXZ+lRY3P8bfbg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1703499205, - "narHash": "sha256-lF9rK5mSUfIZJgZxC3ge40tp1gmyyOXZ+lRY3P8bfbg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_4": { - "locked": { - "lastModified": 1671548329, - "narHash": "sha256-OrC6R6zihRjFqdKFF3/vD3bkz44poONSII8ncre1Wh0=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "ba6ba2b90096dc49f448aa4d4d783b5081b1cc87", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "npmlock2nix": { - "flake": false, - "locked": { - "lastModified": 1673447413, - "narHash": "sha256-sJM82Sj8yfQYs9axEmGZ9Evzdv/kDcI9sddqJ45frrU=", - "owner": "nix-community", - "repo": "npmlock2nix", - "rev": "9197bbf397d76059a76310523d45df10d2e4ca81", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "npmlock2nix", - "type": "github" - } - }, - "packsnap": { - "inputs": { - "flake-utils": "flake-utils", - "naersk": "naersk_2", - "nixpkgs": "nixpkgs_4", - "npmlock2nix": "npmlock2nix" - }, - "locked": { - "lastModified": 1703773328, - "narHash": "sha256-0sbdKBuPr5UAl71jEPocp0OPhp6vuU4lqdJ8c+vPMqo=", - "owner": "aleksrutins", - "repo": "packsnap", - "rev": "08f30585d31d06f55656b1392c5f7d509900770e", - "type": "github" - }, - "original": { - "owner": "aleksrutins", - "repo": "packsnap", - "type": "github" - } - }, - "root": { - "inputs": { - "cheetah": "cheetah", - "utils": "utils_2" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 8ed9f42..0000000 --- a/flake.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - inputs = { - cheetah.url = "https://flakehub.com/f/aleksrutins/cheetah/0.2.3.tar.gz"; - utils.url = "github:numtide/flake-utils"; - }; - - outputs = { self, utils, cheetah }: - let config = { - always_hydrate = true; - }; - in utils.lib.eachDefaultSystem (system: { - packages.default = (cheetah.buildSite.${system} ./. { - name = "site"; - inherit config; - }); - - devShells.default = (cheetah.createDevShell.${system} { inherit config; }); - }); -} diff --git a/layouts/base.html b/layouts/base.html deleted file mode 100644 index 9a5c38a..0000000 --- a/layouts/base.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - {{title}} | Biocircuits for Mere Mortals - - - - - - - - - - - - - - -
-
- - -
-
- - \ No newline at end of file diff --git a/layouts/page.html b/layouts/page.html deleted file mode 100644 index e151fef..0000000 --- a/layouts/page.html +++ /dev/null @@ -1,11 +0,0 @@ - -

-

- -

- - - -

- -

\ No newline at end of file diff --git a/pages/index.html b/pages/index.html deleted file mode 100644 index 182d0d7..0000000 --- a/pages/index.html +++ /dev/null @@ -1,121 +0,0 @@ - - -
-

- Biological Circuits -

-

for mere mortals

-

(albeit ones who know a bit of differential calculus)

- -

DISCLAIMER: This is a school project. I would like to think that the CalTech course I've drawn from has made me somewhat knowledgeable on this topic, but please do not use this for medical advice, etc., etc. If you happen to know what you are doing, and you find a mistake on this website, please tell me about it. With that said:

- -

- Biological circuit design is the science of abstracting natural biological processes by defining them - as you would any synthetic circuit. It also allows us to create our own circuits out of natural components. - As CalTech's open-source Biocircuits course states: -

- -
- Indeed, the marvelous progression of electronic circuit capabilities [...] could well describe biological circuits decades from now. Like electronics, we may will soon be able to program cellular “miracle devices” to create “little gadgets” that address serious environmental and medical applications. -
- -

That CalTech course will be the main source for this presentation. All diagrams are from it.

- -

Let's dive in!

- -
- 1. Concepts of Biocircuits - 2. The Simplest Circuit - 3. Repressors & Leaks - 4. Activators - 5. Ultrasensitivity & the Hill Function - 6. Choosing Between Activators & Repressors -
- More Sections To Come -
-
-
- - - - \ No newline at end of file diff --git a/views/base_layout.rb b/views/base_layout.rb new file mode 100644 index 0000000..4507c84 --- /dev/null +++ b/views/base_layout.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module BC + module Views + class BaseLayout < ::Phlex::HTML + def initialize(title) + @title = title + end + + def view_template + doctype + html do + head do + meta charset: 'utf-8' + meta name: 'viewport', content: 'width=device-width, initial-scale=1.0' + title { @title + " | Biocircuits for Mere Mortals" } + + link rel: 'stylesheet', href: '/assets/site.css' + + link rel: "stylesheet", href: "https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css", integrity: "sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww", crossorigin: "anonymous" + script defer: true, src: "https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js", integrity: "sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd", crossorigin: "anonymous" + script defer: true, src: "https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/mhchem.min.js", integrity: "sha384-ifpG+NlgMq0kvOSGqGQxW1mJKpjjMDmZdpKGq3tbvD3WPhyshCEEYClriK/wRVU0", crossorigin: "anonymous" + script defer: true, src: "https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js", integrity: "sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk", crossorigin: "anonymous" + + script src: "/assets/math.js" + + script src: "https://unpkg.com/function-plot/dist/function-plot.js" + end + + body do + div class: "app" do + main do + yield + footer do + p do + plain "© 2024 " + a(href: "https://farthergate.com") { "Aleks Rūtiņš" } + end + + unsafe_raw { +<Built with Cheetah, Function Plot, and $\KaTeX$

+

+ With the exception of pasted graphics, where the source is noted, this work is licensed under a Creative Commons Attribution License CC BY-NC-SA 4.0. All code contained herein is licensed under an MIT license. +

+EOF + } + end + end + end + end + end + end + end + end +end diff --git a/views/nav_links.rb b/views/nav_links.rb new file mode 100644 index 0000000..1973c30 --- /dev/null +++ b/views/nav_links.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module BC + module Views + class NavLinks < ::Phlex::HTML + def initialize(back, fwd) + @back = back + @fwd = fwd + end + + def view_template + nav class: 'nav-links' do + @back ? a(href: @back) { "BACK" } : div(style: "visibility: hidden") { "BACK" } + a(href: "/") { "HOME" } + @fwd ? a(href: @fwd) { "NEXT" } : div(style: "visibility: hidden") { "NEXT" } + end + end + end + end +end diff --git a/views/page_layout.rb b/views/page_layout.rb new file mode 100644 index 0000000..bb6d5f9 --- /dev/null +++ b/views/page_layout.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module BC + module Views + class PageLayout < ::Phlex::HTML + def initialize(title, back, fwd) + @title = title + @back = back + @fwd = fwd + end + def view_template + render(BaseLayout.new(@title)) do + p + + p do + render(NavLinks.new(@back, @fwd)) + end + + yield + + p do + render(NavLinks.new(@back, @fwd)) + end + end + end + end + end +end diff --git a/pages/activators-vs-repressors.md b/views/pages/activators-vs-repressors.md similarity index 77% rename from pages/activators-vs-repressors.md rename to views/pages/activators-vs-repressors.md index f85eb10..fd78984 100644 --- a/pages/activators-vs-repressors.md +++ b/views/pages/activators-vs-repressors.md @@ -23,12 +23,9 @@ At this point, we're pretty sure that, in the majority of cases, regulators are You've reached the end, for now. I hope to expand this site in the future. If you have any questions, comments, or suggestions, please feel free to [tell me about them](https://github.com/aleksrutins/biocircuits/issues/new). -
-[^1] Savageau, M. A. (1977). Design of molecular control mechanisms and the demand for gene expression. Proceedings of the National Academy of Sciences, 74(12), 5647–5651. +[^1]: Savageau, M. A. (1977). Design of molecular control mechanisms and the demand for gene expression. Proceedings of the National Academy of Sciences, 74(12), 5647–5651. -[^2] Shinar, G., Dekel, E., Tlusty, T., & Alon, U. (2006). Rules for biological regulation based on error minimization. Proceedings of the National Academy of Sciences, 103(11), 3999–4004. +[^2]: Shinar, G., Dekel, E., Tlusty, T., & Alon, U. (2006). Rules for biological regulation based on error minimization. Proceedings of the National Academy of Sciences, 103(11), 3999–4004. -[^3] Gerland, U., & Hwa, T. (2009). Evolutionary selection between alternative modes of gene regulation. Proceedings of the National Academy of Sciences, 106(22), 8841–8846. - -
\ No newline at end of file +[^3]: Gerland, U., & Hwa, T. (2009). Evolutionary selection between alternative modes of gene regulation. Proceedings of the National Academy of Sciences, 106(22), 8841–8846. diff --git a/pages/activators.md b/views/pages/activators.md similarity index 100% rename from pages/activators.md rename to views/pages/activators.md diff --git a/pages/concepts.md b/views/pages/concepts.md similarity index 95% rename from pages/concepts.md rename to views/pages/concepts.md index b28e0bb..450de0d 100644 --- a/pages/concepts.md +++ b/views/pages/concepts.md @@ -1,5 +1,3 @@ - - # Concepts of Biocircuits Before we start designing circuits, we need to talk about **natural** (evolved) circuits and **synthetic** circuits. diff --git a/pages/hill-functions.md b/views/pages/hill-functions.md similarity index 100% rename from pages/hill-functions.md rename to views/pages/hill-functions.md diff --git a/views/pages/index.rb b/views/pages/index.rb new file mode 100644 index 0000000..ac9f30c --- /dev/null +++ b/views/pages/index.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module BC + module Views + module Pages + class Index < ::Phlex::HTML + def sections = { + "1. Concepts of Biocircuits" => "/concepts.html", + "2. The Simplest Circuit" => "/simplest-circuit.html", + "3. Repressors & Leaks" => "/repressors.html", + "4. Activators" => "/activators.html", + "5. Ultrasensitivity & the Hill Function" => "/hill-functions.html", + "6. Choosing Between Activators & Repressors" => "/activators-vs-repressors.html" + } + + def view_template + render(::BC::Views::BaseLayout.new("Home")) do + section do + h1 class: "welcome" do + img src: "/assets/biocircuitslogo.svg", alt: "Biological Circuits" + end + + p(class: "tagline") { "for mere mortals" } + p(class: "tagline") { "(albeit ones who know a bit of differential calculus)" } + + p do + strong do + span { "DISCLAIMER: This is a school project. I would like to think that the CalTech course I've drawn from has made me somewhat knowledgeable on this topic, but please do not use this for medical advice, etc., etc. If you happen to know what you are doing, and you find a mistake on this website, please " } + a(href: "https://github.com/aleksrutins/biocircuits/issues/new") { "tell me about it." } + span { " With that said:" } + end + end + + unsafe_raw( +< + Biological circuit design is the science of abstracting natural biological processes by defining them + as you would any synthetic circuit. It also allows us to create our own circuits out of natural components. + As CalTech's open-source Biocircuits course states: +

+ +
+ Indeed, the marvelous progression of electronic circuit capabilities [...] could well describe biological circuits decades from now. Like electronics, we may will soon be able to program cellular “miracle devices” to create “little gadgets” that address serious environmental and medical applications. +
+ +

That CalTech course will be the main source for this presentation. All diagrams are from it.

+ +

Let's dive in!

+EOF + ) + + div class: "fade fade5" do + sections.each { |title, link| + render(SectionLink.new(link)) { title } + } + div class: "under-construction" do + "More Sections To Come" + end + end + + script { + unsafe_raw(" + addEventListener('DOMContentLoaded', () => { + if(localStorage.getItem('faded')) + document.querySelectorAll('.fade').forEach(it => + it.classList.add('no-delay')); + localStorage.setItem('faded', true); + }); + ") + } + end + end + end + end + end + end +end diff --git a/views/pages/markdown_page.rb b/views/pages/markdown_page.rb new file mode 100644 index 0000000..5b4b4b3 --- /dev/null +++ b/views/pages/markdown_page.rb @@ -0,0 +1,20 @@ +module BC + module Views + module Pages + class MarkdownPage < ::Phlex::HTML + def initialize(content, title, prev, fwd) + @content = content + @title = title + @prev = prev + @fwd = fwd + end + + def view_template + render PageLayout.new(@title, @prev, @fwd) do + unsafe_raw Kramdown::Document.new(@content).to_html + end + end + end + end + end +end diff --git a/pages/repressors.md b/views/pages/repressors.md similarity index 100% rename from pages/repressors.md rename to views/pages/repressors.md diff --git a/pages/simplest-circuit.md b/views/pages/simplest-circuit.md similarity index 99% rename from pages/simplest-circuit.md rename to views/pages/simplest-circuit.md index 7a427a5..a2f6baf 100644 --- a/pages/simplest-circuit.md +++ b/views/pages/simplest-circuit.md @@ -21,8 +21,10 @@ However, in real life, proteins aren't just made forever; they're also reduced, There's a differential equation for this: $$ \frac{dx}{dt} = \text{production} - (\text{degradation} + \text{dilution}) $$ + Or: $$ \frac{dx}{dt} = \beta - \gamma x $$ + Since \\(\gamma\\) counts both degradation and dilution, we can say that: $$ \gamma = \gamma_\text{degradation} + \gamma_\text{dilution} $$ @@ -31,8 +33,11 @@ Since we're getting into the math, a quick tip: if you (like me) forget what a v To find the net production of the protein under steady state conditions, set the derivative to zero and solve for \\(x\\): $$0 = \beta - \gamma x$$ + $$-\beta = -\gamma x$$ + $$\frac{-\beta}{-\gamma} = x$$ + $$\frac\beta\gamma = x$$ And we find that **steady-state protein concentration is proportional to the ratio of production and removal rates**. This is another core concept that should be built as intuition. @@ -65,11 +70,13 @@ Right now, we have protein synthesis as one process — no intermediate step The reaction can now be described by two coupled differential equations: $$\frac{dm}{dt} = \beta_m - \gamma_mm$$ + $$\frac{dx}{dt} = \beta_pm - \gamma_px$$ Now, to find steady-state mRNA and protein concentrations, we set both derivatives to zero and solve, giving us: $$m_{ss}=\frac{\beta_m}{\gamma_m}$$ + $$x_{ss}=\frac{\beta_pm_{ss}}{\gamma_p}=\frac{\beta_p\beta_m}{\gamma_p\gamma_m}$$ This tells us that steady-state protein concentration, when we consider transcription and translation as separate steps, is proportional to the product of the two synthesis rates and inversely proportional to the product of the two degradation rates. Again, if you think about it, that's pretty intuitive. diff --git a/views/section_link.rb b/views/section_link.rb new file mode 100644 index 0000000..532cce1 --- /dev/null +++ b/views/section_link.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module BC + module Views + class ChevronRightIcon < Phlex::SVG + def view_template + svg xmlns: 'http://www.w3.org/2000/svg', height: 24, width: 24, fill: "none", viewBox: "0 0 24 24", stroke_width: 1.5, stroke: "currentColor", class: "size-6" do + path font_weight: "bold", stroke_linecap: "round", stroke_linejoin: "round", d: "m8.25 4.5 7.5 7.5-7.5 7.5" + end + end + end + + class SectionLink < Phlex::HTML + def initialize(href) + @href = href + end + + def view_template + a href: @href, class: "section-link" do + span do + yield + end + + render ChevronRightIcon.new + end + end + end + end +end