Initial commit: scaffold stack.gallery catalog frontend
This commit is contained in:
152
ts_web/elements/sg-install-snippet.ts
Normal file
152
ts_web/elements/sg-install-snippet.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
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>
|
||||
`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user