Add Legal Office seal and complete Azure CDN deployment

- Add Legal Office of the Master seal (SVG design with Maltese Cross, scales of justice, legal scroll)
- Create legal-office-manifest-template.json for Legal Office credentials
- Update SEAL_MAPPING.md and DESIGN_GUIDE.md with Legal Office seal documentation
- Complete Azure CDN infrastructure deployment:
  - Resource group, storage account, and container created
  - 17 PNG seal files uploaded to Azure Blob Storage
  - All manifest templates updated with Azure URLs
  - Configuration files generated (azure-cdn-config.env)
- Add comprehensive Azure CDN setup scripts and documentation
- Fix manifest URL generation to prevent double slashes
- Verify all seals accessible via HTTPS
This commit is contained in:
defiQUG
2025-11-12 22:03:42 -08:00
parent 8649ad4124
commit 92cc41d26d
258 changed files with 16021 additions and 1260 deletions

View File

@@ -25,7 +25,7 @@ export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
export function Badge({ className, variant, ...props }: BadgeProps) {
export function Badge({ className, variant, ...props }: BadgeProps): JSX.Element {
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}

View File

@@ -1,5 +1,3 @@
import React from 'react';
import Link from 'next/link';
import { cn } from '../lib/utils';
export interface BreadcrumbItem {
@@ -10,9 +8,10 @@ export interface BreadcrumbItem {
export interface BreadcrumbsProps {
items: BreadcrumbItem[];
className?: string;
LinkComponent?: React.ComponentType<{ href: string; className?: string; children: React.ReactNode }>;
}
export function Breadcrumbs({ items, className }: BreadcrumbsProps) {
export function Breadcrumbs({ items, className, LinkComponent }: BreadcrumbsProps): JSX.Element {
return (
<nav aria-label="Breadcrumb" className={cn('flex', className)}>
<ol className="flex items-center space-x-2 text-sm">
@@ -26,9 +25,15 @@ export function Breadcrumbs({ items, className }: BreadcrumbsProps) {
{item.label}
</span>
) : item.href ? (
<Link href={item.href} className="text-gray-600 hover:text-gray-900">
{item.label}
</Link>
LinkComponent ? (
<LinkComponent href={item.href} className="text-gray-600 hover:text-gray-900">
{item.label}
</LinkComponent>
) : (
<a href={item.href} className="text-gray-600 hover:text-gray-900">
{item.label}
</a>
)
) : (
<span className="text-gray-600">{item.label}</span>
)}

View File

@@ -32,7 +32,7 @@ export interface ButtonProps
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
<button className={cn(buttonVariants({ variant, size }), className)} ref={ref} {...props} />
);
}
);

View File

@@ -16,27 +16,29 @@ export interface DropdownProps {
className?: string;
}
export function Dropdown({ trigger, items, align = 'left', className }: DropdownProps) {
export function Dropdown({ trigger, items, align = 'left', className }: DropdownProps): JSX.Element {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
const handleClickOutside = (event: MouseEvent): void => {
if (dropdownRef.current && event.target instanceof Node && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
};
if (isOpen) {
if (isOpen && typeof document !== 'undefined') {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
if (typeof document !== 'undefined') {
document.removeEventListener('mousedown', handleClickOutside);
}
};
}, [isOpen]);
const handleItemClick = (item: DropdownItem) => {
const handleItemClick = (item: DropdownItem): void => {
if (item.disabled) return;
item.onClick?.();
setIsOpen(false);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {}
export type LabelProps = React.LabelHTMLAttributes<HTMLLabelElement>;
export const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
({ className, ...props }, ref) => {

View File

@@ -20,15 +20,17 @@ export function Modal({
children,
size = 'md',
showCloseButton = true,
}: ModalProps) {
}: ModalProps): JSX.Element | null {
useEffect(() => {
if (open) {
if (open && typeof document !== 'undefined') {
document.body.style.overflow = 'hidden';
} else {
} else if (typeof document !== 'undefined') {
document.body.style.overflow = '';
}
return () => {
document.body.style.overflow = '';
if (typeof document !== 'undefined') {
document.body.style.overflow = '';
}
};
}, [open]);
@@ -102,8 +104,8 @@ export function ConfirmModal({
confirmText = 'Confirm',
cancelText = 'Cancel',
variant = 'default',
}: ConfirmModalProps) {
const handleConfirm = () => {
}: ConfirmModalProps): JSX.Element {
const handleConfirm = (): void => {
onConfirm();
onClose();
};

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}
export type SelectProps = React.SelectHTMLAttributes<HTMLSelectElement>;
export const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
({ className, children, ...props }, ref) => {

View File

@@ -1,9 +1,9 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {}
export type SkeletonProps = React.HTMLAttributes<HTMLDivElement>;
export function Skeleton({ className, ...props }: SkeletonProps) {
export function Skeleton({ className, ...props }: SkeletonProps): JSX.Element {
return <div className={cn('animate-pulse rounded-md bg-muted', className)} {...props} />;
}

View File

@@ -1,4 +1,4 @@
import React, { createContext, useContext, useState, ReactNode } from 'react';
import { createContext, useContext, useState, ReactNode } from 'react';
import { cn } from '../lib/utils';
interface TabsContextType {
@@ -16,12 +16,12 @@ export interface TabsProps {
className?: string;
}
export function Tabs({ defaultValue, value: controlledValue, onValueChange, children, className }: TabsProps) {
export function Tabs({ defaultValue, value: controlledValue, onValueChange, children, className }: TabsProps): JSX.Element {
const [internalValue, setInternalValue] = useState(defaultValue || '');
const isControlled = controlledValue !== undefined;
const currentValue = isControlled ? controlledValue : internalValue;
const handleValueChange = (newValue: string) => {
const handleValueChange = (newValue: string): void => {
if (!isControlled) {
setInternalValue(newValue);
}
@@ -40,7 +40,7 @@ export interface TabsListProps {
className?: string;
}
export function TabsList({ children, className }: TabsListProps) {
export function TabsList({ children, className }: TabsListProps): JSX.Element {
return (
<div
className={cn(
@@ -60,7 +60,7 @@ export interface TabsTriggerProps {
className?: string;
}
export function TabsTrigger({ value, children, className }: TabsTriggerProps) {
export function TabsTrigger({ value, children, className }: TabsTriggerProps): JSX.Element {
const context = useContext(TabsContext);
if (!context) {
throw new Error('TabsTrigger must be used within Tabs');
@@ -94,7 +94,7 @@ export interface TabsContentProps {
className?: string;
}
export function TabsContent({ value, children, className }: TabsContentProps) {
export function TabsContent({ value, children, className }: TabsContentProps): JSX.Element | null {
const context = useContext(TabsContext);
if (!context) {
throw new Error('TabsContent must be used within Tabs');

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {

View File

@@ -1,5 +1,4 @@
import React, { createContext, useContext, useState, useCallback, ReactNode } from 'react';
import { cn } from '../lib/utils';
import { createContext, useContext, useState, useCallback, ReactNode } from 'react';
import { Alert, AlertDescription } from './Alert';
export type ToastVariant = 'default' | 'success' | 'error' | 'warning' | 'info';
@@ -24,7 +23,7 @@ interface ToastContextType {
const ToastContext = createContext<ToastContextType | undefined>(undefined);
export function useToast() {
export function useToast(): ToastContextType {
const context = useContext(ToastContext);
if (!context) {
throw new Error('useToast must be used within a ToastProvider');
@@ -32,15 +31,15 @@ export function useToast() {
return context;
}
export function ToastProvider({ children }: { children: ReactNode }) {
export function ToastProvider({ children }: { children: ReactNode }): JSX.Element {
const [toasts, setToasts] = useState<Toast[]>([]);
const removeToast = useCallback((id: string) => {
const removeToast = useCallback((id: string): void => {
setToasts((prev) => prev.filter((toast) => toast.id !== id));
}, []);
const addToast = useCallback(
(toast: Omit<Toast, 'id'>) => {
(toast: Omit<Toast, 'id'>): void => {
const id = Math.random().toString(36).substring(2, 9);
const newToast: Toast = {
...toast,
@@ -51,37 +50,39 @@ export function ToastProvider({ children }: { children: ReactNode }) {
setToasts((prev) => [...prev, newToast]);
if (newToast.duration && newToast.duration > 0) {
setTimeout(() => {
removeToast(id);
}, newToast.duration);
if (typeof window !== 'undefined') {
setTimeout(() => {
removeToast(id);
}, newToast.duration);
}
}
},
[removeToast]
);
const success = useCallback(
(message: string, title?: string) => {
(message: string, title?: string): void => {
addToast({ message, title, variant: 'success' });
},
[addToast]
);
const error = useCallback(
(message: string, title?: string) => {
(message: string, title?: string): void => {
addToast({ message, title, variant: 'error' });
},
[addToast]
);
const warning = useCallback(
(message: string, title?: string) => {
(message: string, title?: string): void => {
addToast({ message, title, variant: 'warning' });
},
[addToast]
);
const info = useCallback(
(message: string, title?: string) => {
(message: string, title?: string): void => {
addToast({ message, title, variant: 'info' });
},
[addToast]
@@ -95,7 +96,7 @@ export function ToastProvider({ children }: { children: ReactNode }) {
);
}
function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast: (id: string) => void }) {
function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast: (id: string) => void }): JSX.Element | null {
if (toasts.length === 0) return null;
return (
@@ -107,7 +108,7 @@ function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast:
);
}
function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: (id: string) => void }) {
function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: (id: string) => void }): JSX.Element {
const variantMap: Record<ToastVariant, { alert: 'default' | 'destructive' | 'success' | 'warning'; icon: string }> = {
default: { alert: 'default', icon: '' },
success: { alert: 'success', icon: '✓' },

View File

@@ -1,7 +1,7 @@
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
export function cn(...inputs: ClassValue[]): string {
return twMerge(clsx(inputs));
}

View File

@@ -3,7 +3,8 @@
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"jsx": "react-jsx"
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "esnext"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"]