diff --git a/assets/css/app.css b/assets/css/app.css index d10000e1a..0a807a65a 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -1,204 +1,12 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss/base"; +@import "tailwindcss/components"; +@import "tailwindcss/utilities"; -@import "../node_modules/nprogress/nprogress.css"; +@import "nprogress/nprogress.css"; + +@import "./global.css"; +@import "./components.css"; +@import "./utilities.css"; @import "./live_view.css"; - -/* Remove the default outline on focused elements */ -:focus, -button:focus { - outline: none; -} - -/* Hide Phoenix live reload frame */ -iframe[hidden] { - display: none; -} - -/* Markdown rendered content */ - -.markdown { - @apply text-gray-700; -} - -.markdown h1 { - @apply text-gray-900 font-semibold text-3xl my-4; -} - -.markdown h2 { - @apply text-gray-900 font-semibold text-2xl my-4; -} - -.markdown h3 { - @apply text-gray-900 font-semibold text-xl my-4; -} - -.markdown p { - @apply my-4; -} - -.markdown ul { - @apply list-disc list-inside my-4; -} - -.markdown ol { - @apply list-decimal list-inside my-4; -} - -.markdown ul > li, -.markdown ol > li { - @apply my-1; -} - -.markdown ul > li ul, -.markdown ol > li ol { - @apply ml-6; -} - -.markdown blockquote { - @apply border-l-4 border-gray-200 pl-4 py-2 my-4 text-gray-500; -} - -.markdown a { - @apply font-medium underline text-gray-900 hover:no-underline; -} - -.markdown table { - @apply w-full my-4; -} - -.markdown table thead tr { - @apply border-b border-gray-200; -} - -.markdown table tbody tr:not(:last-child) { - @apply border-b border-gray-200; -} - -.markdown table th { - @apply p-2 font-bold; -} - -.markdown table td { - @apply p-2; -} - -.markdown table th:first-child, -.markdown table td:first-child { - @apply pl-0; -} - -.markdown table th:last-child, -.markdown table td:last-child { - @apply pr-0; -} - -.markdown code { - @apply py-1 px-2 rounded text-sm align-middle; - /* Match the editor colors */ - background-color: #282c34; - color: #abb2bf; -} - -.markdown pre > code { - @apply block p-4 rounded text-sm align-middle; - /* Match the editor colors */ - background-color: #282c34; - color: #abb2bf; -} - -.markdown :first-child { - @apply mt-0; -} - -.markdown :last-child { - @apply mb-0; -} - -/* Elixir HTML-ized inspect result */ - -.elixir-inspect .atom { - color: #61afef; -} - -.elixir-inspect .binary { - color: #5c6370; -} - -.elixir-inspect .boolean { - color: #c678dd; -} - -.elixir-inspect .list { - color: #5c6370; -} - -.elixir-inspect .map { - color: #5c6370; -} - -.elixir-inspect .nil { - color: #c678dd; -} - -.elixir-inspect .number { - color: #d19a66; -} - -.elixir-inspect .regex { - color: #e06c75; -} - -.elixir-inspect .string { - color: #98c379; -} - -.elixir-inspect .tuple { - color: #5c6370; -} - -/* Other */ - -.bg-editor { - background-color: #282c34; -} - -.font-editor { - font-family: "Droid Sans Mono", monospace, monospace, "Droid Sans Fallback"; - font-size: 14px; -} - -.tiny-scrollbar::-webkit-scrollbar { - width: 0.4rem; - height: 0.4rem; -} - -.tiny-scrollbar::-webkit-scrollbar-thumb { - border-radius: 0.25rem; - @apply bg-gray-400; -} - -.tiny-scrollbar::-webkit-scrollbar-track { - @apply bg-gray-100; -} - -.button-base { - @apply px-4 py-2 bg-white rounded-md border border-gray-300 font-medium text-gray-700 hover:bg-gray-50; -} - -.button-sm { - @apply px-3 py-1; -} - -.button-danger { - @apply border border-red-300 text-red-500 hover:bg-red-50; -} - -.button-primary { - @apply border-0 bg-purple-400 text-white hover:bg-purple-500; -} - -.input-base { - @apply w-full px-3 py-3 bg-white rounded-md placeholder-gray-400 text-gray-700; -} +@import "./markdown.css"; +@import "./elixir_inspect.css"; diff --git a/assets/css/components.css b/assets/css/components.css new file mode 100644 index 000000000..73356b4ae --- /dev/null +++ b/assets/css/components.css @@ -0,0 +1,39 @@ +/* Buttons */ + +.button-base { + @apply px-4 py-2 bg-white rounded-md border border-gray-300 font-medium text-gray-700 hover:bg-gray-50; +} + +.button-sm { + @apply px-3 py-1; +} + +.button-danger { + @apply border border-red-300 text-red-500 hover:bg-red-50; +} + +.button-primary { + @apply border-0 bg-purple-400 text-white hover:bg-purple-500; +} + +/* Form fields */ + +.input-base { + @apply w-full px-3 py-3 bg-white rounded-md placeholder-gray-400 text-gray-700; +} + +/* Custom scrollbars */ + +.tiny-scrollbar::-webkit-scrollbar { + width: 0.4rem; + height: 0.4rem; +} + +.tiny-scrollbar::-webkit-scrollbar-thumb { + border-radius: 0.25rem; + @apply bg-gray-400; +} + +.tiny-scrollbar::-webkit-scrollbar-track { + @apply bg-gray-100; +} diff --git a/assets/css/elixir_inspect.css b/assets/css/elixir_inspect.css new file mode 100644 index 000000000..188cb7e13 --- /dev/null +++ b/assets/css/elixir_inspect.css @@ -0,0 +1,41 @@ +/* Elixir HTML-ized inspect result */ + +.elixir-inspect .atom { + color: #61afef; +} + +.elixir-inspect .binary { + color: #5c6370; +} + +.elixir-inspect .boolean { + color: #c678dd; +} + +.elixir-inspect .list { + color: #5c6370; +} + +.elixir-inspect .map { + color: #5c6370; +} + +.elixir-inspect .nil { + color: #c678dd; +} + +.elixir-inspect .number { + color: #d19a66; +} + +.elixir-inspect .regex { + color: #e06c75; +} + +.elixir-inspect .string { + color: #98c379; +} + +.elixir-inspect .tuple { + color: #5c6370; +} diff --git a/assets/css/global.css b/assets/css/global.css new file mode 100644 index 000000000..50446d881 --- /dev/null +++ b/assets/css/global.css @@ -0,0 +1,5 @@ +/* Remove the default outline on focused elements */ +:focus, +button:focus { + outline: none; +} diff --git a/assets/css/live_view.css b/assets/css/live_view.css index f8321d9da..c22537aba 100644 --- a/assets/css/live_view.css +++ b/assets/css/live_view.css @@ -1,4 +1,9 @@ -/* LiveView specific classes for your customizations */ +/* Hide Phoenix live reload frame */ +iframe[hidden] { + display: none; +} + +/* LiveView specific classes */ .phx-no-feedback.invalid-feedback, .phx-no-feedback .invalid-feedback { @@ -13,75 +18,7 @@ .phx-disconnected { cursor: wait; } + .phx-disconnected * { pointer-events: none; } - -.phx-modal { - opacity: 1 !important; - position: fixed; - z-index: 1; - left: 0; - top: 0; - width: 100%; - height: 100%; - overflow: auto; - background-color: rgb(0, 0, 0); - background-color: rgba(0, 0, 0, 0.4); -} - -.phx-modal-content { - background-color: #fefefe; - margin: 15% auto; - padding: 20px; - border: 1px solid #888; - width: 80%; -} - -.phx-modal-close { - color: #aaa; - float: right; - font-size: 28px; - font-weight: bold; -} - -.phx-modal-close:hover, -.phx-modal-close:focus { - color: black; - text-decoration: none; - cursor: pointer; -} - -/* Alerts and form errors */ -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px; -} -.alert-info { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} -.alert-warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} -.alert-danger { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} -.alert p { - margin-bottom: 0; -} -.alert:empty { - display: none; -} -.invalid-feedback { - color: #a94442; - display: block; - margin: -1rem 0 2rem; -} diff --git a/assets/css/markdown.css b/assets/css/markdown.css new file mode 100644 index 000000000..bbaba8507 --- /dev/null +++ b/assets/css/markdown.css @@ -0,0 +1,99 @@ +/* Markdown rendered content */ + +.markdown { + @apply text-gray-700; +} + +.markdown h1 { + @apply text-gray-900 font-semibold text-3xl my-4; +} + +.markdown h2 { + @apply text-gray-900 font-semibold text-2xl my-4; +} + +.markdown h3 { + @apply text-gray-900 font-semibold text-xl my-4; +} + +.markdown p { + @apply my-4; +} + +.markdown ul { + @apply list-disc list-inside my-4; +} + +.markdown ol { + @apply list-decimal list-inside my-4; +} + +.markdown ul > li, +.markdown ol > li { + @apply my-1; +} + +.markdown ul > li ul, +.markdown ol > li ol { + @apply ml-6; +} + +.markdown blockquote { + @apply border-l-4 border-gray-200 pl-4 py-2 my-4 text-gray-500; +} + +.markdown a { + @apply font-medium underline text-gray-900 hover:no-underline; +} + +.markdown table { + @apply w-full my-4; +} + +.markdown table thead tr { + @apply border-b border-gray-200; +} + +.markdown table tbody tr:not(:last-child) { + @apply border-b border-gray-200; +} + +.markdown table th { + @apply p-2 font-bold; +} + +.markdown table td { + @apply p-2; +} + +.markdown table th:first-child, +.markdown table td:first-child { + @apply pl-0; +} + +.markdown table th:last-child, +.markdown table td:last-child { + @apply pr-0; +} + +.markdown code { + @apply py-1 px-2 rounded-md text-sm align-middle; + /* Match the editor colors */ + background-color: #282c34; + color: #abb2bf; +} + +.markdown pre > code { + @apply block p-4 rounded-md text-sm align-middle; + /* Match the editor colors */ + background-color: #282c34; + color: #abb2bf; +} + +.markdown :first-child { + @apply mt-0; +} + +.markdown :last-child { + @apply mb-0; +} diff --git a/assets/css/phoenix.css b/assets/css/phoenix.css deleted file mode 100644 index 69e004329..000000000 --- a/assets/css/phoenix.css +++ /dev/null @@ -1,633 +0,0 @@ -/* Includes some default style for the starter application. - * This can be safely deleted to start fresh. - */ - -/* Milligram v1.3.0 https://milligram.github.io - * Copyright (c) 2017 CJ Patoilo Licensed under the MIT license - */ - -*, -*:after, -*:before { - box-sizing: inherit; -} -html { - box-sizing: border-box; - font-size: 62.5%; -} -body { - color: #000000; - font-family: "Helvetica", "Arial", sans-serif; - font-size: 1.6em; - font-weight: 300; - line-height: 1.6; -} -blockquote { - border-left: 0.3rem solid #d1d1d1; - margin-left: 0; - margin-right: 0; - padding: 1rem 1.5rem; -} -blockquote *:last-child { - margin-bottom: 0; -} -.button, -button, -input[type="button"], -input[type="reset"], -input[type="submit"] { - background-color: #0069d9; - border: 0.1rem solid #0069d9; - border-radius: 0.4rem; - color: #fff; - cursor: pointer; - display: inline-block; - font-size: 1.1rem; - font-weight: 700; - height: 3.8rem; - letter-spacing: 0.1rem; - line-height: 3.8rem; - padding: 0 3rem; - text-align: center; - text-decoration: none; - text-transform: uppercase; - white-space: nowrap; -} -.button:focus, -.button:hover, -button:focus, -button:hover, -input[type="button"]:focus, -input[type="button"]:hover, -input[type="reset"]:focus, -input[type="reset"]:hover, -input[type="submit"]:focus, -input[type="submit"]:hover { - background-color: #606c76; - border-color: #606c76; - color: #fff; - outline: 0; -} -.button[disabled], -button[disabled], -input[type="button"][disabled], -input[type="reset"][disabled], -input[type="submit"][disabled] { - cursor: default; - opacity: 0.5; -} -.button[disabled]:focus, -.button[disabled]:hover, -button[disabled]:focus, -button[disabled]:hover, -input[type="button"][disabled]:focus, -input[type="button"][disabled]:hover, -input[type="reset"][disabled]:focus, -input[type="reset"][disabled]:hover, -input[type="submit"][disabled]:focus, -input[type="submit"][disabled]:hover { - background-color: #0069d9; - border-color: #0069d9; -} -.button.button-outline, -button.button-outline, -input[type="button"].button-outline, -input[type="reset"].button-outline, -input[type="submit"].button-outline { - background-color: transparent; - color: #0069d9; -} -.button.button-outline:focus, -.button.button-outline:hover, -button.button-outline:focus, -button.button-outline:hover, -input[type="button"].button-outline:focus, -input[type="button"].button-outline:hover, -input[type="reset"].button-outline:focus, -input[type="reset"].button-outline:hover, -input[type="submit"].button-outline:focus, -input[type="submit"].button-outline:hover { - background-color: transparent; - border-color: #606c76; - color: #606c76; -} -.button.button-outline[disabled]:focus, -.button.button-outline[disabled]:hover, -button.button-outline[disabled]:focus, -button.button-outline[disabled]:hover, -input[type="button"].button-outline[disabled]:focus, -input[type="button"].button-outline[disabled]:hover, -input[type="reset"].button-outline[disabled]:focus, -input[type="reset"].button-outline[disabled]:hover, -input[type="submit"].button-outline[disabled]:focus, -input[type="submit"].button-outline[disabled]:hover { - border-color: inherit; - color: #0069d9; -} -.button.button-clear, -button.button-clear, -input[type="button"].button-clear, -input[type="reset"].button-clear, -input[type="submit"].button-clear { - background-color: transparent; - border-color: transparent; - color: #0069d9; -} -.button.button-clear:focus, -.button.button-clear:hover, -button.button-clear:focus, -button.button-clear:hover, -input[type="button"].button-clear:focus, -input[type="button"].button-clear:hover, -input[type="reset"].button-clear:focus, -input[type="reset"].button-clear:hover, -input[type="submit"].button-clear:focus, -input[type="submit"].button-clear:hover { - background-color: transparent; - border-color: transparent; - color: #606c76; -} -.button.button-clear[disabled]:focus, -.button.button-clear[disabled]:hover, -button.button-clear[disabled]:focus, -button.button-clear[disabled]:hover, -input[type="button"].button-clear[disabled]:focus, -input[type="button"].button-clear[disabled]:hover, -input[type="reset"].button-clear[disabled]:focus, -input[type="reset"].button-clear[disabled]:hover, -input[type="submit"].button-clear[disabled]:focus, -input[type="submit"].button-clear[disabled]:hover { - color: #0069d9; -} -code { - background: #f4f5f6; - border-radius: 0.4rem; - font-size: 86%; - margin: 0 0.2rem; - padding: 0.2rem 0.5rem; - white-space: nowrap; -} -pre { - background: #f4f5f6; - border-left: 0.3rem solid #0069d9; - overflow-y: hidden; -} -pre > code { - border-radius: 0; - display: block; - padding: 1rem 1.5rem; - white-space: pre; -} -hr { - border: 0; - border-top: 0.1rem solid #f4f5f6; - margin: 3rem 0; -} -input[type="email"], -input[type="number"], -input[type="password"], -input[type="search"], -input[type="tel"], -input[type="text"], -input[type="url"], -textarea, -select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: transparent; - border: 0.1rem solid #d1d1d1; - border-radius: 0.4rem; - box-shadow: none; - box-sizing: inherit; - height: 3.8rem; - padding: 0.6rem 1rem; - width: 100%; -} -input[type="email"]:focus, -input[type="number"]:focus, -input[type="password"]:focus, -input[type="search"]:focus, -input[type="tel"]:focus, -input[type="text"]:focus, -input[type="url"]:focus, -textarea:focus, -select:focus { - border-color: #0069d9; - outline: 0; -} -select { - background: url('data:image/svg+xml;utf8,') - center right no-repeat; - padding-right: 3rem; -} -select:focus { - background-image: url('data:image/svg+xml;utf8,'); -} -textarea { - min-height: 6.5rem; -} -label, -legend { - display: block; - font-size: 1.6rem; - font-weight: 700; - margin-bottom: 0.5rem; -} -fieldset { - border-width: 0; - padding: 0; -} -input[type="checkbox"], -input[type="radio"] { - display: inline; -} -.label-inline { - display: inline-block; - font-weight: normal; - margin-left: 0.5rem; -} -.row { - display: flex; - flex-direction: column; - padding: 0; - width: 100%; -} -.row.row-no-padding { - padding: 0; -} -.row.row-no-padding > .column { - padding: 0; -} -.row.row-wrap { - flex-wrap: wrap; -} -.row.row-top { - align-items: flex-start; -} -.row.row-bottom { - align-items: flex-end; -} -.row.row-center { - align-items: center; -} -.row.row-stretch { - align-items: stretch; -} -.row.row-baseline { - align-items: baseline; -} -.row .column { - display: block; - flex: 1 1 auto; - margin-left: 0; - max-width: 100%; - width: 100%; -} -.row .column.column-offset-10 { - margin-left: 10%; -} -.row .column.column-offset-20 { - margin-left: 20%; -} -.row .column.column-offset-25 { - margin-left: 25%; -} -.row .column.column-offset-33, -.row .column.column-offset-34 { - margin-left: 33.3333%; -} -.row .column.column-offset-50 { - margin-left: 50%; -} -.row .column.column-offset-66, -.row .column.column-offset-67 { - margin-left: 66.6666%; -} -.row .column.column-offset-75 { - margin-left: 75%; -} -.row .column.column-offset-80 { - margin-left: 80%; -} -.row .column.column-offset-90 { - margin-left: 90%; -} -.row .column.column-10 { - flex: 0 0 10%; - max-width: 10%; -} -.row .column.column-20 { - flex: 0 0 20%; - max-width: 20%; -} -.row .column.column-25 { - flex: 0 0 25%; - max-width: 25%; -} -.row .column.column-33, -.row .column.column-34 { - flex: 0 0 33.3333%; - max-width: 33.3333%; -} -.row .column.column-40 { - flex: 0 0 40%; - max-width: 40%; -} -.row .column.column-50 { - flex: 0 0 50%; - max-width: 50%; -} -.row .column.column-60 { - flex: 0 0 60%; - max-width: 60%; -} -.row .column.column-66, -.row .column.column-67 { - flex: 0 0 66.6666%; - max-width: 66.6666%; -} -.row .column.column-75 { - flex: 0 0 75%; - max-width: 75%; -} -.row .column.column-80 { - flex: 0 0 80%; - max-width: 80%; -} -.row .column.column-90 { - flex: 0 0 90%; - max-width: 90%; -} -.row .column .column-top { - align-self: flex-start; -} -.row .column .column-bottom { - align-self: flex-end; -} -.row .column .column-center { - -ms-grid-row-align: center; - align-self: center; -} -@media (min-width: 40rem) { - .row { - flex-direction: row; - margin-left: -1rem; - width: calc(100% + 2rem); - } - .row .column { - margin-bottom: inherit; - padding: 0 1rem; - } -} -a { - color: #0069d9; - text-decoration: none; -} -a:focus, -a:hover { - color: #606c76; -} -dl, -ol, -ul { - list-style: none; - margin-top: 0; - padding-left: 0; -} -dl dl, -dl ol, -dl ul, -ol dl, -ol ol, -ol ul, -ul dl, -ul ol, -ul ul { - font-size: 90%; - margin: 1.5rem 0 1.5rem 3rem; -} -ol { - list-style: decimal inside; -} -ul { - list-style: circle inside; -} -.button, -button, -dd, -dt, -li { - margin-bottom: 1rem; -} -fieldset, -input, -select, -textarea { - margin-bottom: 1.5rem; -} -blockquote, -dl, -figure, -form, -ol, -p, -pre, -table, -ul { - margin-bottom: 2.5rem; -} -table { - border-spacing: 0; - width: 100%; -} -td, -th { - border-bottom: 0.1rem solid #e1e1e1; - padding: 1.2rem 1.5rem; - text-align: left; -} -td:first-child, -th:first-child { - padding-left: 0; -} -td:last-child, -th:last-child { - padding-right: 0; -} -b, -strong { - font-weight: bold; -} -p { - margin-top: 0; -} -h1, -h2, -h3, -h4, -h5, -h6 { - font-weight: 300; - letter-spacing: -0.1rem; - margin-bottom: 2rem; - margin-top: 0; -} -h1 { - font-size: 4.6rem; - line-height: 1.2; -} -h2 { - font-size: 3.6rem; - line-height: 1.25; -} -h3 { - font-size: 2.8rem; - line-height: 1.3; -} -h4 { - font-size: 2.2rem; - letter-spacing: -0.08rem; - line-height: 1.35; -} -h5 { - font-size: 1.8rem; - letter-spacing: -0.05rem; - line-height: 1.5; -} -h6 { - font-size: 1.6rem; - letter-spacing: 0; - line-height: 1.4; -} -img { - max-width: 100%; -} -.clearfix:after { - clear: both; - content: " "; - display: table; -} -.float-left { - float: left; -} -.float-right { - float: right; -} - -/* General style */ -h1 { - font-size: 3.6rem; - line-height: 1.25; -} -h2 { - font-size: 2.8rem; - line-height: 1.3; -} -h3 { - font-size: 2.2rem; - letter-spacing: -0.08rem; - line-height: 1.35; -} -h4 { - font-size: 1.8rem; - letter-spacing: -0.05rem; - line-height: 1.5; -} -h5 { - font-size: 1.6rem; - letter-spacing: 0; - line-height: 1.4; -} -h6 { - font-size: 1.4rem; - letter-spacing: 0; - line-height: 1.2; -} -pre { - padding: 1em; -} - -.container { - margin: 0 auto; - max-width: 80rem; - padding: 0 2rem; - position: relative; - width: 100%; -} -select { - width: auto; -} - -/* Phoenix promo and logo */ -.phx-hero { - text-align: center; - border-bottom: 1px solid #e3e3e3; - background: #eee; - border-radius: 6px; - padding: 3em 3em 1em; - margin-bottom: 3rem; - font-weight: 200; - font-size: 120%; -} -.phx-hero input { - background: #ffffff; -} -.phx-logo { - min-width: 300px; - margin: 1rem; - display: block; -} -.phx-logo img { - width: auto; - display: block; -} - -/* Headers */ -header { - width: 100%; - background: #fdfdfd; - border-bottom: 1px solid #eaeaea; - margin-bottom: 2rem; -} -header section { - align-items: center; - display: flex; - flex-direction: column; - justify-content: space-between; -} -header section :first-child { - order: 2; -} -header section :last-child { - order: 1; -} -header nav ul, -header nav li { - margin: 0; - padding: 0; - display: block; - text-align: right; - white-space: nowrap; -} -header nav ul { - margin: 1rem; - margin-top: 0; -} -header nav a { - display: block; -} - -@media (min-width: 40rem) { - /* Small devices (landscape phones, 576px and up) */ - header section { - flex-direction: row; - } - header nav ul { - margin: 1rem; - } - .phx-logo { - flex-basis: 527px; - margin: 2rem 1rem; - } -} diff --git a/assets/css/utilities.css b/assets/css/utilities.css new file mode 100644 index 000000000..2508024da --- /dev/null +++ b/assets/css/utilities.css @@ -0,0 +1,10 @@ +/* A set of reusable classes */ + +.bg-editor { + background-color: #282c34; +} + +.font-editor { + font-family: "Droid Sans Mono", monospace, monospace, "Droid Sans Fallback"; + font-size: 14px; +} diff --git a/assets/js/editor/index.js b/assets/js/editor/index.js deleted file mode 100644 index 32ae2d87f..000000000 --- a/assets/js/editor/index.js +++ /dev/null @@ -1,135 +0,0 @@ -import monaco from "../cell/live_editor/monaco"; -import EditorClient from "../cell/live_editor/editor_client"; -import MonacoEditorAdapter from "../cell/live_editor/monaco_editor_adapter"; -import HookServerAdapter from "./hook_server_adapter"; -import { - getAttributeOrThrow, - parseBoolean, - parseInteger, -} from "../lib/attribute"; - -/** - * A hook managing an editable cell. - * - * Mounts a Monaco Editor and provides real-time collaboration mechanism - * by sending all changes as `Delta` objects to the server - * and handling such objects sent by other clients. - * - * Configuration: - * - * * `data-cell-id` - id of the cell being edited - * * `data-type` - editor type (i.e. language), either "markdown" or "elixir" is expected - * * `data-hidden` - whether this editor is currently hidden - * * `data-active` - whether this editor is currently the active one - * - * Additionally the root element should have a direct `div` child - * with `data-source` and `data-revision` providing the initial values. - */ -const Editor = { - mounted() { - this.props = getProps(this); - - this.editorContainer = this.el.querySelector("div"); - - if (!this.editorContainer) { - throw new Error("Editor Hook root element should have a div child"); - } - - // Remove the content placeholder - this.editorContainer.firstElementChild.remove(); - - this.__mountEditor(); - - const source = getAttributeOrThrow(this.editorContainer, "data-source"); - const revision = getAttributeOrThrow( - this.editorContainer, - "data-revision", - parseInteger - ); - - this.editor.getModel().setValue(source); - - new EditorClient( - new HookServerAdapter(this, this.props.cellId), - new MonacoEditorAdapter(this.editor), - revision - ); - }, - - updated() { - const prevProps = this.props; - this.props = getProps(this); - - if (prevProps.isHidden && !this.props.isHidden) { - // If the editor was created as hidden it didn't get the chance - // to properly adjust to the available space, so trigger it now. - this.__adjustEditorLayout(); - } - - if (!prevProps.isActive && this.props.isActive) { - this.editor.focus(); - } - - if (prevProps.isActive && !this.props.isActive) { - if (this.editor.hasTextFocus()) { - document.activeElement.blur(); - } - } - }, - - __mountEditor() { - this.editor = monaco.editor.create(this.editorContainer, { - language: this.props.type, - value: "", - scrollbar: { - vertical: "hidden", - handleMouseWheel: false, - }, - minimap: { - enabled: false, - }, - overviewRulerLanes: 0, - scrollBeyondLastLine: false, - quickSuggestions: false, - renderIndentGuides: false, - occurrencesHighlight: false, - renderLineHighlight: "none", - theme: "custom", - }); - - this.editor.getModel().updateOptions({ - tabSize: 2, - }); - - this.editor.updateOptions({ - autoIndent: true, - tabSize: 2, - formatOnType: true, - }); - - this.editor.onDidContentSizeChange(() => this.__adjustEditorLayout()); - this.__adjustEditorLayout(); - - window.addEventListener("resize", (event) => { - this.editor.layout(); - }); - }, - - __adjustEditorLayout() { - // Dynamically adjust editor height to the content, see https://github.com/microsoft/monaco-editor/issues/794 - const contentHeight = this.editor.getContentHeight(); - this.editorContainer.style.height = `${contentHeight}px`; - this.editor.layout(); - }, -}; - -function getProps(hook) { - return { - cellId: getAttributeOrThrow(hook.el, "data-cell-id"), - type: getAttributeOrThrow(hook.el, "data-type"), - isHidden: getAttributeOrThrow(hook.el, "data-hidden", parseBoolean), - isActive: getAttributeOrThrow(hook.el, "data-active", parseBoolean), - }; -} - -export default Editor; diff --git a/assets/package-lock.json b/assets/package-lock.json index 00068c3cf..f63e32765 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -9256,6 +9256,17 @@ } } }, + "postcss-import": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.0.0.tgz", + "integrity": "sha512-gFDDzXhqr9ELmnLHgCC3TbGfA6Dm/YMb/UN8/f7Uuq4fL7VTk2vOIj6hwINEwbokEmp123bLD7a5m+E+KIetRg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, "postcss-js": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz", @@ -10711,6 +10722,23 @@ "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", "dev": true }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", diff --git a/assets/package.json b/assets/package.json index c24d8d44e..08497ae82 100644 --- a/assets/package.json +++ b/assets/package.json @@ -31,6 +31,7 @@ "monaco-editor-webpack-plugin": "^2.1.0", "optimize-css-assets-webpack-plugin": "^5.0.1", "postcss": "^8.2.3", + "postcss-import": "^14.0.0", "postcss-loader": "^4.1.0", "prettier": "^2.2.1", "tailwindcss": "^2.0.2", diff --git a/assets/postcss.config.js b/assets/postcss.config.js index ae2a7495b..fb51b3e3b 100644 --- a/assets/postcss.config.js +++ b/assets/postcss.config.js @@ -1,5 +1,6 @@ module.exports = { plugins: [ + require('postcss-import'), require('tailwindcss'), require('autoprefixer'), ] diff --git a/lib/live_book_web/live/cell.ex b/lib/live_book_web/live/cell_component.ex similarity index 87% rename from lib/live_book_web/live/cell.ex rename to lib/live_book_web/live/cell_component.ex index a9d3ec409..04785d517 100644 --- a/lib/live_book_web/live/cell.ex +++ b/lib/live_book_web/live/cell_component.ex @@ -1,15 +1,15 @@ -defmodule LiveBookWeb.Cell do +defmodule LiveBookWeb.CellComponent do use LiveBookWeb, :live_component def render(assigns) do ~L""" -
"> +
" + id="cell-<%= @cell.id %>" + phx-hook="Cell" + data-cell-id="<%= @cell.id %>" + data-type="<%= @cell.type %>" + data-focused="<%= @focused %>" + data-expanded="<%= @expanded %>"> <%= render_cell_content(assigns) %>
""" @@ -64,9 +64,10 @@ defmodule LiveBookWeb.Cell do ~L"""
-
+
<%= render_editor_content_placeholder(@cell.source) %>
@@ -97,9 +98,9 @@ defmodule LiveBookWeb.Cell do ~L"""
-
-
-
+
+
+
""" @@ -119,9 +120,9 @@ defmodule LiveBookWeb.Cell do ~L"""
-
-
-
+
+
+
""" diff --git a/lib/live_book_web/live/insert_cell_actions.ex b/lib/live_book_web/live/insert_cell_component.ex similarity index 66% rename from lib/live_book_web/live/insert_cell_actions.ex rename to lib/live_book_web/live/insert_cell_component.ex index 43d92d9b9..4e50bacad 100644 --- a/lib/live_book_web/live/insert_cell_actions.ex +++ b/lib/live_book_web/live/insert_cell_component.ex @@ -1,24 +1,22 @@ -defmodule LiveBookWeb.InsertCellActions do +defmodule LiveBookWeb.InsertCellComponent do use LiveBookWeb, :live_component def render(assigns) do ~L"""
<%= line() %> - - <%= line() %> diff --git a/lib/live_book_web/live/runtime_component.ex b/lib/live_book_web/live/runtime_component.ex index 2bd795735..739a3109b 100644 --- a/lib/live_book_web/live/runtime_component.ex +++ b/lib/live_book_web/live/runtime_component.ex @@ -91,16 +91,11 @@ defmodule LiveBookWeb.RuntimeComponent do

Then enter the name of the node below:

- <%= f = form_for :node, "#", - phx_target: @myself, - phx_submit: "init_attached" %> + <%= f = form_for :node, "#", phx_target: @myself, phx_submit: "init_attached" %> + <%= text_input f, :name, class: "input-base text-sm shadow", + placeholder: if(LiveBook.Config.shortnames?, do: "test", else: "test@127.0.0.1") %> - <%= text_input f, :name, - placeholder: if(LiveBook.Config.shortnames?, do: "test", else: "test@127.0.0.1"), - class: "input-base text-sm shadow" %> - - <%= submit "Connect", - class: "mt-3 button-base text-sm" %> + <%= submit "Connect", class: "mt-3 button-base text-sm" %>
diff --git a/lib/live_book_web/live/section.ex b/lib/live_book_web/live/section.ex deleted file mode 100644 index 85bb763fa..000000000 --- a/lib/live_book_web/live/section.ex +++ /dev/null @@ -1,48 +0,0 @@ -defmodule LiveBookWeb.Section do - use LiveBookWeb, :live_component - - def render(assigns) do - ~L""" -
"> -
-
- <%= Icons.svg(:chevron_right, class: "h-8") %> -

<%= @section.name %>

-
-
- -
-
-
-
- <%= live_component @socket, LiveBookWeb.InsertCellActions, - id: "#{@section.id}:0", - section_id: @section.id, - index: 0 %> - <%= for {cell, index} <- Enum.with_index(@section.cells) do %> - <%= live_component @socket, LiveBookWeb.Cell, - id: cell.id, - cell: cell, - cell_info: @cell_infos[cell.id], - focused: @selected and cell.id == @focused_cell_id, - expanded: @selected and cell.id == @focused_cell_id and @focused_cell_expanded %> - <%= live_component @socket, LiveBookWeb.InsertCellActions, - id: "#{@section.id}:#{index + 1}", - section_id: @section.id, - index: index + 1 %> - <% end %> -
-
-
- """ - end -end diff --git a/lib/live_book_web/live/section_component.ex b/lib/live_book_web/live/section_component.ex new file mode 100644 index 000000000..48ea3fad5 --- /dev/null +++ b/lib/live_book_web/live/section_component.ex @@ -0,0 +1,50 @@ +defmodule LiveBookWeb.SectionComponent do + use LiveBookWeb, :live_component + + def render(assigns) do + ~L""" +
"> +
+
+ <%= Icons.svg(:chevron_right, class: "h-8") %> +

<%= @section.name %>

+ <%# ^ Note it's important there's no space between

and

+ because we want the content to exactly match @section.name. %> +
+
+ +
+
+
+
+ <%= live_component @socket, LiveBookWeb.InsertCellComponent, + id: "#{@section.id}:0", + section_id: @section.id, + index: 0 %> + <%= for {cell, index} <- Enum.with_index(@section.cells) do %> + <%= live_component @socket, LiveBookWeb.CellComponent, + id: cell.id, + cell: cell, + cell_info: @cell_infos[cell.id], + focused: @selected and cell.id == @focused_cell_id, + expanded: @selected and cell.id == @focused_cell_id and @focused_cell_expanded %> + <%= live_component @socket, LiveBookWeb.InsertCellComponent, + id: "#{@section.id}:#{index + 1}", + section_id: @section.id, + index: index + 1 %> + <% end %> +
+
+
+ """ + end +end diff --git a/lib/live_book_web/live/session_live.ex b/lib/live_book_web/live/session_live.ex index 4a449536b..b72461e13 100644 --- a/lib/live_book_web/live/session_live.ex +++ b/lib/live_book_web/live/session_live.ex @@ -18,7 +18,7 @@ defmodule LiveBookWeb.SessionLive do {:ok, assign(socket, initial_assigns(session_id, data))} else - {:ok, redirect(socket, to: Routes.live_path(socket, LiveBookWeb.SessionsLive))} + {:ok, redirect(socket, to: Routes.sessions_path(socket, :page))} end end @@ -44,11 +44,11 @@ defmodule LiveBookWeb.SessionLive do ~L""" <%= if @live_action == :runtime do %> <%= live_modal @socket, LiveBookWeb.RuntimeComponent, - id: :runtime_modal, - action: :runtime, - return_to: Routes.session_path(@socket, :show, @session_id), - session_id: @session_id, - runtime: @data.runtime %> + id: :runtime_modal, + action: :runtime, + return_to: Routes.session_path(@socket, :page, @session_id), + session_id: @session_id, + runtime: @data.runtime %> <% end %>
<%= for section <- @data.notebook.sections do %> - <%= live_component @socket, LiveBookWeb.Section, - id: section.id, - section: section, - selected: section.id == @selected_section_id, - cell_infos: @data.cell_infos, - focused_cell_id: @focused_cell_id, - focused_cell_expanded: @focused_cell_expanded %> + <%= live_component @socket, LiveBookWeb.SectionComponent, + id: section.id, + section: section, + selected: section.id == @selected_section_id, + cell_infos: @data.cell_infos, + focused_cell_id: @focused_cell_id, + focused_cell_expanded: @focused_cell_expanded %> <% end %>
diff --git a/lib/live_book_web/live/sessions_live.ex b/lib/live_book_web/live/sessions_live.ex index 873f810f4..b6fff2c75 100644 --- a/lib/live_book_web/live/sessions_live.ex +++ b/lib/live_book_web/live/sessions_live.ex @@ -16,14 +16,14 @@ defmodule LiveBookWeb.SessionsLive do def render(assigns) do ~L"""
-
+
Sessions
<%= for session_id <- Enum.sort(@session_ids) do %>
- <%= live_redirect session_id, to: Routes.session_path(@socket, :show, session_id) %> + <%= live_redirect session_id, to: Routes.session_path(@socket, :page, session_id) %>