
3D Extruded Buildings & Urban Footprints
Real-world 3D building extrusions with dynamic sunlight shadows, terrain DEM elevations, and pitch/bearing camera controls.
B2B cross-border commercial invoice generator with HTS tariff codes, EORI tax identifiers, and CIF valuation totals.
Also available for React ->$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/commercial-invoice-generator.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/commercial-invoice-generator.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/commercial-invoice-generator.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/commercial-invoice-generator.jsonnpx shadcn-vue@latest add @uipkge/commercial-invoice-generatorInstalls to:app/components/blocks/commercial-invoice-generator/| Name | Type / Values | Default | Required |
|---|---|---|---|
invoiceNumber | string | 'INV-EXP-2026-9042' | optional |
incoterms | string | 'DAP (Delivered at Place)' | optional |
currency | string | 'USD' | optional |
Type aliases exported from this item's source. Use these to shape the data you pass in.
InvoiceIteminterface InvoiceItem {
id: string
description: string
htsCode: string
countryOfOrigin: string
qty: number
unitPrice: number
weightKg: number
}<script setup lang="ts">
import { ref, computed } from 'vue'
import { Download, Plus, Printer, ShieldCheck, Trash2 } from 'lucide-vue-next'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Badge } from '@/components/ui/badge'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
export interface InvoiceItem {
id: string
description: string
htsCode: string
countryOfOrigin: string
qty: number
unitPrice: number
weightKg: number
}
export interface CommercialInvoiceProps {
invoiceNumber?: string
incoterms?: string
currency?: string
}
const props = withDefaults(defineProps<CommercialInvoiceProps>(), {
invoiceNumber: 'INV-EXP-2026-9042',
incoterms: 'DAP (Delivered at Place)',
currency: 'USD',
})
const isSigned = ref(false)
const items = ref<InvoiceItem[]>([
{
id: 'inv-1',
description: 'Precision CNC Machined Aluminum Actuator Housing',
htsCode: '8479.90.94',
countryOfOrigin: 'US',
qty: 50,
unitPrice: 185.0,
weightKg: 24.5,
},
{
id: 'inv-2',
description: 'Brushless DC High-Torque Servo Motor 48V',
htsCode: '8501.31.20',
countryOfOrigin: 'DE',
qty: 25,
unitPrice: 320.0,
weightKg: 31.0,
},
{
id: 'inv-3',
description: 'Industrial Polyurethane Seal Gasket Kit',
htsCode: '3926.90.99',
countryOfOrigin: 'JP',
qty: 100,
unitPrice: 14.5,
weightKg: 4.2,
},
])
const subtotal = computed(() => items.value.reduce((sum, item) => sum + item.qty * item.unitPrice, 0))
const totalWeightKg = computed(() => items.value.reduce((sum, item) => sum + item.weightKg, 0))
const freightCharges = ref(450.0)
const insuranceCharges = ref(85.0)
const grandTotal = computed(() => subtotal.value + freightCharges.value + insuranceCharges.value)
function addItem() {
items.value.push({
id: `inv-${Date.now()}`,
description: 'General Industrial Hardware / Fasteners',
htsCode: '7318.15.20',
countryOfOrigin: 'US',
qty: 10,
unitPrice: 25.0,
weightKg: 2.0,
})
}
function removeItem(id: string) {
items.value = items.value.filter((i) => i.id !== id)
}
</script>
<template>
<div data-slot="commercial-invoice-generator" class="w-full space-y-6">
<!-- Top Action Card -->
<Card>
<CardHeader class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div class="space-y-1">
<div class="flex items-center gap-2">
<span class="text-foreground font-mono text-sm font-semibold">{{ invoiceNumber }}</span>
<Badge variant="outline">{{ incoterms }}</Badge>
<Badge :variant="isSigned ? 'default' : 'secondary'">
{{ isSigned ? 'Customs Declared & Sealed' : 'Draft Declaration' }}
</Badge>
</div>
<CardTitle class="text-xl">International Commercial Customs Invoice</CardTitle>
<CardDescription>
Harmonized Tariff Schedule (HTS) compliance declaration for international customs clearance.
</CardDescription>
</div>
<div class="flex items-center gap-2">
<Button variant="outline" size="sm" class="gap-1.5">
<Printer class="size-3.5" />
Print Form
</Button>
<Button variant="outline" size="sm" class="gap-1.5">
<Download class="size-3.5" />
Export EDI / PDF
</Button>
<Button v-if="!isSigned" variant="default" size="sm" class="gap-1.5" @click="isSigned = true">
<ShieldCheck class="size-3.5" />
Sign Customs Declaration
</Button>
<Button v-else variant="secondary" size="sm" class="gap-1.5" @click="isSigned = false"> Unlock Edit </Button>
</div>
</CardHeader>
<CardContent class="border-border grid grid-cols-1 gap-6 border-t pt-4 sm:grid-cols-2">
<!-- Exporter / Shipper -->
<div class="border-border space-y-1 rounded-lg border p-3">
<div class="text-muted-foreground text-xs font-semibold">EXPORTER / SHIPPER (CONSIGNOR)</div>
<div class="text-foreground text-sm font-medium">Global Aerospace Components Inc.</div>
<div class="text-muted-foreground text-xs">9400 Aeronautics Way, Dock 4</div>
<div class="text-muted-foreground text-xs">Seattle, WA 98108, United States</div>
<div class="text-muted-foreground pt-1 font-mono text-xs">EORI / Tax ID: US-EIN-98441029</div>
</div>
<!-- Importer / Consignee -->
<div class="border-border space-y-1 rounded-lg border p-3">
<div class="text-muted-foreground text-xs font-semibold">IMPORTER / BUYER (CONSIGNEE)</div>
<div class="text-foreground text-sm font-medium">Nordic Robotics Systems AB</div>
<div class="text-muted-foreground text-xs">Industrigatan 18, Byggnad B</div>
<div class="text-muted-foreground text-xs">SE-417 56 Göteborg, Sweden</div>
<div class="text-muted-foreground pt-1 font-mono text-xs">VAT / EORI: SE556012345601</div>
</div>
</CardContent>
</Card>
<!-- Line Items Table -->
<Card>
<CardHeader class="flex flex-col gap-3 pb-3 sm:flex-row sm:items-center sm:justify-between">
<div>
<CardTitle class="text-base font-semibold">Customs Line Item Breakdown</CardTitle>
<CardDescription>
Total Gross Net Weight: <span class="font-mono">{{ totalWeightKg.toFixed(1) }} kg</span> · Currency:
{{ currency }}
</CardDescription>
</div>
<Button v-if="!isSigned" variant="outline" size="sm" class="gap-1.5" @click="addItem">
<Plus class="size-3.5" />
Add Line Item
</Button>
</CardHeader>
<CardContent class="p-0">
<Table>
<TableHeader>
<TableRow>
<TableHead class="w-[300px]">Goods Description</TableHead>
<TableHead>HTS / Tariff Code</TableHead>
<TableHead>Origin (COO)</TableHead>
<TableHead class="text-right">Net Wt (kg)</TableHead>
<TableHead class="w-[90px] text-right">Qty</TableHead>
<TableHead class="w-[120px] text-right">Unit Price</TableHead>
<TableHead class="text-right">Customs Total</TableHead>
<TableHead v-if="!isSigned" class="w-[40px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="item in items" :key="item.id">
<!-- Description -->
<TableCell>
<Input v-if="!isSigned" v-model="item.description" class="h-8 text-xs" />
<span v-else class="text-foreground font-medium">{{ item.description }}</span>
</TableCell>
<!-- HTS Code -->
<TableCell>
<Input v-if="!isSigned" v-model="item.htsCode" class="h-8 w-28 font-mono text-xs" />
<span v-else class="font-mono text-xs font-semibold">{{ item.htsCode }}</span>
</TableCell>
<!-- Country of Origin -->
<TableCell>
<Input
v-if="!isSigned"
v-model="item.countryOfOrigin"
class="h-8 w-16 text-center font-mono text-xs uppercase"
/>
<span v-else class="bg-muted rounded px-1.5 py-0.5 font-mono text-xs font-medium">{{
item.countryOfOrigin
}}</span>
</TableCell>
<!-- Net Weight -->
<TableCell class="text-right">
<Input
v-if="!isSigned"
v-model.number="item.weightKg"
type="number"
step="0.1"
class="h-8 text-right font-mono text-xs"
/>
<span v-else class="text-muted-foreground font-mono text-xs">{{ item.weightKg.toFixed(1) }}</span>
</TableCell>
<!-- Qty -->
<TableCell class="text-right">
<Input
v-if="!isSigned"
v-model.number="item.qty"
type="number"
min="1"
class="h-8 text-right font-mono text-xs"
/>
<span v-else class="font-mono text-sm">{{ item.qty }}</span>
</TableCell>
<!-- Unit Price -->
<TableCell class="text-right">
<Input
v-if="!isSigned"
v-model.number="item.unitPrice"
type="number"
step="0.01"
class="h-8 text-right font-mono text-xs"
/>
<span v-else class="font-mono text-sm">${{ item.unitPrice.toFixed(2) }}</span>
</TableCell>
<!-- Line Total -->
<TableCell class="text-foreground text-right font-mono text-sm font-semibold">
${{ (item.qty * item.unitPrice).toFixed(2) }}
</TableCell>
<!-- Delete -->
<TableCell v-if="!isSigned">
<Button
variant="ghost"
size="icon"
class="text-muted-foreground hover:text-destructive size-8"
@click="removeItem(item.id)"
>
<Trash2 class="size-3.5" />
</Button>
</TableCell>
</TableRow>
</TableBody>
</Table>
</CardContent>
<!-- Totals & Tariff Summary Footer -->
<CardFooter class="border-border flex flex-col gap-4 border-t pt-4 sm:flex-row sm:items-start sm:justify-between">
<div class="text-muted-foreground space-y-1 text-xs sm:max-w-md">
<p class="text-foreground font-medium">Exporter Declaration & Legal Certification:</p>
<p>
I hereby certify that the information on this invoice is true and correct and that the contents of this
shipment are as stated above.
</p>
</div>
<div class="w-full space-y-1.5 sm:w-72">
<div class="text-muted-foreground flex justify-between text-xs">
<span>FOB Line Subtotal:</span>
<span class="text-foreground font-mono font-medium">${{ subtotal.toFixed(2) }}</span>
</div>
<div class="text-muted-foreground flex justify-between text-xs">
<span>International Freight (Air):</span>
<span class="text-foreground font-mono font-medium">${{ freightCharges.toFixed(2) }}</span>
</div>
<div class="text-muted-foreground flex justify-between text-xs">
<span>Cargo Marine Insurance:</span>
<span class="text-foreground font-mono font-medium">${{ insuranceCharges.toFixed(2) }}</span>
</div>
<div class="border-border text-foreground flex justify-between border-t pt-2 text-sm font-semibold">
<span>Declared CIF Value:</span>
<span class="font-mono text-base font-bold">${{ grandTotal.toFixed(2) }} USD</span>
</div>
</div>
</CardFooter>
</Card>
</div>
</template>
export { default as CommercialInvoiceGenerator } from './CommercialInvoiceGenerator.vue'
export type { InvoiceItem, CommercialInvoiceProps } from './CommercialInvoiceGenerator.vue'
Raw manifest:https://uipkge.dev/r/vue/commercial-invoice-generator.json