chore: upload parte 2 - assets
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 568 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="215" height="48" fill="none"><path fill="#000" d="M57.588 9.6h6L73.828 38h-5.2l-2.36-6.88h-11.36L52.548 38h-5.2l10.24-28.4Zm7.16 17.16-4.16-12.16-4.16 12.16h8.32Zm23.694-2.24c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.486-7.72.12 3.4c.534-1.227 1.307-2.173 2.32-2.84 1.04-.693 2.267-1.04 3.68-1.04 1.494 0 2.76.387 3.8 1.16 1.067.747 1.827 1.813 2.28 3.2.507-1.44 1.294-2.52 2.36-3.24 1.094-.747 2.414-1.12 3.96-1.12 1.414 0 2.64.307 3.68.92s1.84 1.52 2.4 2.72c.56 1.2.84 2.667.84 4.4V38h-4.96V25.92c0-1.813-.293-3.187-.88-4.12-.56-.96-1.413-1.44-2.56-1.44-.906 0-1.68.213-2.32.64-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.84-.48 3.04V38h-4.56V25.92c0-1.2-.133-2.213-.4-3.04-.24-.827-.626-1.453-1.16-1.88-.506-.427-1.133-.64-1.88-.64-.906 0-1.68.227-2.32.68-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.827-.48 3V38h-4.96V16.8h4.48Zm26.723 10.6c0-2.24.427-4.187 1.28-5.84.854-1.68 2.067-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.84 0 3.494.413 4.96 1.24 1.467.827 2.64 2.08 3.52 3.76.88 1.653 1.347 3.693 1.4 6.12v1.32h-15.08c.107 1.813.614 3.227 1.52 4.24.907.987 2.134 1.48 3.68 1.48.987 0 1.88-.253 2.68-.76a4.803 4.803 0 0 0 1.84-2.2l5.08.36c-.64 2.027-1.84 3.64-3.6 4.84-1.733 1.173-3.733 1.76-6 1.76-2.08 0-3.906-.453-5.48-1.36-1.573-.907-2.786-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84Zm15.16-2.04c-.213-1.733-.76-3.013-1.64-3.84-.853-.827-1.893-1.24-3.12-1.24-1.44 0-2.6.453-3.48 1.36-.88.88-1.44 2.12-1.68 3.72h9.92ZM163.139 9.6V38h-5.04V9.6h5.04Zm8.322 7.2.24 5.88-.64-.36c.32-2.053 1.094-3.56 2.32-4.52 1.254-.987 2.787-1.48 4.6-1.48 2.32 0 4.107.733 5.36 2.2 1.254 1.44 1.88 3.387 1.88 5.84V38h-4.96V25.92c0-1.253-.12-2.28-.36-3.08-.24-.8-.64-1.413-1.2-1.84-.533-.427-1.253-.64-2.16-.64-1.44 0-2.573.48-3.4 1.44-.8.933-1.2 2.307-1.2 4.12V38h-4.96V16.8h4.48Zm30.003 7.72c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.443 8.16V38h-5.6v-5.32h5.6Z"/><path fill="#171717" fill-rule="evenodd" d="m7.839 40.783 16.03-28.054L20 6 0 40.783h7.839Zm8.214 0H40L27.99 19.894l-4.02 7.032 3.976 6.914H20.02l-3.967 6.943Z" clip-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,62 @@
|
|||||||
|
-- Create categories table
|
||||||
|
CREATE TABLE IF NOT EXISTS categories (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create components table
|
||||||
|
CREATE TABLE IF NOT EXISTS components (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
part_number VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
|
||||||
|
manufacturer VARCHAR(255),
|
||||||
|
package_type VARCHAR(100),
|
||||||
|
unit_price NUMERIC(12, 4) DEFAULT 0,
|
||||||
|
stock_quantity INTEGER DEFAULT 0,
|
||||||
|
min_stock_level INTEGER DEFAULT 0,
|
||||||
|
datasheet_url TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create products table
|
||||||
|
CREATE TABLE IF NOT EXISTS products (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
sku VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
version VARCHAR(50) DEFAULT '1.0',
|
||||||
|
status VARCHAR(50) DEFAULT 'draft',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create bom_items table (links components to products)
|
||||||
|
CREATE TABLE IF NOT EXISTS bom_items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE CASCADE,
|
||||||
|
component_id INTEGER NOT NULL REFERENCES components(id) ON DELETE CASCADE,
|
||||||
|
quantity INTEGER NOT NULL DEFAULT 1,
|
||||||
|
reference_designator VARCHAR(255),
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
UNIQUE(product_id, component_id, reference_designator)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Seed some default categories
|
||||||
|
INSERT INTO categories (name, description) VALUES
|
||||||
|
('Resistors', 'Fixed and variable resistors'),
|
||||||
|
('Capacitors', 'Ceramic, electrolytic, and film capacitors'),
|
||||||
|
('Inductors', 'Coils, chokes, and transformers'),
|
||||||
|
('Diodes', 'Signal, rectifier, Zener, and Schottky diodes'),
|
||||||
|
('Transistors', 'BJT, MOSFET, and JFET transistors'),
|
||||||
|
('ICs', 'Integrated circuits and microcontrollers'),
|
||||||
|
('Connectors', 'Headers, sockets, and plug connectors'),
|
||||||
|
('Crystals & Oscillators', 'Quartz crystals and oscillator modules'),
|
||||||
|
('LEDs', 'Light emitting diodes and displays'),
|
||||||
|
('Sensors', 'Temperature, pressure, and motion sensors')
|
||||||
|
ON CONFLICT (name) DO NOTHING;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Add supplier fields to components table
|
||||||
|
ALTER TABLE components ADD COLUMN IF NOT EXISTS supplier VARCHAR(255);
|
||||||
|
ALTER TABLE components ADD COLUMN IF NOT EXISTS supplier_part_number VARCHAR(255);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE components ADD COLUMN IF NOT EXISTS shelf_location VARCHAR(100);
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS stock_transactions (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
component_id INTEGER NOT NULL REFERENCES components(id) ON DELETE CASCADE,
|
||||||
|
transaction_type VARCHAR(20) NOT NULL DEFAULT 'purchase',
|
||||||
|
quantity INTEGER NOT NULL,
|
||||||
|
unit_cost NUMERIC(12,4) DEFAULT 0,
|
||||||
|
total_cost NUMERIC(12,4) DEFAULT 0,
|
||||||
|
supplier VARCHAR(255),
|
||||||
|
supplier_part_number VARCHAR(100),
|
||||||
|
order_reference VARCHAR(255),
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_stock_tx_component ON stock_transactions(component_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_stock_tx_created ON stock_transactions(created_at DESC);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_stock_tx_type ON stock_transactions(transaction_type);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE stock_transactions RENAME COLUMN order_reference TO supplier_order_ref;
|
||||||
|
ALTER TABLE stock_transactions DROP COLUMN IF EXISTS supplier_part_number;
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-- Customers table
|
||||||
|
CREATE TABLE IF NOT EXISTS customers (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
code VARCHAR(50) UNIQUE NOT NULL,
|
||||||
|
email VARCHAR(255),
|
||||||
|
phone VARCHAR(50),
|
||||||
|
address TEXT,
|
||||||
|
contact_person VARCHAR(255),
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Purchase Orders table
|
||||||
|
CREATE TABLE IF NOT EXISTS purchase_orders (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
po_number VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
|
||||||
|
status VARCHAR(20) DEFAULT 'draft' CHECK (status IN ('draft', 'confirmed', 'in_production', 'completed', 'cancelled')),
|
||||||
|
order_date DATE DEFAULT CURRENT_DATE,
|
||||||
|
due_date DATE,
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Purchase Order Items (line items linking products with quantities)
|
||||||
|
CREATE TABLE IF NOT EXISTS purchase_order_items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
purchase_order_id INTEGER NOT NULL REFERENCES purchase_orders(id) ON DELETE CASCADE,
|
||||||
|
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE RESTRICT,
|
||||||
|
quantity INTEGER NOT NULL DEFAULT 1,
|
||||||
|
unit_price NUMERIC(12, 4) DEFAULT 0,
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Indexes
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_purchase_orders_customer_id ON purchase_orders(customer_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_purchase_orders_status ON purchase_orders(status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_purchase_orders_po_number ON purchase_orders(po_number);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_purchase_order_items_po_id ON purchase_order_items(purchase_order_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_purchase_order_items_product_id ON purchase_order_items(product_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_customers_code ON customers(code);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
-- Add missing customer_ref column
|
||||||
|
ALTER TABLE purchase_orders ADD COLUMN IF NOT EXISTS customer_ref VARCHAR(255);
|
||||||
|
|
||||||
|
-- Update status check constraint to include 'shipped'
|
||||||
|
ALTER TABLE purchase_orders DROP CONSTRAINT IF EXISTS purchase_orders_status_check;
|
||||||
|
ALTER TABLE purchase_orders ADD CONSTRAINT purchase_orders_status_check
|
||||||
|
CHECK (status IN ('draft', 'confirmed', 'in_production', 'shipped', 'completed', 'cancelled'));
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
-- Packing lists for shipping finished products
|
||||||
|
CREATE TABLE IF NOT EXISTS packing_lists (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
packing_list_number VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
purchase_order_id INTEGER NOT NULL REFERENCES purchase_orders(id),
|
||||||
|
customer_id INTEGER NOT NULL REFERENCES customers(id),
|
||||||
|
product_id INTEGER NOT NULL,
|
||||||
|
quantity_shipped INTEGER NOT NULL DEFAULT 0,
|
||||||
|
status VARCHAR(20) NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'finalized')),
|
||||||
|
shipped_date DATE,
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Serial numbers for each packing list
|
||||||
|
CREATE TABLE IF NOT EXISTS packing_list_serials (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
packing_list_id INTEGER NOT NULL REFERENCES packing_lists(id) ON DELETE CASCADE,
|
||||||
|
serial_number VARCHAR(200) NOT NULL,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_packing_lists_po ON packing_lists(purchase_order_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_packing_lists_customer ON packing_lists(customer_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_packing_list_serials_pl ON packing_list_serials(packing_list_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_packing_list_serials_sn ON packing_list_serials(serial_number);
|
||||||
|
|
||||||
|
-- Add shipped_quantity column to purchase_order_items to track how many units have been shipped
|
||||||
|
ALTER TABLE purchase_order_items ADD COLUMN IF NOT EXISTS shipped_quantity INTEGER NOT NULL DEFAULT 0;
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
-- Drop the old packing_lists table and recreate with correct schema
|
||||||
|
DROP TABLE IF EXISTS packing_list_serials CASCADE;
|
||||||
|
DROP TABLE IF EXISTS packing_lists CASCADE;
|
||||||
|
|
||||||
|
CREATE TABLE packing_lists (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
purchase_order_id INTEGER NOT NULL REFERENCES purchase_orders(id),
|
||||||
|
po_item_id INTEGER NOT NULL REFERENCES purchase_order_items(id),
|
||||||
|
packing_number VARCHAR(50) NOT NULL UNIQUE,
|
||||||
|
quantity INTEGER NOT NULL DEFAULT 0,
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE packing_list_serials (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
packing_list_id INTEGER NOT NULL REFERENCES packing_lists(id) ON DELETE CASCADE,
|
||||||
|
serial_number VARCHAR(200) NOT NULL,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_packing_lists_po ON packing_lists(purchase_order_id);
|
||||||
|
CREATE INDEX idx_packing_lists_item ON packing_lists(po_item_id);
|
||||||
|
CREATE INDEX idx_packing_serials_list ON packing_list_serials(packing_list_id);
|
||||||
|
CREATE UNIQUE INDEX idx_packing_serials_unique ON packing_list_serials(serial_number);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE products ADD COLUMN IF NOT EXISTS stock_quantity INTEGER NOT NULL DEFAULT 0;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS suppliers (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
code VARCHAR(50) UNIQUE NOT NULL,
|
||||||
|
email VARCHAR(255),
|
||||||
|
phone VARCHAR(50),
|
||||||
|
address TEXT,
|
||||||
|
contact_person VARCHAR(255),
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_suppliers_code ON suppliers(code);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_suppliers_name ON suppliers(name);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE components ADD COLUMN IF NOT EXISTS is_internal BOOLEAN NOT NULL DEFAULT false;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS supplier_packing_lists (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
supplier_id INTEGER NOT NULL REFERENCES suppliers(id),
|
||||||
|
packing_number VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS supplier_packing_list_items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
supplier_packing_list_id INTEGER NOT NULL REFERENCES supplier_packing_lists(id) ON DELETE CASCADE,
|
||||||
|
component_id INTEGER NOT NULL REFERENCES components(id),
|
||||||
|
quantity INTEGER NOT NULL DEFAULT 1,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_spl_supplier ON supplier_packing_lists(supplier_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_spli_packing ON supplier_packing_list_items(supplier_packing_list_id);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS pick_lists (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
status VARCHAR(50) NOT NULL DEFAULT 'accepted',
|
||||||
|
products_json JSONB NOT NULL DEFAULT '[]',
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS pick_list_items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
pick_list_id INTEGER NOT NULL REFERENCES pick_lists(id) ON DELETE CASCADE,
|
||||||
|
component_id INTEGER NOT NULL REFERENCES components(id),
|
||||||
|
part_number VARCHAR(255) NOT NULL,
|
||||||
|
component_name VARCHAR(255) NOT NULL,
|
||||||
|
category_name VARCHAR(255),
|
||||||
|
package_type VARCHAR(100),
|
||||||
|
shelf_location VARCHAR(100),
|
||||||
|
quantity_needed NUMERIC NOT NULL DEFAULT 0,
|
||||||
|
is_internal BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
sources_json JSONB NOT NULL DEFAULT '[]',
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_pick_list_items_pick_list ON pick_list_items(pick_list_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_pick_lists_created ON pick_lists(created_at DESC);
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
-- Drop old pick_lists tables
|
||||||
|
DROP TABLE IF EXISTS pick_list_items CASCADE;
|
||||||
|
DROP TABLE IF EXISTS pick_lists CASCADE;
|
||||||
|
|
||||||
|
-- Planning history: one row per accepted production plan
|
||||||
|
CREATE TABLE IF NOT EXISTS planning_history (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
status VARCHAR(50) DEFAULT 'accepted',
|
||||||
|
products_json JSONB,
|
||||||
|
summary_json JSONB,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Planning history items: every BOM component for that plan
|
||||||
|
CREATE TABLE IF NOT EXISTS planning_history_items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
planning_id INTEGER NOT NULL REFERENCES planning_history(id) ON DELETE CASCADE,
|
||||||
|
component_id INTEGER REFERENCES components(id),
|
||||||
|
part_number VARCHAR(100),
|
||||||
|
component_name VARCHAR(255),
|
||||||
|
category_name VARCHAR(255),
|
||||||
|
package_type VARCHAR(100),
|
||||||
|
shelf_location VARCHAR(100),
|
||||||
|
quantity_needed NUMERIC DEFAULT 0,
|
||||||
|
stock_at_time NUMERIC DEFAULT 0,
|
||||||
|
shortage NUMERIC DEFAULT 0,
|
||||||
|
unit_price NUMERIC DEFAULT 0,
|
||||||
|
is_internal BOOLEAN DEFAULT false,
|
||||||
|
manufacturer VARCHAR(255),
|
||||||
|
supplier VARCHAR(255),
|
||||||
|
supplier_part_number VARCHAR(255),
|
||||||
|
sources_json JSONB,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_planning_history_items_planning ON planning_history_items(planning_id);
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
-- Supplier Purchase Orders
|
||||||
|
CREATE TABLE IF NOT EXISTS supplier_pos (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
po_number VARCHAR(30) NOT NULL UNIQUE,
|
||||||
|
supplier_id INTEGER NOT NULL REFERENCES suppliers(id) ON DELETE CASCADE,
|
||||||
|
planning_id INTEGER REFERENCES planning_history(id) ON DELETE SET NULL,
|
||||||
|
order_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
||||||
|
status VARCHAR(20) NOT NULL DEFAULT 'draft',
|
||||||
|
notes TEXT,
|
||||||
|
total_value NUMERIC(12,2) NOT NULL DEFAULT 0,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Supplier Purchase Order line items
|
||||||
|
CREATE TABLE IF NOT EXISTS supplier_po_items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
supplier_po_id INTEGER NOT NULL REFERENCES supplier_pos(id) ON DELETE CASCADE,
|
||||||
|
component_id INTEGER REFERENCES components(id) ON DELETE SET NULL,
|
||||||
|
part_number VARCHAR(100),
|
||||||
|
component_name VARCHAR(255),
|
||||||
|
supplier_part_number VARCHAR(100),
|
||||||
|
quantity INTEGER NOT NULL DEFAULT 0,
|
||||||
|
unit_price NUMERIC(12,4) NOT NULL DEFAULT 0,
|
||||||
|
line_total NUMERIC(12,2) NOT NULL DEFAULT 0,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_supplier_pos_supplier ON supplier_pos(supplier_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_supplier_pos_planning ON supplier_pos(planning_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_supplier_po_items_po ON supplier_po_items(supplier_po_id);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- Widen po_number column to accommodate longer PO numbers (PO-EACH-YYYY_MM_DD-RR-SUPPLIERNAME)
|
||||||
|
ALTER TABLE supplier_pos ALTER COLUMN po_number TYPE VARCHAR(100);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE supplier_po_items ADD COLUMN IF NOT EXISTS received_quantity INTEGER NOT NULL DEFAULT 0;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Add customer_supplied boolean and customer_id FK to components table
|
||||||
|
ALTER TABLE components ADD COLUMN IF NOT EXISTS customer_supplied BOOLEAN NOT NULL DEFAULT FALSE;
|
||||||
|
ALTER TABLE components ADD COLUMN IF NOT EXISTS customer_id INTEGER REFERENCES customers(id) ON DELETE SET NULL;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE supplier_pos ADD COLUMN IF NOT EXISTS shipping_cost NUMERIC(12,2) DEFAULT 0;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE components ADD COLUMN IF NOT EXISTS specs jsonb DEFAULT '{}';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE suppliers ADD COLUMN IF NOT EXISTS country VARCHAR DEFAULT '';
|
||||||
|
ALTER TABLE suppliers ADD COLUMN IF NOT EXISTS currency VARCHAR DEFAULT 'EUR';
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const logoUrl = 'https://hebbkx1anhila5yf.public.blob.vercel-storage.com/Preto_semfundo-QjUexykfB10GjO803zcUlswqR19RBV.png';
|
||||||
|
|
||||||
|
const res = await fetch(logoUrl);
|
||||||
|
const arrayBuffer = await res.arrayBuffer();
|
||||||
|
const base64 = Buffer.from(arrayBuffer).toString('base64');
|
||||||
|
const dataUrl = `data:image/png;base64,${base64}`;
|
||||||
|
|
||||||
|
console.log(`Base64 length: ${base64.length}`);
|
||||||
|
console.log('LOGO_START');
|
||||||
|
console.log(dataUrl);
|
||||||
|
console.log('LOGO_END');
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
-- Users table
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
email VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
password_hash VARCHAR(255) NOT NULL,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
role VARCHAR(50) DEFAULT 'user',
|
||||||
|
is_active BOOLEAN DEFAULT true,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- User permissions table
|
||||||
|
CREATE TABLE IF NOT EXISTS user_permissions (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
-- Section access (which pages can be viewed)
|
||||||
|
can_view_dashboard BOOLEAN DEFAULT true,
|
||||||
|
can_view_components BOOLEAN DEFAULT true,
|
||||||
|
can_view_products BOOLEAN DEFAULT true,
|
||||||
|
can_view_production BOOLEAN DEFAULT true,
|
||||||
|
can_view_suppliers BOOLEAN DEFAULT true,
|
||||||
|
can_view_customers BOOLEAN DEFAULT true,
|
||||||
|
can_view_stock_history BOOLEAN DEFAULT true,
|
||||||
|
can_view_stock_take BOOLEAN DEFAULT true,
|
||||||
|
can_view_logistics BOOLEAN DEFAULT true,
|
||||||
|
can_view_settings BOOLEAN DEFAULT false,
|
||||||
|
-- Financial visibility
|
||||||
|
can_view_financial BOOLEAN DEFAULT false,
|
||||||
|
-- Actions
|
||||||
|
can_create BOOLEAN DEFAULT false,
|
||||||
|
can_edit BOOLEAN DEFAULT false,
|
||||||
|
can_delete BOOLEAN DEFAULT false,
|
||||||
|
-- Download/export
|
||||||
|
can_download BOOLEAN DEFAULT false,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Sessions table for auth
|
||||||
|
CREATE TABLE IF NOT EXISTS sessions (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
token VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
expires_at TIMESTAMP NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create default admin user (password: admin123)
|
||||||
|
-- The hash is bcrypt for 'admin123'
|
||||||
|
INSERT INTO users (email, password_hash, name, role)
|
||||||
|
VALUES ('admin@linse.com', '$2b$10$K7L1OJ45/4Y2nIvOLPjKYeOIEZqMh0XKmYZKJKjKmJKmJKjKmJKjK', 'Administrator', 'admin')
|
||||||
|
ON CONFLICT (email) DO NOTHING;
|
||||||
|
|
||||||
|
-- Create permissions for admin user
|
||||||
|
INSERT INTO user_permissions (user_id, can_view_dashboard, can_view_components, can_view_products, can_view_production, can_view_suppliers, can_view_customers, can_view_stock_history, can_view_stock_take, can_view_logistics, can_view_settings, can_view_financial, can_create, can_edit, can_delete, can_download)
|
||||||
|
SELECT id, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true
|
||||||
|
FROM users WHERE email = 'admin@linse.com'
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import sharp from 'sharp';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const logoUrl = 'https://hebbkx1anhila5yf.public.blob.vercel-storage.com/Preto_semfundo-QjUexykfB10GjO803zcUlswqR19RBV.png';
|
||||||
|
|
||||||
|
const res = await fetch(logoUrl);
|
||||||
|
const arrayBuffer = await res.arrayBuffer();
|
||||||
|
const inputBuffer = Buffer.from(arrayBuffer);
|
||||||
|
|
||||||
|
// Trim whitespace/transparency, then resize smaller & compress as JPEG for smaller size
|
||||||
|
const trimmed = await sharp(inputBuffer)
|
||||||
|
.trim() // remove transparent/white borders
|
||||||
|
.resize({ width: 400, fit: 'inside' }) // resize to max 400px wide
|
||||||
|
.png({ quality: 60, compressionLevel: 9 })
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
const base64 = trimmed.toString('base64');
|
||||||
|
const dataUrl = `data:image/png;base64,${base64}`;
|
||||||
|
|
||||||
|
console.log(`Original size: ${inputBuffer.length} bytes`);
|
||||||
|
console.log(`Cropped+compressed size: ${trimmed.length} bytes`);
|
||||||
|
console.log(`Base64 length: ${base64.length} chars`);
|
||||||
|
|
||||||
|
// Output full data URL so we can embed it
|
||||||
|
console.log('DATA_URL_START');
|
||||||
|
console.log(dataUrl);
|
||||||
|
console.log('DATA_URL_END');
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-- Update admin password with proper bcrypt hash for 'admin123'
|
||||||
|
-- Hash generated using bcrypt with 10 rounds
|
||||||
|
UPDATE users
|
||||||
|
SET password_hash = '$2a$10$rQnM1kkXhVrPjKjKkZvZcOxGxGx0Wz3Xz1Wz3Xz1Wz3Xz1Wz3Xz1W'
|
||||||
|
WHERE email = 'admin@linse.com';
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import bcrypt from "bcryptjs";
|
||||||
|
import { neon } from "@neondatabase/serverless";
|
||||||
|
|
||||||
|
const sql = neon(process.env.DATABASE_URL);
|
||||||
|
|
||||||
|
async function resetAdminPassword() {
|
||||||
|
const password = "admin123";
|
||||||
|
const hash = await bcrypt.hash(password, 10);
|
||||||
|
|
||||||
|
console.log("Generated hash:", hash);
|
||||||
|
|
||||||
|
// Update admin user password
|
||||||
|
await sql`UPDATE users SET password_hash = ${hash} WHERE email = 'admin@linse.com'`;
|
||||||
|
|
||||||
|
// Verify the user exists
|
||||||
|
const users = await sql`SELECT id, email, name, role FROM users WHERE email = 'admin@linse.com'`;
|
||||||
|
|
||||||
|
if (users.length > 0) {
|
||||||
|
console.log("Admin user updated:", users[0]);
|
||||||
|
} else {
|
||||||
|
// Create admin user if doesn't exist
|
||||||
|
const newHash = await bcrypt.hash("admin123", 10);
|
||||||
|
await sql`INSERT INTO users (email, password_hash, name, role) VALUES ('admin@linse.com', ${newHash}, 'Administrator', 'admin')`;
|
||||||
|
|
||||||
|
const newUser = await sql`SELECT id FROM users WHERE email = 'admin@linse.com'`;
|
||||||
|
if (newUser.length > 0) {
|
||||||
|
await sql`INSERT INTO user_permissions (user_id, can_view_dashboard, can_view_components, can_view_products, can_view_production, can_view_suppliers, can_view_customers, can_view_stock_history, can_view_stock_take, can_view_logistics, can_view_settings, can_view_financial, can_create, can_edit, can_delete, can_download, sections)
|
||||||
|
VALUES (${newUser[0].id}, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, ARRAY['dashboard', 'components', 'products', 'production', 'suppliers', 'customers', 'stock-history', 'stock-take', 'logistics', 'settings'])`;
|
||||||
|
console.log("Admin user created with permissions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Done!");
|
||||||
|
}
|
||||||
|
|
||||||
|
resetAdminPassword().catch(console.error);
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.text-balance {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--background: 0 0% 100%;
|
||||||
|
--foreground: 0 0% 3.9%;
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 0 0% 3.9%;
|
||||||
|
--popover: 0 0% 100%;
|
||||||
|
--popover-foreground: 0 0% 3.9%;
|
||||||
|
--primary: 0 0% 9%;
|
||||||
|
--primary-foreground: 0 0% 98%;
|
||||||
|
--secondary: 0 0% 96.1%;
|
||||||
|
--secondary-foreground: 0 0% 9%;
|
||||||
|
--muted: 0 0% 96.1%;
|
||||||
|
--muted-foreground: 0 0% 45.1%;
|
||||||
|
--accent: 0 0% 96.1%;
|
||||||
|
--accent-foreground: 0 0% 9%;
|
||||||
|
--destructive: 0 84.2% 60.2%;
|
||||||
|
--destructive-foreground: 0 0% 98%;
|
||||||
|
--border: 0 0% 89.8%;
|
||||||
|
--input: 0 0% 89.8%;
|
||||||
|
--ring: 0 0% 3.9%;
|
||||||
|
--chart-1: 12 76% 61%;
|
||||||
|
--chart-2: 173 58% 39%;
|
||||||
|
--chart-3: 197 37% 24%;
|
||||||
|
--chart-4: 43 74% 66%;
|
||||||
|
--chart-5: 27 87% 67%;
|
||||||
|
--radius: 0.5rem;
|
||||||
|
--sidebar-background: 0 0% 98%;
|
||||||
|
--sidebar-foreground: 240 5.3% 26.1%;
|
||||||
|
--sidebar-primary: 240 5.9% 10%;
|
||||||
|
--sidebar-primary-foreground: 0 0% 98%;
|
||||||
|
--sidebar-accent: 240 4.8% 95.9%;
|
||||||
|
--sidebar-accent-foreground: 240 5.9% 10%;
|
||||||
|
--sidebar-border: 220 13% 91%;
|
||||||
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
|
}
|
||||||
|
.dark {
|
||||||
|
--background: 0 0% 3.9%;
|
||||||
|
--foreground: 0 0% 98%;
|
||||||
|
--card: 0 0% 3.9%;
|
||||||
|
--card-foreground: 0 0% 98%;
|
||||||
|
--popover: 0 0% 3.9%;
|
||||||
|
--popover-foreground: 0 0% 98%;
|
||||||
|
--primary: 0 0% 98%;
|
||||||
|
--primary-foreground: 0 0% 9%;
|
||||||
|
--secondary: 0 0% 14.9%;
|
||||||
|
--secondary-foreground: 0 0% 98%;
|
||||||
|
--muted: 0 0% 14.9%;
|
||||||
|
--muted-foreground: 0 0% 63.9%;
|
||||||
|
--accent: 0 0% 14.9%;
|
||||||
|
--accent-foreground: 0 0% 98%;
|
||||||
|
--destructive: 0 62.8% 30.6%;
|
||||||
|
--destructive-foreground: 0 0% 98%;
|
||||||
|
--border: 0 0% 14.9%;
|
||||||
|
--input: 0 0% 14.9%;
|
||||||
|
--ring: 0 0% 83.1%;
|
||||||
|
--chart-1: 220 70% 50%;
|
||||||
|
--chart-2: 160 60% 45%;
|
||||||
|
--chart-3: 30 80% 55%;
|
||||||
|
--chart-4: 280 65% 60%;
|
||||||
|
--chart-5: 340 75% 55%;
|
||||||
|
--sidebar-background: 240 5.9% 10%;
|
||||||
|
--sidebar-foreground: 240 4.8% 95.9%;
|
||||||
|
--sidebar-primary: 224.3 76.3% 48%;
|
||||||
|
--sidebar-primary-foreground: 0 0% 100%;
|
||||||
|
--sidebar-accent: 240 3.7% 15.9%;
|
||||||
|
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
||||||
|
--sidebar-border: 240 3.7% 15.9%;
|
||||||
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
@apply border-border;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
@apply bg-background text-foreground;
|
||||||
|
}
|
||||||
|
}
|
||||||