mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-09-06 04:54:29 +08:00
Some cleanups (#25)
* Remove old js files * Cleanup styles * Update page title * Unify elements rounding * Fix indentation * Rename component modules * Add actions to routes for better helpers
This commit is contained in:
parent
b487fe6104
commit
9d3a2ae264
21 changed files with 338 additions and 1141 deletions
|
@ -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";
|
||||
|
|
39
assets/css/components.css
Normal file
39
assets/css/components.css
Normal file
|
@ -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;
|
||||
}
|
41
assets/css/elixir_inspect.css
Normal file
41
assets/css/elixir_inspect.css
Normal file
|
@ -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;
|
||||
}
|
5
assets/css/global.css
Normal file
5
assets/css/global.css
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* Remove the default outline on focused elements */
|
||||
:focus,
|
||||
button:focus {
|
||||
outline: none;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
99
assets/css/markdown.css
Normal file
99
assets/css/markdown.css
Normal file
|
@ -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;
|
||||
}
|
|
@ -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,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="%23d1d1d1" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>')
|
||||
center right no-repeat;
|
||||
padding-right: 3rem;
|
||||
}
|
||||
select:focus {
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="%230069d9" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>');
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
10
assets/css/utilities.css
Normal file
10
assets/css/utilities.css
Normal file
|
@ -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;
|
||||
}
|
|
@ -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;
|
28
assets/package-lock.json
generated
28
assets/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: [
|
||||
require('postcss-import'),
|
||||
require('tailwindcss'),
|
||||
require('autoprefixer'),
|
||||
]
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
defmodule LiveBookWeb.Cell do
|
||||
defmodule LiveBookWeb.CellComponent do
|
||||
use LiveBookWeb, :live_component
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<div id="cell-<%= @cell.id %>"
|
||||
phx-hook="Cell"
|
||||
data-cell-id="<%= @cell.id %>"
|
||||
data-type="<%= @cell.type %>"
|
||||
data-focused="<%= @focused %>"
|
||||
data-expanded="<%= @expanded %>"
|
||||
class="flex flex-col relative mr-10 border-l-4 pl-4 -ml-4 border-blue-100 border-opacity-0 hover:border-opacity-100 <%= if @focused, do: "border-blue-300 border-opacity-100"%>">
|
||||
<div class="flex flex-col relative mr-10 border-l-4 pl-4 -ml-4 border-blue-100 border-opacity-0 hover:border-opacity-100 <%= if @focused, do: "border-blue-300 border-opacity-100"%>"
|
||||
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) %>
|
||||
</div>
|
||||
"""
|
||||
|
@ -64,9 +64,10 @@ defmodule LiveBookWeb.Cell do
|
|||
|
||||
~L"""
|
||||
<div class="py-3 rounded-md overflow-hidden bg-editor relative">
|
||||
<div id="editor-container-<%= @cell.id %>"
|
||||
data-editor-container
|
||||
phx-update="ignore">
|
||||
<div
|
||||
id="editor-container-<%= @cell.id %>"
|
||||
data-editor-container
|
||||
phx-update="ignore">
|
||||
<%= render_editor_content_placeholder(@cell.source) %>
|
||||
</div>
|
||||
|
||||
|
@ -97,9 +98,9 @@ defmodule LiveBookWeb.Cell do
|
|||
~L"""
|
||||
<div class="max-w-2xl w-full animate-pulse">
|
||||
<div class="flex-1 space-y-4">
|
||||
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
|
||||
<div class="h-4 bg-gray-200 rounded"></div>
|
||||
<div class="h-4 bg-gray-200 rounded w-5/6"></div>
|
||||
<div class="h-4 bg-gray-200 rounded-md w-3/4"></div>
|
||||
<div class="h-4 bg-gray-200 rounded-md"></div>
|
||||
<div class="h-4 bg-gray-200 rounded-md w-5/6"></div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
@ -119,9 +120,9 @@ defmodule LiveBookWeb.Cell do
|
|||
~L"""
|
||||
<div class="px-8 max-w-2xl w-full animate-pulse">
|
||||
<div class="flex-1 space-y-4 py-1">
|
||||
<div class="h-4 bg-gray-500 rounded w-3/4"></div>
|
||||
<div class="h-4 bg-gray-500 rounded"></div>
|
||||
<div class="h-4 bg-gray-500 rounded w-5/6"></div>
|
||||
<div class="h-4 bg-gray-500 rounded-md w-3/4"></div>
|
||||
<div class="h-4 bg-gray-500 rounded-md"></div>
|
||||
<div class="h-4 bg-gray-500 rounded-md w-5/6"></div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
|
@ -1,24 +1,22 @@
|
|||
defmodule LiveBookWeb.InsertCellActions do
|
||||
defmodule LiveBookWeb.InsertCellComponent do
|
||||
use LiveBookWeb, :live_component
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<div class="opacity-0 hover:opacity-100 flex space-x-2 justify-center items-center">
|
||||
<%= line() %>
|
||||
<button
|
||||
<button class="py-1 px-2 rounded-md text-sm hover:bg-gray-100 border border-gray-200 bg-gray-50"
|
||||
phx-click="insert_cell"
|
||||
phx-value-type="markdown"
|
||||
phx-value-section_id="<%= @section_id %>"
|
||||
phx-value-index="<%= @index %>"
|
||||
class="py-1 px-2 rounded text-sm hover:bg-gray-100 border border-gray-200 bg-gray-50">
|
||||
phx-value-index="<%= @index %>">
|
||||
+ Markdown
|
||||
</button>
|
||||
<button
|
||||
<button class="py-1 px-2 rounded-md text-sm hover:bg-gray-100 border border-gray-200 bg-gray-50"
|
||||
phx-click="insert_cell"
|
||||
phx-value-type="elixir"
|
||||
phx-value-section_id="<%= @section_id %>"
|
||||
phx-value-index="<%= @index %>"
|
||||
class="py-1 px-2 rounded text-sm hover:bg-gray-100 border border-gray-200 bg-gray-50">
|
||||
phx-value-index="<%= @index %>">
|
||||
+ Elixir
|
||||
</button>
|
||||
<%= line() %>
|
|
@ -91,16 +91,11 @@ defmodule LiveBookWeb.RuntimeComponent do
|
|||
<p class="text-sm text-gray-500">
|
||||
Then enter the name of the node below:
|
||||
</p>
|
||||
<%= 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" %>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
defmodule LiveBookWeb.Section do
|
||||
use LiveBookWeb, :live_component
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<div class="<%= if not @selected, do: "hidden" %>">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex space-x-2 items-center text-gray-600">
|
||||
<%= Icons.svg(:chevron_right, class: "h-8") %>
|
||||
<h2 id="section-<%= @section.id %>-name"
|
||||
contenteditable
|
||||
spellcheck="false"
|
||||
phx-blur="set_section_name"
|
||||
phx-value-section_id="<%= @section.id %>"
|
||||
phx-hook="ContentEditable"
|
||||
data-update-attribute="phx-value-name"
|
||||
class="text-3xl"><%= @section.name %></h2>
|
||||
</div>
|
||||
<div class="flex space-x-2 items-center">
|
||||
<button phx-click="delete_section" phx-value-section_id="<%= @section.id %>" class="text-gray-600 hover:text-current">
|
||||
<%= Icons.svg(:trash, class: "h-6") %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container py-4">
|
||||
<div class="flex flex-col space-y-2 pb-80">
|
||||
<%= 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 %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
50
lib/live_book_web/live/section_component.ex
Normal file
50
lib/live_book_web/live/section_component.ex
Normal file
|
@ -0,0 +1,50 @@
|
|||
defmodule LiveBookWeb.SectionComponent do
|
||||
use LiveBookWeb, :live_component
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<div class="<%= if not @selected, do: "hidden" %>">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex space-x-2 items-center text-gray-600">
|
||||
<%= Icons.svg(:chevron_right, class: "h-8") %>
|
||||
<h2 class="text-3xl"
|
||||
id="section-<%= @section.id %>-name"
|
||||
contenteditable
|
||||
spellcheck="false"
|
||||
phx-blur="set_section_name"
|
||||
phx-value-section_id="<%= @section.id %>"
|
||||
phx-hook="ContentEditable"
|
||||
data-update-attribute="phx-value-name"><%= @section.name %></h2>
|
||||
<%# ^ Note it's important there's no space between <h2> and </h2>
|
||||
because we want the content to exactly match @section.name. %>
|
||||
</div>
|
||||
<div class="flex space-x-2 items-center">
|
||||
<button phx-click="delete_section" phx-value-section_id="<%= @section.id %>" class="text-gray-600 hover:text-current">
|
||||
<%= Icons.svg(:trash, class: "h-6") %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container py-4">
|
||||
<div class="flex flex-col space-y-2 pb-80">
|
||||
<%= 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 %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
|
@ -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 %>
|
||||
|
||||
<div class="flex flex-grow h-full"
|
||||
|
@ -91,13 +91,13 @@ defmodule LiveBookWeb.SessionLive do
|
|||
<div class="flex-grow px-6 py-8 flex overflow-y-auto">
|
||||
<div class="max-w-screen-lg w-full mx-auto">
|
||||
<%= 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 %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,14 +16,14 @@ defmodule LiveBookWeb.SessionsLive do
|
|||
def render(assigns) do
|
||||
~L"""
|
||||
<div class="container max-w-screen-md p-4 mx-auto">
|
||||
<div class="flex flex-col shadow-md rounded px-3 py-2 mb-4">
|
||||
<div class="flex flex-col shadow-md rounded-md px-3 py-2 mb-4">
|
||||
<div class="text-gray-700 text-lg font-semibold p-2">
|
||||
Sessions
|
||||
</div>
|
||||
<%= for session_id <- Enum.sort(@session_ids) do %>
|
||||
<div class="p-3 flex">
|
||||
<div class="flex-grow text-lg text-gray-500 hover:text-current">
|
||||
<%= live_redirect session_id, to: Routes.session_path(@socket, :show, session_id) %>
|
||||
<%= live_redirect session_id, to: Routes.session_path(@socket, :page, session_id) %>
|
||||
</div>
|
||||
<div>
|
||||
<button phx-click="delete_session" phx-value-id="<%= session_id %>" aria-label="delete" class="text-gray-500 hover:text-current">
|
||||
|
@ -44,7 +44,7 @@ defmodule LiveBookWeb.SessionsLive do
|
|||
def handle_event("create_session", _params, socket) do
|
||||
case LiveBook.SessionSupervisor.create_session() do
|
||||
{:ok, id} ->
|
||||
{:noreply, push_redirect(socket, to: Routes.session_path(socket, :show, id))}
|
||||
{:noreply, push_redirect(socket, to: Routes.session_path(socket, :page, id))}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, put_flash(socket, :error, "Failed to create a notebook: #{reason}")}
|
||||
|
|
|
@ -17,9 +17,9 @@ defmodule LiveBookWeb.Router do
|
|||
scope "/", LiveBookWeb do
|
||||
pipe_through :browser
|
||||
|
||||
live "/", HomeLive
|
||||
live "/sessions", SessionsLive
|
||||
live "/sessions/:id", SessionLive, :show
|
||||
live "/", HomeLive, :page
|
||||
live "/sessions", SessionsLive, :page
|
||||
live "/sessions/:id", SessionLive, :page
|
||||
live "/sessions/:id/runtime", SessionLive, :runtime
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<%= csrf_meta_tag() %>
|
||||
<%= live_title_tag assigns[:page_title] || "LiveBook", suffix: " · Phoenix Framework" %>
|
||||
<%= live_title_tag assigns[:page_title] || "LiveBook" %>
|
||||
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
|
||||
<script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
|
||||
</head>
|
||||
|
|
Loading…
Add table
Reference in a new issue