+
-
@@ -87,9 +174,17 @@ const hello = 'yes'
public async firstUpdated(_changedPropertiesArg) {
await super.firstUpdated(_changedPropertiesArg);
+
+ // Initialize current ratio from property
+ this.currentSplitRatio = this.splitRatio;
+
+ // Cache elements
+ this.containerElement = this.shadowRoot.querySelector('.splitContainer');
+ this.resizeHandleElement = this.shadowRoot.querySelector('.resizeHandle');
+
const editor = this.shadowRoot.querySelector('dees-workspace-monaco') as DeesWorkspaceMonaco;
- // lets care about wiring the markdown stuff.
+ // Wire up markdown rendering
const markdownOutlet = this.shadowRoot.querySelector('dees-workspace-markdownoutlet');
const smartmarkdownInstance = new domtools.plugins.smartmarkdown.SmartMarkdown();
const mdParsedResult = await smartmarkdownInstance.getMdParsedResultFromMarkdown('loading...')
@@ -97,6 +192,64 @@ const hello = 'yes'
await mdParsedResult.updateFromMarkdownString(contentArg)
const html = mdParsedResult.html;
markdownOutlet.updateHtmlText(html);
- })
+ });
+ }
+
+ private handleMouseDown = (e: MouseEvent) => {
+ e.preventDefault();
+ this.isDragging = true;
+
+ document.addEventListener('mousemove', this.handleMouseMove);
+ document.addEventListener('mouseup', this.handleMouseUp);
+ };
+
+ private handleMouseMove = (e: MouseEvent) => {
+ if (!this.isDragging || !this.containerElement) return;
+
+ const containerRect = this.containerElement.getBoundingClientRect();
+ const containerWidth = containerRect.width;
+ const mouseX = e.clientX - containerRect.left;
+
+ // Calculate percentage, accounting for the resize handle width (6px)
+ let newRatio = (mouseX / containerWidth) * 100;
+
+ // Clamp to min/max
+ newRatio = Math.max(this.minPanelSize, Math.min(100 - this.minPanelSize, newRatio));
+
+ this.currentSplitRatio = newRatio;
+ };
+
+ private handleMouseUp = () => {
+ this.isDragging = false;
+ document.removeEventListener('mousemove', this.handleMouseMove);
+ document.removeEventListener('mouseup', this.handleMouseUp);
+
+ // Trigger resize on monaco editor
+ const editor = this.shadowRoot.querySelector('dees-workspace-monaco') as DeesWorkspaceMonaco;
+ if (editor) {
+ // Monaco needs to be notified of size changes
+ window.dispatchEvent(new Event('resize'));
+ }
+ };
+
+ async disconnectedCallback() {
+ await super.disconnectedCallback();
+ // Clean up event listeners
+ document.removeEventListener('mousemove', this.handleMouseMove);
+ document.removeEventListener('mouseup', this.handleMouseUp);
+ }
+
+ /**
+ * Programmatically set the split ratio
+ */
+ public setSplitRatio(ratio: number) {
+ this.currentSplitRatio = Math.max(this.minPanelSize, Math.min(100 - this.minPanelSize, ratio));
+ }
+
+ /**
+ * Reset to initial split ratio
+ */
+ public resetSplitRatio() {
+ this.currentSplitRatio = this.splitRatio;
}
}
diff --git a/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.demo.ts b/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.demo.ts
new file mode 100644
index 0000000..3d8567a
--- /dev/null
+++ b/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.demo.ts
@@ -0,0 +1,289 @@
+import { html, css } from '@design.estate/dees-element';
+import '@design.estate/dees-wcctools/demotools';
+import '../../dees-panel/dees-panel.js';
+import type { DeesWorkspaceMarkdownoutlet } from './dees-workspace-markdownoutlet.js';
+
+export const demoFunc = () => html`
+
+
+
+
+
+
{
+ const outlet = panelEl.querySelector('dees-workspace-markdownoutlet') as DeesWorkspaceMarkdownoutlet;
+ await outlet?.updateHtmlText(`
+ Heading Level 1
+ Heading Level 2
+ Heading Level 3
+ Heading Level 4
+ Heading Level 5
+ Heading Level 6
+ `);
+ }}
+ >
+
+
+
+
+
{
+ const outlet = panelEl.querySelector('dees-workspace-markdownoutlet') as DeesWorkspaceMarkdownoutlet;
+ await outlet?.updateHtmlText(`
+ This is a paragraph with bold text and italic text.
+ You can also use bold italic for emphasis.
+ Here's a link example and some inline code.
+ Press Ctrl + C to copy text.
+
+ Above is a horizontal rule separator.
+ `);
+ }}
+ >
+
+
+
+
+
{
+ const outlet = panelEl.querySelector('dees-workspace-markdownoutlet') as DeesWorkspaceMarkdownoutlet;
+ await outlet?.updateHtmlText(`
+ Unordered List
+
+ - First item
+ - Second item
+
+ - Nested item 1
+ - Nested item 2
+
+
+ - Third item
+
+
+ Ordered List
+
+ - Step one
+ - Step two
+ - Step three
+
+
+ Task List
+
+ `);
+ }}
+ >
+
+
+
+
+
{
+ const outlet = panelEl.querySelector('dees-workspace-markdownoutlet') as DeesWorkspaceMarkdownoutlet;
+ await outlet?.updateHtmlText(`
+ Inline code: const greeting = "Hello, World!";
+
+ TypeScript Example
+ import { html, css } from '@design.estate/dees-element';
+
+interface IUser {
+ name: string;
+ email: string;
+ age?: number;
+}
+
+const getUser = async (id: string): Promise<IUser> => {
+ const response = await fetch(\`/api/users/\${id}\`);
+ return response.json();
+};
+
+ JSON Example
+ {
+ "name": "dees-catalog",
+ "version": "3.0.0",
+ "dependencies": {
+ "@design.estate/dees-element": "^2.0.0"
+ }
+}
+ `);
+ }}
+ >
+
+
+
+
+
{
+ const outlet = panelEl.querySelector('dees-workspace-markdownoutlet') as DeesWorkspaceMarkdownoutlet;
+ await outlet?.updateHtmlText(`
+
+
+
+ | Feature |
+ Status |
+ Priority |
+
+
+
+
+ | Dark mode support |
+ Completed |
+ High |
+
+
+ | Responsive design |
+ In Progress |
+ Medium |
+
+
+ | Accessibility |
+ Planned |
+ High |
+
+
+ | Documentation |
+ In Progress |
+ Low |
+
+
+
+ `);
+ }}
+ >
+
+
+
+
+
{
+ const outlet = panelEl.querySelector('dees-workspace-markdownoutlet') as DeesWorkspaceMarkdownoutlet;
+ await outlet?.updateHtmlText(`
+
+ This is a standard blockquote. It's great for highlighting important information or quotes from other sources.
+
+
+
+
Note: This is an informational note to draw attention to important details.
+
+
+
+
Tip: Here's a helpful tip to improve your workflow.
+
+
+
+
Important: This information is crucial for understanding the topic.
+
+
+
+
Warning: Be careful when performing this action.
+
+
+
+
Caution: This action may have unintended consequences.
+
+ `);
+ }}
+ >
+
+
+
+
+
{
+ const outlet = panelEl.querySelector('dees-workspace-markdownoutlet') as DeesWorkspaceMarkdownoutlet;
+ await outlet?.updateHtmlText(`
+ Getting Started Guide
+ Welcome to the dees-catalog component library. This guide will help you get up and running quickly.
+
+ Installation
+ Install the package using your preferred package manager:
+
+pnpm add @design.estate/dees-catalog
+
+
+npm install @design.estate/dees-catalog
+
+ Basic Usage
+ Import and use components in your TypeScript files:
+ import { DeesButton } from '@design.estate/dees-catalog';
+
+
+html\`<dees-button>Click me</dees-button>\`
+
+
+
Tip: Check the demo showcase for live examples of all components.
+
+
+ Available Components
+
+
+
+ | Component |
+ Description |
+
+
+
+
+ dees-button |
+ Primary button component |
+
+
+ dees-input-text |
+ Text input field |
+
+
+ dees-table |
+ Data table with sorting |
+
+
+ dees-modal |
+ Modal dialog |
+
+
+
+
+ Next Steps
+
+
+
+ "The best component library is one that gets out of your way." — Design Systems Team
+
+ `);
+ }}
+ >
+
+
+
+
+`;
diff --git a/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.ts b/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.ts
index 5a18c2f..1f3ab58 100644
--- a/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.ts
+++ b/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.ts
@@ -1,4 +1,13 @@
-import { customElement, DeesElement, html, type TemplateResult } from '@design.estate/dees-element';
+import {
+ customElement,
+ DeesElement,
+ html,
+ type TemplateResult,
+ css,
+ cssManager,
+} from '@design.estate/dees-element';
+import { themeDefaultStyles } from '../../00theme.js';
+import { demoFunc } from './dees-workspace-markdownoutlet.demo.js';
declare global {
interface HTMLElementTagNameMap {
@@ -9,27 +18,382 @@ declare global {
@customElement('dees-workspace-markdownoutlet')
export class DeesWorkspaceMarkdownoutlet extends DeesElement {
// DEMO
- public static demo = () => html`
`;
+ public static demo = demoFunc;
+
+ public static styles = [
+ themeDefaultStyles,
+ cssManager.defaultStyles,
+ css`
+ :host {
+ display: block;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ line-height: 1.6;
+ color: ${cssManager.bdTheme('#24292f', '#e6edf3')};
+ }
+
+ .outlet {
+ word-wrap: break-word;
+ }
+
+ /* Headings */
+ h1, h2, h3, h4, h5, h6 {
+ margin-top: 24px;
+ margin-bottom: 16px;
+ font-weight: 600;
+ line-height: 1.25;
+ color: ${cssManager.bdTheme('#1f2328', '#f0f6fc')};
+ }
+
+ h1 {
+ font-size: 2em;
+ padding-bottom: 0.3em;
+ border-bottom: 1px solid ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ }
+
+ h2 {
+ font-size: 1.5em;
+ padding-bottom: 0.3em;
+ border-bottom: 1px solid ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ }
+
+ h3 {
+ font-size: 1.25em;
+ }
+
+ h4 {
+ font-size: 1em;
+ }
+
+ h5 {
+ font-size: 0.875em;
+ }
+
+ h6 {
+ font-size: 0.85em;
+ color: ${cssManager.bdTheme('#656d76', '#8b949e')};
+ }
+
+ /* Paragraphs and text */
+ p {
+ margin-top: 0;
+ margin-bottom: 16px;
+ }
+
+ /* Links */
+ a {
+ color: ${cssManager.bdTheme('#0969da', '#58a6ff')};
+ text-decoration: none;
+ }
+
+ a:hover {
+ text-decoration: underline;
+ }
+
+ /* Strong and emphasis */
+ strong {
+ font-weight: 600;
+ color: ${cssManager.bdTheme('#1f2328', '#f0f6fc')};
+ }
+
+ em {
+ font-style: italic;
+ }
+
+ /* Lists */
+ ul, ol {
+ margin-top: 0;
+ margin-bottom: 16px;
+ padding-left: 2em;
+ }
+
+ li {
+ margin-top: 4px;
+ }
+
+ li + li {
+ margin-top: 4px;
+ }
+
+ ul ul, ul ol, ol ul, ol ol {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ /* Blockquotes */
+ blockquote {
+ margin: 0 0 16px 0;
+ padding: 0 1em;
+ color: ${cssManager.bdTheme('#656d76', '#8b949e')};
+ border-left: 4px solid ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ }
+
+ blockquote > :first-child {
+ margin-top: 0;
+ }
+
+ blockquote > :last-child {
+ margin-bottom: 0;
+ }
+
+ /* Inline code */
+ code {
+ padding: 0.2em 0.4em;
+ margin: 0;
+ font-size: 85%;
+ font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
+ background-color: ${cssManager.bdTheme('rgba(175, 184, 193, 0.2)', 'rgba(110, 118, 129, 0.4)')};
+ border-radius: 6px;
+ white-space: break-spaces;
+ }
+
+ /* Code blocks */
+ pre {
+ margin-top: 0;
+ margin-bottom: 16px;
+ padding: 16px;
+ overflow: auto;
+ font-size: 85%;
+ line-height: 1.45;
+ font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
+ background-color: ${cssManager.bdTheme('#f6f8fa', '#161b22')};
+ border-radius: 6px;
+ word-wrap: normal;
+ }
+
+ pre code {
+ display: block;
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ line-height: inherit;
+ word-wrap: normal;
+ background-color: transparent;
+ border: 0;
+ font-size: 100%;
+ white-space: pre;
+ }
+
+ /* Tables */
+ table {
+ width: max-content;
+ max-width: 100%;
+ margin-top: 0;
+ margin-bottom: 16px;
+ border-spacing: 0;
+ border-collapse: collapse;
+ overflow: auto;
+ display: block;
+ }
+
+ table th {
+ font-weight: 600;
+ padding: 6px 13px;
+ border: 1px solid ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ background-color: ${cssManager.bdTheme('#f6f8fa', '#161b22')};
+ color: ${cssManager.bdTheme('#1f2328', '#e6edf3')};
+ }
+
+ table td {
+ padding: 6px 13px;
+ border: 1px solid ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ color: ${cssManager.bdTheme('#1f2328', '#e6edf3')};
+ }
+
+ table tr {
+ background-color: ${cssManager.bdTheme('#ffffff', '#0d1117')};
+ border-top: 1px solid ${cssManager.bdTheme('#d1d9e0', '#21262d')};
+ }
+
+ table tr:nth-child(2n) {
+ background-color: ${cssManager.bdTheme('#f6f8fa', '#161b22')};
+ }
+
+ /* Horizontal rules */
+ hr {
+ height: 4px;
+ padding: 0;
+ margin: 24px 0;
+ background-color: ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ border: 0;
+ border-radius: 2px;
+ }
+
+ /* Images */
+ img {
+ max-width: 100%;
+ box-sizing: border-box;
+ border-radius: 6px;
+ }
+
+ /* Task lists */
+ .task-list-item {
+ list-style-type: none;
+ }
+
+ .task-list-item input {
+ margin: 0 0.2em 0.25em -1.4em;
+ vertical-align: middle;
+ }
+
+ /* Definition lists */
+ dl {
+ padding: 0;
+ }
+
+ dl dt {
+ padding: 0;
+ margin-top: 16px;
+ font-size: 1em;
+ font-style: italic;
+ font-weight: 600;
+ }
+
+ dl dd {
+ padding: 0 16px;
+ margin-bottom: 16px;
+ }
+
+ /* Keyboard input */
+ kbd {
+ display: inline-block;
+ padding: 3px 5px;
+ font-size: 11px;
+ font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
+ line-height: 10px;
+ color: ${cssManager.bdTheme('#1f2328', '#e6edf3')};
+ vertical-align: middle;
+ background-color: ${cssManager.bdTheme('#f6f8fa', '#161b22')};
+ border: 1px solid ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ border-radius: 6px;
+ box-shadow: inset 0 -1px 0 ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ }
+
+ /* Footnotes */
+ .footnotes {
+ font-size: 12px;
+ color: ${cssManager.bdTheme('#656d76', '#8b949e')};
+ border-top: 1px solid ${cssManager.bdTheme('#d1d9e0', '#30363d')};
+ padding-top: 16px;
+ margin-top: 32px;
+ }
+
+ /* Alerts/Admonitions */
+ .markdown-alert {
+ padding: 8px 16px;
+ margin-bottom: 16px;
+ border-left: 4px solid;
+ border-radius: 6px;
+ }
+
+ .markdown-alert-note {
+ border-color: ${cssManager.bdTheme('#0969da', '#58a6ff')};
+ background-color: ${cssManager.bdTheme('rgba(9, 105, 218, 0.1)', 'rgba(56, 139, 253, 0.1)')};
+ }
+
+ .markdown-alert-warning {
+ border-color: ${cssManager.bdTheme('#bf8700', '#d29922')};
+ background-color: ${cssManager.bdTheme('rgba(191, 135, 0, 0.1)', 'rgba(187, 128, 9, 0.1)')};
+ }
+
+ .markdown-alert-important {
+ border-color: ${cssManager.bdTheme('#8250df', '#a371f7')};
+ background-color: ${cssManager.bdTheme('rgba(130, 80, 223, 0.1)', 'rgba(163, 113, 247, 0.1)')};
+ }
+
+ .markdown-alert-caution {
+ border-color: ${cssManager.bdTheme('#cf222e', '#f85149')};
+ background-color: ${cssManager.bdTheme('rgba(207, 34, 46, 0.1)', 'rgba(248, 81, 73, 0.1)')};
+ }
+
+ .markdown-alert-tip {
+ border-color: ${cssManager.bdTheme('#1a7f37', '#3fb950')};
+ background-color: ${cssManager.bdTheme('rgba(26, 127, 55, 0.1)', 'rgba(46, 160, 67, 0.1)')};
+ }
+
+ /* Syntax highlighting for code blocks */
+ .hljs-comment,
+ .hljs-quote {
+ color: ${cssManager.bdTheme('#6a737d', '#8b949e')};
+ }
+
+ .hljs-keyword,
+ .hljs-selector-tag,
+ .hljs-addition {
+ color: ${cssManager.bdTheme('#d73a49', '#ff7b72')};
+ }
+
+ .hljs-number,
+ .hljs-string,
+ .hljs-meta .hljs-meta-string,
+ .hljs-literal,
+ .hljs-doctag,
+ .hljs-regexp {
+ color: ${cssManager.bdTheme('#032f62', '#a5d6ff')};
+ }
+
+ .hljs-title,
+ .hljs-section,
+ .hljs-name,
+ .hljs-selector-id,
+ .hljs-selector-class {
+ color: ${cssManager.bdTheme('#6f42c1', '#d2a8ff')};
+ }
+
+ .hljs-attribute,
+ .hljs-attr,
+ .hljs-variable,
+ .hljs-template-variable,
+ .hljs-class .hljs-title,
+ .hljs-type {
+ color: ${cssManager.bdTheme('#005cc5', '#79c0ff')};
+ }
+
+ .hljs-symbol,
+ .hljs-bullet,
+ .hljs-subst,
+ .hljs-meta,
+ .hljs-meta .hljs-keyword,
+ .hljs-selector-attr,
+ .hljs-selector-pseudo,
+ .hljs-link {
+ color: ${cssManager.bdTheme('#e36209', '#ffa657')};
+ }
+
+ .hljs-built_in,
+ .hljs-deletion {
+ color: ${cssManager.bdTheme('#b31d28', '#ffa198')};
+ }
+
+ .hljs-formula {
+ background-color: ${cssManager.bdTheme('#f6f8fa', '#161b22')};
+ }
+
+ .hljs-emphasis {
+ font-style: italic;
+ }
+
+ .hljs-strong {
+ font-weight: bold;
+ }
+ `,
+ ];
// INSTANCE
private outlet: HTMLElement;
public render(): TemplateResult {
return html`
-
-
Hi there
+
+
Markdown Preview
+
Content will appear here when markdown is parsed.
`;
}
public async firstUpdated(_changedProperties: Map
) {
await super.firstUpdated(_changedProperties);
- const styleElement = document.createElement('style');
- const cssText = await (
- await fetch('https://unpkg.com/github-markdown-css@5.1.0/github-markdown-dark.css')
- ).text();
- styleElement.textContent = cssText;
- this.shadowRoot.append(styleElement);
+ this.outlet = this.shadowRoot.querySelector('.outlet');
}
public async updateHtmlText(htmlTextArg: string) {
diff --git a/ts_web/elements/00group-workspace/dees-workspace/typescript-intellisense.ts b/ts_web/elements/00group-workspace/dees-workspace/typescript-intellisense.ts
index 41e240d..08220a5 100644
--- a/ts_web/elements/00group-workspace/dees-workspace/typescript-intellisense.ts
+++ b/ts_web/elements/00group-workspace/dees-workspace/typescript-intellisense.ts
@@ -378,7 +378,10 @@ export class TypeScriptIntelliSenseManager {
const existingModel = this.monacoInstance.editor.getModel(uri);
if (existingModel) {
- existingModel.setValue(content);
+ // Only update if content actually changed (prevents cursor reset)
+ if (existingModel.getValue() !== content) {
+ existingModel.setValue(content);
+ }
} else {
const language = this.getLanguageFromPath(path);
this.monacoInstance.editor.createModel(content, language, uri);