diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87174b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/public/ diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..a89dd94 --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,188 @@ +:root { + --color-white: #FFFFFF; + --color-gray: #D9D9D9; + --color-brown: #D29E79; + --color-black: #3E3E3E; + --arrow: "→ "; + --gap-s: 0.9rem; + --gap-m: 1rem; + --gap-l: 1.5rem; + --gap-xl: 2rem; + --gap-xxl: 3rem; +} + +body { + font-family: 'Open Sans', sans-serif; + background-color: var(--color-black); + color: var(--color-white); + line-height: 1.5; + scroll-behavior: smooth; +} + +/* Components */ + +.container { + margin-inline: auto; + max-width: 1000px; + padding: 1rem; +} + +.container--full { + max-width: 100%; +} + +.text-center { + text-align: center; +} + +.link { + display: inline-block; + color: var(--color-brown); + text-decoration: none; + padding-block: .3rem; +} + +.link:hover { + text-decoration: underline; +} + +.title { + font-weight: normal; + text-decoration: underline; + text-decoration-color: var(--color-brown); + text-decoration-thickness: 2px; + text-underline-offset: .2rem; +} + +.list { + list-style-type: var(--arrow); +} + +.nav-main__list { + grid-gap: 1rem; +} + +.image { + display: block; + width: 100%; + object-fit: cover; + object-position: center; +} + +.button { + display: inline-block; + min-width: 4rem; + font-weight: bold; + box-sizing: border-box; + text-align: center; + padding: .5rem .8rem; + border: 2px solid var(--color-brown); + color: var(--color-gray); + text-decoration: none; + border-radius: .6rem; +} + +.button:hover { + border-color: var(--color-brown); + box-shadow: 0 5px 0 var(--color-brown); +} + +.nav__list { + display: flex; + flex-wrap: wrap; + list-style: none; + padding: 0; +} + +.code__block { + background-color: var(--color-gray); + color: var(--color-black); + padding: 1rem; + border-radius: .5rem; + font-family: 'Fira Code', monospace; + overflow-x: auto; +} + +.code__line { + color: var(--color-brown); + font-family: 'Fira Code', monospace; +} + +.details { + margin-block: 1rem; + border: 2px solid var(--color-brown); +} + + +.details__title { + border-bottom: 2px solid var(--color-brown); +} + +.details__summary { + background-color: var(--color-brown); + color: var(--color-white); + padding: 1rem; + list-style-type: "🐱 "; +} + + +.details[open] > .details__summary { + list-style-type: "😺 "; +} + +.details__content { + padding: 1rem; +} + +/* Hero */ + +.hero__hgroup { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: 1fr auto 1fr; + grid-template-areas: + "title image" + "subtitle image" + "nav image"; + grid-gap: 1rem; +} + +@media (width < 600px) { + .hero__hgroup { + grid-template-columns: 1fr; + grid-template-rows: repeat(3, auto); + grid-template-areas: + "title" + "image" + "subtitle" + "nav"; + } +} + +.hero__logo { + grid-area: image; +} + +.hero__title { + grid-area: title; + align-self: end; +} + +.hero__subtitle { + grid-area: subtitle; +} + +.nav-docs { + grid-area: nav; +} + +/* Home */ +.nav-home__list { + justify-content: center; + gap: var(--gap-l); +} + +/* Footer */ +.footer { + text-align: center; +} diff --git a/assets/img/favicon.png b/assets/img/favicon.png new file mode 100644 index 0000000..0338dae Binary files /dev/null and b/assets/img/favicon.png differ diff --git a/assets/img/minimal-template.webp b/assets/img/minimal-template.webp new file mode 100644 index 0000000..e17514d Binary files /dev/null and b/assets/img/minimal-template.webp differ diff --git a/assets/img/og-image.webp b/assets/img/og-image.webp new file mode 100644 index 0000000..7d4162b Binary files /dev/null and b/assets/img/og-image.webp differ diff --git a/assets/img/pet.webp b/assets/img/pet.webp new file mode 100644 index 0000000..97c8be3 Binary files /dev/null and b/assets/img/pet.webp differ diff --git a/one.org b/one.org index e8c0416..d0bb86d 100644 --- a/one.org +++ b/one.org @@ -1,11 +1,30 @@ * Home :PROPERTIES: -:ONE: one-custom-default +:ONE: one-custom-default-home :CUSTOM_ID: / +:TITLE: +:DESCRIPTION: Framework for creating Realtime SPAs using HTML over the Wire technology. :END: -Soy un ejemplo de web. +* Get started +:PROPERTIES: +:ONE: one-custom-default-doc +:CUSTOM_ID: /docs/get-started/ +:END: -#+BEGIN_SRC emacs-lisp -(message "foo bar baz") -#+END_SRC +** What is Django LiveView? + + +Django LiveView is a framework for creating Realtime SPAs using HTML over the Wire technology. It is inspired by Phoenix LiveView and it is built on top of Django Channels. + +It allows you to create interactive web applications using only HTML, CSS and Python. JavaScript ONLY is used to capture events, send and receive strings over a WebSockets channel. + +** What are your superpowers? + +- Create SPAs without using APIs. +- Uses Django's template system to render the frontend (Without JavaScript). +- The logic is not split between the backend and the frontend, it all stays in Python. +- You can still use all of Django's native tools, such as its ORM, forms, plugins, etc. +- Everything is asynchronous by default. +- Don't learn anything new. If you know Python, you know how to use Django LiveView. +- All in real time. diff --git a/onerc.el b/onerc.el index 9f2e252..7136310 100644 --- a/onerc.el +++ b/onerc.el @@ -1,23 +1,82 @@ -(defun one-custom-default (page-tree pages _global) - "Default render function. - -See `one-is-page', `one-render-pages' and `one-default-css'." - (let* ((title (org-element-property :raw-value page-tree)) - (path (org-element-property :CUSTOM_ID page-tree)) +(defun one-custom-default-home (page-tree pages _global) + "Default render function by home page." + (let* ((title (org-element-property :TITLE page-tree)) + (full-title (concat (when (not (string-empty-p title)) (concat title " | ")) "Django LiveView")) + (path (org-element-property :CUSTOM_ID page-tree)) + (description (org-element-property :DESCRIPTION page-tree)) (content (org-export-data-with-backend (org-element-contents page-tree) 'one-ox nil)) (website-name (one-default-website-name pages)) (nav (one-default-nav path pages))) + (jack-html "" - `(:html - (:head - (:meta (@ :charset "utf-8")) - (:meta (@ :name "viewport" :content "width=device-width,initial-scale=1")) - (:link (@ :rel "stylesheet" :type "text/css" :href "https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css")) - (:link (@ :rel "stylesheet" :type "text/css" :href "/one.css")) - (:title ,title)) - (:body - (:main.main - ,content)))))) + `(:html (@ :lang "en") + (:head + ;; Generals + (:meta (@ :charset "utf-8")) + (:link (@ :rel "icon" :type "image/png" :href "img/favicon.png")) + (:meta (@ :name "viewport" :content "width=device-width,initial-scale=1.0, shrink-to-fit=no")) + (:meta (@ :name "author" :content "Andros Fenollosa")) + ;; SEO + (:title ,full-title) + (:meta (@ :name "description" :content ,description)) + (:meta (@ :name "og:image" :content "https://django-liveview.andros.dev/img/og-image.webp")) + ;; Fonts + (:link (@ :rel "preconnect" :href "https://fonts.googleapis.com")) + (:link (@ :rel "preconnect" :href "https://fonts.gstatic.com" :crossorigin t)) + (:link (@ :rel "stylesheet" :href "https://fonts.googleapis.com/css2?family=Fira+Code&family=Open+Sans:wght@400;700&display=swap")) + ;; CSS + (:link (@ :rel "stylesheet" :type "text/css" :href "https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css")) + (:link (@ :rel "stylesheet" :type "text/css" :href "css/main.css"))) + (:body + (:section.hero + (:div.container + (:hgroup.hero__hgroup + (:h1.hero__title "Django LiveView") + (:h2.hero__subtitle "Framework for creating Realtime SPAs using HTML over the Wire technology") + (:img.image.hero__logo (@ :alt "pet" :src "img/pet.webp"))))) + (:main.main + (:nav.nav-home + (:ul.nav__list.nav-home__list + (:li.nav-home__item + (:a.button.nav-home__link (@ :href "/docs/get-started/") "Get started")) + (:li.nav-home__item + (:a.button.nav-home__link (@ :href "/docs/install/") "Install")) + (:li.nav-home__item + (:a.button.nav-home__link (@ :href "https://django-liveview-demo.andros.dev/" :target "_blank") "Demo")))))))))) + +(defun one-custom-default-doc (page-tree pages _global) + "Default render function by home page." + (let* ((title (org-element-property :raw-value page-tree)) + (path (org-element-property :CUSTOM_ID page-tree)) + (content (org-export-data-with-backend + (org-element-contents page-tree) + 'one-ox nil)) + (website-name (one-default-website-name pages)) + (nav (one-default-nav path pages))) + + (jack-html + "" + `(:html (@ :lang "en") + (:head + ;; Generals + (:meta (@ :charset "utf-8")) + (:link (@ :rel "icon" :type "image/png" :href "img/favicon.png")) + (:meta (@ :name "viewport" :content "width=device-width,initial-scale=1.0, shrink-to-fit=no")) + (:meta (@ :name "author" :content "Andros Fenollosa")) + ;; SEO + (:title (concat ,title " | Django LiveView")) + (:meta (@ :name "description" :content "Framework for creating Realtime SPAs using HTML over the Wire technology.")) + (:meta (@ :name "og:image" :content "https://django-liveview.andros.dev/img/og-image.webp")) + ;; Fonts + (:link (@ :rel "preconnect" :href "https://fonts.googleapis.com")) + (:link (@ :rel "preconnect" :href "https://fonts.gstatic.com" :crossorigin t)) + (:link (@ :rel "stylesheet" :href "https://fonts.googleapis.com/css2?family=Fira+Code&family=Open+Sans:wght@400;700&display=swap")) + ;; CSS + (:link (@ :rel "stylesheet" :type "text/css" :href "https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css")) + (:link (@ :rel "stylesheet" :type "text/css" :href "css/main.css"))) + (:body + (:main.main + (:div.container .content)))))))