feat: implement @repo/brand package for centralized asset management and automated distribution to consuming apps
This commit is contained in:
@@ -33,6 +33,9 @@ dist-ssr
|
||||
server/dist
|
||||
public/dist
|
||||
|
||||
# Auto-generated brand assets (copied from @repo/brand)
|
||||
**/public/brand/
|
||||
|
||||
# Storybook Build Outputs
|
||||
*storybook.log
|
||||
storybook-static
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/brand/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Eigen — Company Profile</title>
|
||||
<meta name="description" content="Eigen — Enterprise-grade solutions for modern businesses. Discover our products, services, and vision." />
|
||||
<meta
|
||||
name="description"
|
||||
content="Eigen — Enterprise-grade solutions for modern businesses. Discover our products, services, and vision."
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --clearScreen false",
|
||||
"build": "tsc && vite build",
|
||||
"copy:brand": "node ../../packages/brand/scripts/copy-brand-assets.js",
|
||||
"dev": "pnpm run copy:brand && vite --clearScreen false",
|
||||
"build": "pnpm run copy:brand && tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint \"src/**/*.ts\"",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@repo/brand": "workspace:*",
|
||||
"@repo/core-api": "workspace:*",
|
||||
"@repo/core-i18n": "workspace:*",
|
||||
"@repo/core-storage": "workspace:*",
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<html lang="en" translate="no">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/brand/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="google" content="notranslate" />
|
||||
<title>Applications</title>
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --clearScreen false",
|
||||
"build": "tsc && vite build",
|
||||
"copy:brand": "node ../../packages/brand/scripts/copy-brand-assets.js",
|
||||
"dev": "pnpm run copy:brand && vite --clearScreen false",
|
||||
"build": "pnpm run copy:brand && tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint \"src/**/*.ts\"",
|
||||
"test": "vitest run",
|
||||
@@ -14,6 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.0.1",
|
||||
"@repo/brand": "workspace:*",
|
||||
"@repo/core-api": "workspace:*",
|
||||
"@repo/core-events": "workspace:*",
|
||||
"@repo/core-i18n": "workspace:*",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="32" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path fill="#007ACC" d="M0 128v128h256V0H0z"></path><path fill="#FFF" d="m56.612 128.85l-.081 10.483h33.32v94.68h23.568v-94.68h33.321v-10.28c0-5.69-.122-10.444-.284-10.566c-.122-.162-20.4-.244-44.983-.203l-44.74.122l-.121 10.443Zm149.955-10.742c6.501 1.625 11.459 4.51 16.01 9.224c2.357 2.52 5.851 7.111 6.136 8.208c.08.325-11.053 7.802-17.798 11.988c-.244.162-1.22-.894-2.317-2.52c-3.291-4.795-6.745-6.867-12.028-7.233c-7.76-.528-12.759 3.535-12.718 10.321c0 1.992.284 3.17 1.097 4.795c1.707 3.536 4.876 5.649 14.832 9.956c18.326 7.883 26.168 13.084 31.045 20.48c5.445 8.249 6.664 21.415 2.966 31.208c-4.063 10.646-14.14 17.879-28.323 20.276c-4.388.772-14.79.65-19.504-.203c-10.28-1.828-20.033-6.908-26.047-13.572c-2.357-2.6-6.949-9.387-6.664-9.874c.122-.163 1.178-.813 2.356-1.504c1.138-.65 5.446-3.129 9.509-5.485l7.355-4.267l1.544 2.276c2.154 3.29 6.867 7.801 9.712 9.305c8.167 4.307 19.383 3.698 24.909-1.26c2.357-2.153 3.332-4.388 3.332-7.68c0-2.966-.366-4.266-1.91-6.501c-1.99-2.845-6.054-5.242-17.595-10.24c-13.206-5.69-18.895-9.224-24.096-14.832c-3.007-3.25-5.852-8.452-7.03-12.8c-.975-3.617-1.22-12.678-.447-16.335c2.723-12.76 12.353-21.659 26.25-24.3c4.51-.853 14.994-.528 19.424.569Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,32 @@
|
||||
# @repo/brand
|
||||
|
||||
This package serves as the single source of truth for our brand identity, containing static visual assets (logos, favicons) and brand information.
|
||||
|
||||
## 📁 Public Assets
|
||||
|
||||
Place your raw, static brand assets inside the `public/` directory:
|
||||
|
||||
- **`logo.png`** — Primary brand logo
|
||||
- **`favicon.svg`** — Browser favicon
|
||||
|
||||
### How Assets are Distributed
|
||||
|
||||
Due to monorepo constraints, frameworks like Vite or Next.js do not natively serve static assets from external packages. To solve this, these files are automatically copied into the consuming apps' `public/brand/` directories via the `scripts/copy-brand-assets.js` script.
|
||||
|
||||
This makes them directly available in the browser at:
|
||||
- `/brand/logo.png`
|
||||
- `/brand/favicon.svg`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Usage in Consuming Apps
|
||||
|
||||
### 1. Automate the Copy Process
|
||||
To ensure the consuming app always has the latest brand assets, add the copy script to the app's `package.json` (e.g., in `apps/web/package.json`):
|
||||
|
||||
```json
|
||||
"scripts": {
|
||||
"copy:brand": "node ../../packages/brand/scripts/copy-brand-assets.js",
|
||||
"dev": "pnpm run copy:brand && vite --clearScreen false",
|
||||
"build": "pnpm run copy:brand && tsc && vite build"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@repo/brand",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./public/*": "./public/*"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@repo/typescript-config": "workspace:*",
|
||||
"typescript": "5.5.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Blok Utama (Brand Color) -->
|
||||
<rect x="6" y="6" width="16" height="16" rx="4" fill="#652ed9"/>
|
||||
<!-- Blok Sekunder (Memberikan kesan struktur & kedalaman) -->
|
||||
<rect x="18" y="18" width="16" height="16" rx="4" fill="#652ed9" fill-opacity="0.6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 359 B |
@@ -0,0 +1,31 @@
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
// Resolve the source directory (packages/brand/public)
|
||||
const brandPublicDir = path.resolve(__dirname, '../public');
|
||||
|
||||
// Resolve the destination directory (public/brand folder in the calling app)
|
||||
// process.cwd() points to the app folder (e.g., apps/web) when the script is executed
|
||||
const destDir = path.resolve(process.cwd(), 'public', 'brand');
|
||||
|
||||
// Ensure the destination folder exists
|
||||
if (!fs.existsSync(destDir)) {
|
||||
fs.mkdirSync(destDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Copy files using fs.cpSync (Available in Node.js 16.7+)
|
||||
try {
|
||||
fs.cpSync(brandPublicDir, destDir, {
|
||||
recursive: true,
|
||||
force: true, // Overwrite files if they already exist
|
||||
filter: (src) => {
|
||||
const filename = path.basename(src);
|
||||
// Exclude unwanted files
|
||||
return !['.gitkeep', 'README.md'].includes(filename);
|
||||
},
|
||||
});
|
||||
console.log(`✓ Brand assets successfully copied to ${destDir}`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to copy brand assets:`, error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "My Brand",
|
||||
"description": "A short description of your brand or product.",
|
||||
"tagline": "Building the future, one pixel at a time.",
|
||||
"socialLinks": {
|
||||
"twitter": "https://twitter.com/mybrand",
|
||||
"github": "https://github.com/mybrand",
|
||||
"website": "https://mybrand.com"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import brandInfo from './data/info.json';
|
||||
|
||||
export type BrandInfo = typeof brandInfo;
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "@repo/typescript-config/library.json",
|
||||
"include": ["."],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Generated
+41
-1
@@ -88,6 +88,9 @@ importers:
|
||||
|
||||
apps/landing:
|
||||
dependencies:
|
||||
'@repo/brand':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/brand
|
||||
'@repo/core-api':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/core-api
|
||||
@@ -243,6 +246,9 @@ importers:
|
||||
'@hookform/resolvers':
|
||||
specifier: ^5.0.1
|
||||
version: 5.4.0(react-hook-form@7.79.0)
|
||||
'@repo/brand':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/brand
|
||||
'@repo/core-api':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/core-api
|
||||
@@ -329,6 +335,15 @@ importers:
|
||||
specifier: ^4.0.17
|
||||
version: 4.0.17(jsdom@26.1.0)
|
||||
|
||||
packages/brand:
|
||||
devDependencies:
|
||||
'@repo/typescript-config':
|
||||
specifier: workspace:*
|
||||
version: link:../configs/typescript
|
||||
typescript:
|
||||
specifier: 5.5.4
|
||||
version: 5.5.4
|
||||
|
||||
packages/configs/eslint:
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
@@ -7444,6 +7459,18 @@ packages:
|
||||
dependencies:
|
||||
picomatch: 4.0.3
|
||||
|
||||
/fdir@6.5.0(picomatch@4.0.5):
|
||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
peerDependencies:
|
||||
picomatch: ^3 || ^4
|
||||
peerDependenciesMeta:
|
||||
picomatch:
|
||||
optional: true
|
||||
dependencies:
|
||||
picomatch: 4.0.5
|
||||
dev: false
|
||||
|
||||
/fetch-cookie@2.2.0:
|
||||
resolution: {integrity: sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==}
|
||||
dependencies:
|
||||
@@ -9989,6 +10016,11 @@ packages:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
/picomatch@4.0.5:
|
||||
resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/plist@3.1.0:
|
||||
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
|
||||
engines: {node: '>=10.4.0'}
|
||||
@@ -11252,7 +11284,7 @@ packages:
|
||||
is-plain-obj: 4.1.0
|
||||
semver: 7.7.1
|
||||
sort-object-keys: 2.0.1
|
||||
tinyglobby: 0.2.15
|
||||
tinyglobby: 0.2.17
|
||||
dev: false
|
||||
|
||||
/source-map-js@1.2.1:
|
||||
@@ -11627,6 +11659,14 @@ packages:
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
|
||||
/tinyglobby@0.2.17:
|
||||
resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
dependencies:
|
||||
fdir: 6.5.0(picomatch@4.0.5)
|
||||
picomatch: 4.0.5
|
||||
dev: false
|
||||
|
||||
/tinyrainbow@3.0.3:
|
||||
resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
Reference in New Issue
Block a user