Skip to content

Commit

Permalink
feat(notebook-pov): add notebook, cell and editor web components
Browse files Browse the repository at this point in the history
  • Loading branch information
bsahitya committed Jun 25, 2024
1 parent cac0f4b commit 409f0f5
Show file tree
Hide file tree
Showing 17 changed files with 1,007 additions and 1 deletion.
15 changes: 15 additions & 0 deletions libs/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
"import": "./button.mjs",
"require": "./button.js"
},
"./cell": {
"types": "./cell/cell.d.ts",
"import": "./cell.mjs",
"require": "./cell.js"
},
"./checkbox": {
"types": "./checkbox/checkbox.d.ts",
"import": "./checkbox.mjs",
Expand All @@ -66,6 +71,11 @@
"import": "./circular-progress.mjs",
"require": "./circular-progress.js"
},
"./code-editor": {
"types": "./code-editor/code-editor.d.ts",
"import": "./code-editor.mjs",
"require": "./code-editor.js"
},
"./code-snippet": {
"types": "./code-snippet/code-snippet.d.ts",
"import": "./code-snippet.mjs",
Expand Down Expand Up @@ -161,6 +171,11 @@
"import": "./menu.mjs",
"require": "./menu.js"
},
"./notebook": {
"types": "./notebook/notebook.d.ts",
"import": "./notebook.mjs",
"require": "./notebook.js"
},
"./radio": {
"types": "./radio/radio.d.ts",
"import": "./radio.mjs",
Expand Down
59 changes: 59 additions & 0 deletions libs/components/src/cell/cell.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
:host {
--mdc-icon-button-size: 24px;

font-family: var(--mdc-typography-body1-font-family);
height: 100%;
width: 100%;
}

.selection-indicator {
background-color: var(--cv-theme-primary);
border-radius: 2px;
margin-top: 2px;
visibility: hidden;
width: 8px;
}

.timesExecuted {
color: var(--cv-theme-outline-variant);
min-height: var(--mdc-icon-button-size);
min-width: var(--mdc-icon-button-size);
}

.cell {
box-sizing: border-box;
display: flex;
justify-content: space-between;

&:hover,
&.focused,
&.selected {
.selection-indicator {
visibility: visible;
}

.timesExecuted {
color: var(--cv-theme-primary);
}
}
}

.cellWrapper {
display: flex;
flex-direction: column;
width: 95%;
}

.cellCodeWrapper {
align-items: flex-start;
display: flex;
justify-content: space-between;

.editor-output-wrapper {
width: calc(95% - 8px);
}
}

.output {
margin: 0.5rem 0.25rem;
}
11 changes: 11 additions & 0 deletions libs/components/src/cell/cell.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @vitest-environment jsdom
*/
import { it, describe, expect } from 'vitest';
import { CovalentCell } from './cell';

describe('Cell', () => {
it('should work', () => {
expect(new CovalentCell()).toBeDefined();
});
});
22 changes: 22 additions & 0 deletions libs/components/src/cell/cell.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import './cell';

export default {
title: 'Components/Cell',
args: {
code: '',
index: 0,
language: 'sql',
output: 'Heres my output!',
selected: false,
},
};

const Template = ({ code, index, language, selected }) => {
return `<div style="width: 800px; ">
<cv-cell code="${code}" index="${index}" language="${language}" ${
selected ? 'selected' : ''
}></cv-cell>
</div>`;
};

export const Basic = Template.bind({});
153 changes: 153 additions & 0 deletions libs/components/src/cell/cell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { css, html, LitElement, PropertyValues, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import styles from './cell.scss?inline';
import { classMap } from 'lit/directives/class-map.js';
import '../code-editor/code-editor';
import '../icon-button/icon-button';
import '../typography/typography';

declare global {
interface HTMLElementTagNameMap {
'cv-cell': CovalentCell;
}
}

enum CvCellEvents {
RUN_CODE = 'cell-run-code',
}

@customElement('cv-cell')
export class CovalentCell extends LitElement {
/**
* The index of the cell in a notebook
*/
@property({ type: Number })
index?: number;

/**
* Code written in the cell
*/
@property({ type: String })
code = '';

/**
* Language of the code
*/
@property({ type: String })
language = '';

/**
* Whether the cell is selected
*/
@property({ type: Boolean, reflect: true })
selected = false;

/**
* Number of times the cell was exceuted
*/
@property({ type: Number })
timesExecuted = 0;

/**
* Whether the editor is shown
*/
@property({ type: Boolean, reflect: true })
showEditor? = true;

_editorFocused = false;

editorOptions = {
minimap: { enabled: false }, // Disable minimap to save space
wordWrap: 'on', // Enable word wrap to avoid horizontal scroll
fontSize: '14px',
glyphMargin: false,
folding: false,
lineNumbers: 'off',
lineDecorationsWidth: 0,
lineNumbersMinChars: 0,
renderLineHighlight: 'none',
};

static override styles = [
css`
${unsafeCSS(styles)}
`,
];

handleCodeChange(e: CustomEvent) {
this.code = e.detail.code;
}

handleRun() {
this.dispatchEvent(
new CustomEvent(CvCellEvents.RUN_CODE, {
detail: { index: this.index, code: this.code },
bubbles: true,
composed: true,
})
);
}

setEditorFocus(setFocus: boolean) {
this._editorFocused = setFocus;
this.requestUpdate();
}

protected updated(changedProperties: PropertyValues) {
if (changedProperties.has('code') || changedProperties.has('language')) {
const editor = this.shadowRoot?.querySelector('cv-code-editor');
if (editor) {
editor.code = this.code;
editor.language = this.language;
}
}
}

renderEditor() {
const editor = html`<cv-code-editor
@code-change="${this.handleCodeChange}"
@editor-focus="${() => this.setEditorFocus(true)}"
@editor-blur="${() => this.setEditorFocus(false)}"
.code="${this.code}"
.language="${this.language}"
.options="${this.editorOptions}"
></cv-code-editor>`;

const output = html`<cv-typography class="output" scale="body1">
<slot name="output"></slot>
</cv-typography>`;

return html`${this.showEditor ? editor : ''}${(!this.showEditor &&
this.language === 'markdown') ||
this.language !== 'markdown'
? output
: ''}`;
}

protected render() {
const classes = {
cell: true,
selected: this.selected,
focused: this._editorFocused,
};
return html`
<div class="${classMap(classes)}">
<span class="selection-indicator"></span>
<div class="cellWrapper">
<div class="cellCodeWrapper">
<span class="timesExecuted">
${this.showEditor
? html`[${this.timesExecuted === 0
? ' '
: this.timesExecuted}]:`
: ''}
</span>
<div class="editor-output-wrapper">${this.renderEditor()}</div>
</div>
</div>
</div>
`;
}
}

export default CovalentCell;
24 changes: 24 additions & 0 deletions libs/components/src/code-editor/code-editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
:host {
--editor-width: 100%;
--editor-height: 100%;

.monaco-editor {
.lines-content.monaco-editor-background {
height: var(--editor-height);
margin-left: 4px;
width: var(--editor-width);
}
}

.monaco-editor.focused {
border: 1px solid var(--cv-theme-primary);
}
}

.editor {
height: var(--editor-height);
min-height: var(--editor-height);
min-width: var(--editor-height);
padding-top: 2px;
width: var(--editor-width);
}
11 changes: 11 additions & 0 deletions libs/components/src/code-editor/code-editor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @vitest-environment jsdom
*/
import { it, describe, expect } from 'vitest';
import { CovalentCodeEditor } from './code-editor';

describe('Code editor', () => {
it('should work', () => {
expect(new CovalentCodeEditor()).toBeDefined();
});
});
41 changes: 41 additions & 0 deletions libs/components/src/code-editor/code-editor.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import './code-editor';

const sqlContent = `
SELECT * FROM load_to_teradata (
ON (
SELECT 'class' AS class_col,
'variable' AS variable_col,
'type' AS type_col,
category,
cnt,
'sum' AS sum_col,
'sumSq',
'totalCnt'
FROM aster_nb_modelSC
)
tdpid ('sdt12432.labs.teradata.com')
username ('sample_user')
password ('sample_user')
target_table ('td_nb_modelSC')
);
`;

export default {
title: 'Components/Code Editor',
args: {
theme: 'vs-light',
code: sqlContent,
language: 'sql',
},
};

const Template = ({ theme, language, code }) => {
return `
<div style="width: 800px; height: 400px">
<cv-code-editor language="${language}" theme="${theme}" code="${code}">
</cv-code-editor>
</div>
`;
};

export const Basic = Template.bind();
Loading

0 comments on commit 409f0f5

Please sign in to comment.