153 lines
4.6 KiB
TypeScript
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>
|
|
`;
|
|
}
|
|
}
|