Files
catalog/ts_web/elements/sg-install-snippet.ts

153 lines
4.6 KiB
TypeScript

import {
DeesElement,
customElement,
html,
property,
css,
cssManager,
type TemplateResult,
} from '@design.estate/dees-element';
import type { TSgProtocol } from '../interfaces.js';
declare global {
interface HTMLElementTagNameMap {
'sg-install-snippet': SgInstallSnippet;
}
}
@customElement('sg-install-snippet')
export class SgInstallSnippet extends DeesElement {
public static demo = () => html`
<div style="display: flex; flex-direction: column; gap: 16px; max-width: 500px;">
<sg-install-snippet .protocol=${'npm'} .packageName=${'@myorg/mypackage'}></sg-install-snippet>
<sg-install-snippet .protocol=${'oci'} .packageName=${'myorg/myimage'} .registryUrl=${'registry.stack.gallery'}></sg-install-snippet>
<sg-install-snippet .protocol=${'pypi'} .packageName=${'mypackage'} .registryUrl=${'registry.stack.gallery'}></sg-install-snippet>
<sg-install-snippet .protocol=${'cargo'} .packageName=${'mypackage'}></sg-install-snippet>
</div>
`;
public static demoGroups = ['Packages'];
@property({ type: String })
accessor protocol: TSgProtocol = 'npm';
@property({ type: String })
accessor packageName: string = '';
@property({ type: String })
accessor registryUrl: string = '';
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
}
.snippet {
background: ${cssManager.bdTheme('#f5f5f5', '#111')};
border: 1px solid ${cssManager.bdTheme('#e5e5e5', '#333')};
padding: 12px 16px;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
color: ${cssManager.bdTheme('#333', '#e5e5e5')};
position: relative;
overflow-x: auto;
white-space: nowrap;
}
.label {
font-size: 11px;
color: ${cssManager.bdTheme('#999', '#666')};
margin-bottom: 4px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.copy-btn {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
background: ${cssManager.bdTheme('#e5e5e5', '#333')};
border: none;
padding: 4px 8px;
cursor: pointer;
font-size: 11px;
color: ${cssManager.bdTheme('#666', '#999')};
}
.copy-btn:hover {
background: ${cssManager.bdTheme('#ddd', '#444')};
}
`,
];
private getInstallCommand(): { label: string; command: string } {
const reg = this.registryUrl;
switch (this.protocol) {
case 'npm':
return {
label: 'npm',
command: reg
? `npm install ${this.packageName} --registry=https://${reg}`
: `npm install ${this.packageName}`,
};
case 'oci':
return {
label: 'Docker / OCI',
command: reg
? `docker pull ${reg}/${this.packageName}`
: `docker pull ${this.packageName}`,
};
case 'maven':
return {
label: 'Maven',
command: `<dependency>\n <groupId>${this.packageName.split('/')[0] || ''}</groupId>\n <artifactId>${this.packageName.split('/')[1] || this.packageName}</artifactId>\n</dependency>`,
};
case 'cargo':
return {
label: 'Cargo',
command: `cargo add ${this.packageName}`,
};
case 'pypi':
return {
label: 'pip',
command: reg
? `pip install ${this.packageName} --index-url https://${reg}/simple/`
: `pip install ${this.packageName}`,
};
case 'composer':
return {
label: 'Composer',
command: `composer require ${this.packageName}`,
};
case 'rubygems':
return {
label: 'gem',
command: reg
? `gem install ${this.packageName} --source https://${reg}`
: `gem install ${this.packageName}`,
};
default:
return { label: this.protocol, command: this.packageName };
}
}
private async copyToClipboard() {
const { command } = this.getInstallCommand();
try {
await navigator.clipboard.writeText(command);
} catch {
// Fallback for browsers without clipboard API
}
}
public render(): TemplateResult {
const { label, command } = this.getInstallCommand();
return html`
<div class="label">${label}</div>
<div class="snippet">
<code>${command}</code>
<button class="copy-btn" @click=${() => this.copyToClipboard()}>Copy</button>
</div>
`;
}
}