Polish Hedena brand, home layout, and user-app chrome.
Switch the customer app to IRANSans, restyle home featured/newest and cart note sheet, refresh brand icons across apps, and add the PWA install prompt. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Generate brand image assets from the icon-only master mark.
|
||||
* Usage (from repo root): node scripts/generate-brand-icons.mjs
|
||||
*
|
||||
* Requires: npm install sharp to-ico (dev/one-off; or already present)
|
||||
*/
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import sharp from 'sharp'
|
||||
import toIco from 'to-ico'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const root = path.resolve(__dirname, '..')
|
||||
const master = path.join(__dirname, 'brand-assets', 'hedena-icon.webp')
|
||||
|
||||
if (!fs.existsSync(master)) {
|
||||
console.error('Missing master:', master)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
async function writePng(outPath, size) {
|
||||
await fs.promises.mkdir(path.dirname(outPath), { recursive: true })
|
||||
await sharp(master)
|
||||
.resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 1 } })
|
||||
.png()
|
||||
.toFile(outPath)
|
||||
console.log('wrote', path.relative(root, outPath))
|
||||
}
|
||||
|
||||
async function writeWebp(outPath, size) {
|
||||
await fs.promises.mkdir(path.dirname(outPath), { recursive: true })
|
||||
await sharp(master)
|
||||
.resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 1 } })
|
||||
.webp({ quality: 90 })
|
||||
.toFile(outPath)
|
||||
console.log('wrote', path.relative(root, outPath))
|
||||
}
|
||||
|
||||
async function writeFull(outPath, format) {
|
||||
await fs.promises.mkdir(path.dirname(outPath), { recursive: true })
|
||||
const pipeline = sharp(master)
|
||||
if (format === 'png') await pipeline.png().toFile(outPath)
|
||||
else await pipeline.webp({ quality: 90 }).toFile(outPath)
|
||||
console.log('wrote', path.relative(root, outPath))
|
||||
}
|
||||
|
||||
async function writeIco(outPath, sizes = [16, 32, 48]) {
|
||||
const bufs = await Promise.all(
|
||||
sizes.map((s) =>
|
||||
sharp(master)
|
||||
.resize(s, s, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 1 } })
|
||||
.png()
|
||||
.toBuffer(),
|
||||
),
|
||||
)
|
||||
const ico = await toIco(bufs)
|
||||
await fs.promises.mkdir(path.dirname(outPath), { recursive: true })
|
||||
await fs.promises.writeFile(outPath, ico)
|
||||
console.log('wrote', path.relative(root, outPath))
|
||||
}
|
||||
|
||||
const userPublic = path.join(root, 'apps/user-app/public')
|
||||
const userAssets = path.join(root, 'apps/user-app/src/assets/img')
|
||||
const adminPublic = path.join(root, 'apps/admin-panel/public')
|
||||
const adminLogo = path.join(root, 'apps/admin-panel/src/assets/images/logo')
|
||||
|
||||
// Ensure adminPublic exists before writing no-items under it
|
||||
await fs.promises.mkdir(path.join(adminPublic, 'img'), { recursive: true })
|
||||
|
||||
await writeFull(path.join(userPublic, 'img/brand-logo.png'), 'png')
|
||||
await writeFull(path.join(userPublic, 'img/brand-logo.webp'), 'webp')
|
||||
await writeFull(path.join(userAssets, 'brand-logo.png'), 'png')
|
||||
|
||||
// Product / missing-image placeholder — same mark
|
||||
await writeFull(path.join(userPublic, 'img/no-items.png'), 'png')
|
||||
await writeFull(path.join(userAssets, 'no-items.png'), 'png')
|
||||
await writeFull(path.join(adminPublic, 'img/no-items.png'), 'png')
|
||||
|
||||
await writeFull(path.join(adminLogo, 'brand-icon.png'), 'png')
|
||||
await writeFull(path.join(adminLogo, 'brand-icon.webp'), 'webp')
|
||||
await writeFull(path.join(adminLogo, 'brand-horizontal.png'), 'png')
|
||||
|
||||
await writePng(path.join(userPublic, 'icon-192.png'), 192)
|
||||
await writePng(path.join(userPublic, 'icon-512.png'), 512)
|
||||
await writePng(path.join(adminPublic, 'icon-192.png'), 192)
|
||||
await writePng(path.join(adminPublic, 'icon-512.png'), 512)
|
||||
|
||||
await writePng(path.join(adminPublic, 'favicon.png'), 32)
|
||||
await writeIco(path.join(userPublic, 'favicon.ico'))
|
||||
await writeIco(path.join(adminPublic, 'favicon.ico'))
|
||||
await writeIco(path.join(adminLogo, 'favicon.ico'))
|
||||
|
||||
console.log('done')
|
||||
@@ -1,8 +1,12 @@
|
||||
"""
|
||||
Legacy Python generator — prefer scripts/generate-brand-icons.mjs when Node + sharp are available.
|
||||
|
||||
Point `src` at the icon-only master (scripts/brand-assets/hedena-icon.webp), then run from repo root.
|
||||
"""
|
||||
from PIL import Image
|
||||
from pathlib import Path
|
||||
|
||||
# Point `src` at your Hedena Gold master logo, then run from the repo root.
|
||||
src = Path(r"path/to/hedena-gold-logo.webp")
|
||||
src = Path(__file__).resolve().parent / "brand-assets" / "hedena-icon.webp"
|
||||
img = Image.open(src).convert("RGBA")
|
||||
print("source size", img.size)
|
||||
|
||||
@@ -10,10 +14,13 @@ root = Path(__file__).resolve().parents[1]
|
||||
(root / "apps/user-app/public/img").mkdir(parents=True, exist_ok=True)
|
||||
(root / "apps/user-app/src/assets/img").mkdir(parents=True, exist_ok=True)
|
||||
(root / "apps/admin-panel/src/assets/images/logo").mkdir(parents=True, exist_ok=True)
|
||||
(root / "apps/admin-panel/public").mkdir(parents=True, exist_ok=True)
|
||||
|
||||
img.save(root / "apps/user-app/public/img/brand-logo.webp", "WEBP")
|
||||
img.save(root / "apps/user-app/public/img/brand-logo.png", "PNG")
|
||||
img.save(root / "apps/user-app/src/assets/img/brand-logo.png", "PNG")
|
||||
img.save(root / "apps/user-app/public/img/no-items.png", "PNG")
|
||||
img.save(root / "apps/user-app/src/assets/img/no-items.png", "PNG")
|
||||
img.save(root / "apps/admin-panel/src/assets/images/logo/brand-icon.webp", "WEBP")
|
||||
img.save(root / "apps/admin-panel/src/assets/images/logo/brand-icon.png", "PNG")
|
||||
img.save(root / "apps/admin-panel/src/assets/images/logo/brand-horizontal.png", "PNG")
|
||||
@@ -23,8 +30,9 @@ for size, path in [
|
||||
(512, root / "apps/user-app/public/icon-512.png"),
|
||||
(192, root / "apps/admin-panel/public/icon-192.png"),
|
||||
(512, root / "apps/admin-panel/public/icon-512.png"),
|
||||
(32, root / "apps/admin-panel/public/favicon.png"),
|
||||
]:
|
||||
icon = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||
icon = Image.new("RGBA", (size, size), (0, 0, 0, 255))
|
||||
fitted = img.copy()
|
||||
fitted.thumbnail((size, size), Image.Resampling.LANCZOS)
|
||||
x = (size - fitted.width) // 2
|
||||
@@ -32,3 +40,5 @@ for size, path in [
|
||||
icon.paste(fitted, (x, y), fitted)
|
||||
icon.save(path, "PNG")
|
||||
print("wrote", path)
|
||||
|
||||
print("Note: favicon.ico is generated by scripts/generate-brand-icons.mjs (to-ico).")
|
||||
|
||||
Reference in New Issue
Block a user