refactor_#3 #14
17
app/app.css
17
app/app.css
|
|
@ -1,7 +1,5 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
/* Persian/Farsi font support */
|
||||
@import url("https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100..900&display=swap");
|
||||
@import url(/font/fontiran.css);
|
||||
|
||||
@theme {
|
||||
--font-sans:
|
||||
|
|
@ -49,6 +47,17 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
font-family: IRANYekanX !important;
|
||||
direction: rtl;
|
||||
background-color: #cdcdcd;
|
||||
margin: 0;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6,input, textarea {
|
||||
font-family: IRANYekanX !important;
|
||||
}
|
||||
|
||||
/* RTL Support */
|
||||
html[dir="rtl"] {
|
||||
direction: rtl;
|
||||
|
|
@ -251,7 +260,7 @@ html[dir="rtl"] body {
|
|||
|
||||
/* Persian/Farsi font class */
|
||||
.font-persian {
|
||||
font-family: "Vazirmatn", "Inter", ui-sans-serif, system-ui, sans-serif;
|
||||
font-family: IRANYekanX;
|
||||
}
|
||||
|
||||
/* Custom utility classes */
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ export function LoginForm({ onSuccess }: LoginFormProps) {
|
|||
<div className="flex justify-end">
|
||||
<CheckboxField
|
||||
id="remember"
|
||||
label="همیشه متصل بمانم"
|
||||
label="همیشه متصل بمان"
|
||||
checked={formData.rememberMe}
|
||||
onChange={(checked) => updateField("rememberMe", checked)}
|
||||
disabled={isLoading}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useAuth } from "~/contexts/auth-context";
|
||||
import { Link } from "react-router";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
Menu,
|
||||
ChevronDown,
|
||||
Server,
|
||||
ChevronLeft ,
|
||||
|
||||
} from "lucide-react";
|
||||
import apiService from "~/lib/api";
|
||||
|
|
@ -20,12 +21,14 @@ interface HeaderProps {
|
|||
onToggleSidebar?: () => void;
|
||||
className?: string;
|
||||
title?: string;
|
||||
titleIcon?: React.ComponentType<{ className?: string }> | null;
|
||||
}
|
||||
|
||||
export function Header({
|
||||
onToggleSidebar,
|
||||
className,
|
||||
title = "صفحه اول",
|
||||
titleIcon,
|
||||
}: HeaderProps) {
|
||||
const { user } = useAuth();
|
||||
const [isProfileMenuOpen, setIsProfileMenuOpen] = useState(false);
|
||||
|
|
@ -65,7 +68,24 @@ export function Header({
|
|||
|
||||
{/* Page Title */}
|
||||
<h1 className="text-xl flex items-center justify-center gap-4 font-bold text-white font-persian">
|
||||
<PanelLeft /> {title}
|
||||
{/* Right-side icon for current page */}
|
||||
{titleIcon ? (
|
||||
<div className="flex items-center gap-2 mr-4">
|
||||
{React.createElement(titleIcon, { className: "w-5 h-5 " })}
|
||||
</div>
|
||||
) : (
|
||||
<PanelLeft />
|
||||
)}
|
||||
{title.includes("-") ? (
|
||||
<span className="flex items-center gap-1">
|
||||
{title.split("-")[0]}
|
||||
<ChevronLeft className="inline-block w-4 h-4" />
|
||||
{title.split("-")[1]}
|
||||
</span>
|
||||
) : (
|
||||
title
|
||||
)}
|
||||
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
|
@ -89,9 +109,7 @@ export function Header({
|
|||
onClick={() => setIsProfileMenuOpen(!isProfileMenuOpen)}
|
||||
className="flex items-center gap-2 text-gray-300"
|
||||
>
|
||||
<div className="w-8 h-8 bg-gradient-to-r from-emerald-500/20 to-teal-500/20 text-emerald-400 rounded-full flex items-center justify-center">
|
||||
<User className="h-4 w-4" />
|
||||
</div>
|
||||
|
||||
<div className="hidden sm:block text-right">
|
||||
<div className="text-sm font-medium font-persian">
|
||||
{user?.name} {user?.family}
|
||||
|
|
@ -100,7 +118,9 @@ export function Header({
|
|||
{user?.username}
|
||||
</div>
|
||||
</div>
|
||||
<ChevronDown className="h-3 w-3" />
|
||||
<div className="w-8 h-8 bg-gradient-to-r from-emerald-500/20 to-teal-500/20 text-emerald-400 rounded-lg flex items-center justify-center">
|
||||
<User className="h-4 w-4" />
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
{/* Profile Dropdown */}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ export function DashboardLayout({
|
|||
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
|
||||
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
|
||||
const [isStrategicAlignmentPopupOpen, setIsStrategicAlignmentPopupOpen] = useState(false);
|
||||
const [currentTitle, setCurrentTitle] = useState<string | undefined>(title ?? "صفحه اول");
|
||||
const [currentTitleIcon, setCurrentTitleIcon] = useState<React.ComponentType<{ className?: string }> | null | undefined>(undefined);
|
||||
|
||||
const toggleSidebarCollapse = () => {
|
||||
setIsSidebarCollapsed(!isSidebarCollapsed);
|
||||
|
|
@ -61,6 +63,10 @@ export function DashboardLayout({
|
|||
onToggleCollapse={toggleSidebarCollapse}
|
||||
className="h-full flex-shrink-0 relative z-10"
|
||||
onStrategicAlignmentClick={() => setIsStrategicAlignmentPopupOpen(true)}
|
||||
onTitleChange={(info) => {
|
||||
setCurrentTitle(info.title);
|
||||
setCurrentTitleIcon(info.icon ?? null);
|
||||
}}
|
||||
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -71,7 +77,8 @@ export function DashboardLayout({
|
|||
<Header
|
||||
onToggleSidebar={toggleMobileSidebar}
|
||||
className="flex-shrink-0"
|
||||
title={title}
|
||||
title={currentTitle}
|
||||
titleIcon={currentTitleIcon}
|
||||
/>
|
||||
|
||||
{/* Main content */}
|
||||
|
|
|
|||
|
|
@ -813,7 +813,7 @@ export function GreenInnovationPage() {
|
|||
<div className="params flex flex-col gap-3.5">
|
||||
{Object.entries(recycleParams).map((el, index) => {
|
||||
return (
|
||||
<div className="param flex flex-row justify-between items-center">
|
||||
<div key={index} className="param flex flex-row justify-between items-center">
|
||||
<div className="flex flex-row gap-2">
|
||||
{el[1].icon}
|
||||
<span className="font-normal text-sm font-persian">
|
||||
|
|
|
|||
|
|
@ -587,10 +587,10 @@ export function ProcessInnovationPage() {
|
|||
|
||||
return (
|
||||
<DashboardLayout title="نوآوری در فرآیند">
|
||||
<div className="p-6 space-y-4">
|
||||
<div className="p-6 py-2 space-y-4">
|
||||
{/* Stats Cards */}
|
||||
<div className="flex gap-6">
|
||||
<div className="space-y-6 w-full">
|
||||
<div className="space-y-4 w-full">
|
||||
{/* Stats Grid */}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{loading || statsLoading
|
||||
|
|
|
|||
|
|
@ -15,12 +15,13 @@ import {
|
|||
UsersIcon,
|
||||
Wrench,
|
||||
} from "lucide-react";
|
||||
import moment from "moment-jalaali";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
import { MetricCard } from "~/components/ui/metric-card";
|
||||
import { BaseCard } from "~/components/ui/base-card";
|
||||
import { Checkbox } from "~/components/ui/checkbox";
|
||||
import { Bar, BarChart, LabelList } from "recharts"
|
||||
import {
|
||||
|
|
@ -54,7 +55,6 @@ import { DashboardLayout } from "../layout";
|
|||
import { Skeleton } from "~/components/ui/skeleton";
|
||||
import { Tooltip as TooltipSh, TooltipTrigger, TooltipContent } from "~/components/ui/tooltip";
|
||||
|
||||
moment.loadPersian({ usePersianDigits: true });
|
||||
|
||||
interface ProjectData {
|
||||
project_no: string;
|
||||
|
|
@ -608,25 +608,25 @@ export function ProductInnovationPage() {
|
|||
size="sm"
|
||||
onClick={() => {
|
||||
handleProjectDetails(item)}}
|
||||
className="text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/20 p-2 h-auto"
|
||||
className="text-emerald-400 underline underline-offset-4 font-ligth text-base hover:bg-emerald-500/20 p-2 h-auto"
|
||||
>
|
||||
جزئیات بیشتر
|
||||
</Button>
|
||||
);
|
||||
case "project_no":
|
||||
return (
|
||||
<Badge variant="outline" className="font-mono">
|
||||
<Badge variant="outline" className="font-mono text-base font-light">
|
||||
{String(value)}
|
||||
</Badge>
|
||||
);
|
||||
case "title":
|
||||
return <span className="font-medium text-white">{String(value)}</span>;
|
||||
return <span className="font-light text-base text-white">{String(value)}</span>;
|
||||
case "project_status":
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center text-base font-light gap-1">
|
||||
<Badge
|
||||
variant={statusColor(value as projectStatus)}
|
||||
className="font-medium border-2 p-0 block w-2 h-2 rounded-full"
|
||||
className="font-semibold text-base border-2 p-0 block w-2 h-2 rounded-full"
|
||||
style={{
|
||||
border: "none",
|
||||
}}
|
||||
|
|
@ -638,13 +638,13 @@ export function ProductInnovationPage() {
|
|||
return (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={`text-lg text-center border-none mx-auto`}
|
||||
className={`font-semibold text-base text-center border-none mx-auto`}
|
||||
>
|
||||
{formatNumber(String(value))}
|
||||
</Badge>
|
||||
);
|
||||
default:
|
||||
return <span className="text-gray-300">{String(value) || "-"}</span>;
|
||||
return <span className="text-white text-base font-light">{String(value) || "-"}</span>;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -670,8 +670,8 @@ export function ProductInnovationPage() {
|
|||
<div className="space-y-6 w-full">
|
||||
{/* Stats Grid */}
|
||||
<div className="grid grid-cols-2 grid-rows-2 gap-5 h-full">
|
||||
{loading || statsLoading
|
||||
? // Loading skeleton for stats cards - matching new design
|
||||
{loading || statsLoading ? (
|
||||
// Loading skeleton for stats cards - matching new design
|
||||
Array.from({ length: 3 }).map((_, index) => (
|
||||
<Card
|
||||
key={`skeleton-${index}`}
|
||||
|
|
@ -690,7 +690,7 @@ export function ProductInnovationPage() {
|
|||
</div>
|
||||
<div className="flex items-center justify-center flex-col p-1">
|
||||
<div
|
||||
className="h-8 bg-gray-600 rounded animate-pulse"
|
||||
className="h-8 bg-gray-600 rounded animate-pulse mb-1"
|
||||
style={{ width: "40%" }}
|
||||
/>
|
||||
<div
|
||||
|
|
@ -702,55 +702,54 @@ export function ProductInnovationPage() {
|
|||
</CardContent>
|
||||
</Card>
|
||||
))
|
||||
: Object.entries(stateCard).map(([key, card], index) => (
|
||||
<Card
|
||||
key={card.id}
|
||||
className={`bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm border-gray-700/50 ${index !== 0 ? "row-start-2 " : "col-span-2"} `}
|
||||
>
|
||||
<CardContent className="p-2 h-full">
|
||||
<div className="grid grid-cols-2 justify-between gap-2 h-full">
|
||||
<div className="flex justify-between rows-start-1 col-span-2 items-center border-b-2 mx-4 border-gray-500/20">
|
||||
<h3 className="text-lg text-white font-persian py-2">
|
||||
{card.title}
|
||||
</h3>
|
||||
<div
|
||||
className={`p-3 gird placeitems-center rounded-full w-fit `}
|
||||
>
|
||||
) : (
|
||||
<>
|
||||
{/* First card (Metric/Matrix style) - span two columns */}
|
||||
<div className="col-span-2">
|
||||
<MetricCard
|
||||
title={stateCard.revenueNewProducts.title}
|
||||
value={stateCard.revenueNewProducts.value}
|
||||
percentValue={stateCard.revenueNewProducts.percent}
|
||||
valueLabel={stateCard.revenueNewProducts.description}
|
||||
percentLabel={stateCard.revenueNewProducts.descriptionPercent}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`flex items-center row-start-2 justify-center flex-col row-start-2 p-1 my-auto ${card?.percent ? "col-span-1 col-start-1" : "col-span-2"}`}>
|
||||
<p
|
||||
className={`text-3xl font-bold ${card.color} mb-1`}
|
||||
>
|
||||
{card.value}
|
||||
|
||||
</p>
|
||||
<p className="text-sm text-gray-300 font-persian">
|
||||
{card.description}
|
||||
</p>
|
||||
{/* Second card */}
|
||||
<div>
|
||||
<BaseCard title={stateCard.newProductExports.title} className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm border-gray-700/50">
|
||||
<div className="flex items-center justify-center flex-col">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-center">
|
||||
<p className="text-3xl font-bold mb-1 text-pr-green">{stateCard.newProductExports.value}</p>
|
||||
<div className="text-xs text-gray-400 font-persian">{stateCard.newProductExports.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BaseCard>
|
||||
</div>
|
||||
{card?.percent && <span className="text-gray-600 row-start-2 col-span-2 self-center col-start-2 font-thin text-5xl">/</span>}
|
||||
{card?.percent && <div className="flex col-span-1 items-center row-start-2 my-auto col-start-2 justify-center flex-col p-1 my-auto">
|
||||
<p
|
||||
className={`text-3xl font-bold ${card.color} mb-1`}
|
||||
>
|
||||
{card?.percent}
|
||||
|
||||
</p>
|
||||
<p className="text-sm text-gray-300 font-persian">
|
||||
{card.descriptionPercent}
|
||||
</p>
|
||||
</div>}
|
||||
{/* Third card - basic BaseCard */}
|
||||
<div>
|
||||
<BaseCard title={stateCard.impactOnImports.title} className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm border-gray-700/50">
|
||||
<div className="flex items-center justify-center flex-col">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-center">
|
||||
<p className="text-3xl font-bold mb-1 text-pr-red">{stateCard.impactOnImports.value}</p>
|
||||
<div className="text-xs text-gray-400 font-persian">{stateCard.impactOnImports.description}</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</BaseCard>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Funnel Chart */}
|
||||
<Card className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] h-full backdrop-blur-sm rounded-2xl w-full overflow-hidden">
|
||||
<CardContent className="p-6">
|
||||
<CardContent className="px-0 py-4">
|
||||
<FunnelChart
|
||||
title="قيف فرآیند پروژه ها"
|
||||
data={[
|
||||
|
|
@ -795,7 +794,7 @@ export function ProductInnovationPage() {
|
|||
{columns.map((column) => (
|
||||
<TableHead
|
||||
key={column.key}
|
||||
className="text-center font-persian whitespace-nowrap text-gray-200 font-medium sticky top-0 z-20 bg-[#3F415A]"
|
||||
className="text-center font-persian whitespace-nowrap text-white font-medium sticky top-0 z-20 bg-pr-gray text-sm font-semibold"
|
||||
style={{ width: column.width }}
|
||||
>
|
||||
{column.sortable ? (
|
||||
|
|
@ -891,10 +890,10 @@ export function ProductInnovationPage() {
|
|||
</CardContent>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="p-2 px-4 bg-[#3F415A]">
|
||||
<div className="p-2 px-4 bg-pr-gray">
|
||||
<div className="flex gap-4 text-sm text-gray-300 font-persian justify-between sm:flex-col xl:flex-row">
|
||||
<div className="text-center gap-2 items-center xl:w-1/3 pr-36 sm:w-full">
|
||||
<div className="text-base text-gray-401">
|
||||
<div className="text-sm font-semibold text-white">
|
||||
کل پروژه ها :{formatNumber(stats?.count_innovation_construction_inside_projects)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -907,8 +906,8 @@ export function ProductInnovationPage() {
|
|||
<span className="block w-7 h-2.5 bg-pink-400 rounded-tr-xl rounded-br-xl"></span>
|
||||
</div>
|
||||
<div className="flex justify-center items-center gap-2">
|
||||
<div className="text-base text-gray-400">میانگین :</div>
|
||||
<div className="font-bold">
|
||||
<div className="text-bold text-sm text-white">میانگین :</div>
|
||||
<div className="font-bold text-sm text-white">
|
||||
{formatNumber(
|
||||
((stats.average_project_score ?? 0) as number).toFixed?.(1) ?? 0
|
||||
)}
|
||||
|
|
@ -924,7 +923,7 @@ export function ProductInnovationPage() {
|
|||
<Dialog open={detailsDialogOpen} onOpenChange={setDetailsDialogOpen}>
|
||||
<DialogContent className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] max-w-7xl max-h-[95vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-white mr-4 border-b-2 border-gray-600 pb-2 font-persian text-right">
|
||||
<DialogTitle className="text-white mr-4 border-b-2 border-gray-600 pb-2 text-sm font-semibold font-persian text-right">
|
||||
شرح پروژه
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
|
@ -934,17 +933,17 @@ export function ProductInnovationPage() {
|
|||
<div className="space-y-4">
|
||||
{/* Stats Cards */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="font-bold text-lg">{selectedProjectDetails?.title}</h3>
|
||||
<h3 className="font-bold text-base">{selectedProjectDetails?.title}</h3>
|
||||
<p className="py-2">{selectedProjectDetails?.project_description}</p>
|
||||
</div>
|
||||
<Timeline />
|
||||
|
||||
{/* Technical Knowledge */}
|
||||
<div className=" rounded-lg py-2 mb-0">
|
||||
<h3 className="text-sm text-gray-400 mb-2">دانش فنی محصول جدید</h3>
|
||||
<h3 className="text-sm text-white font-semibold mb-2">دانش فنی محصول جدید</h3>
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-white">توسعه درونزا</span>
|
||||
<span className="text-sm text-white font-light">توسعه درونزا</span>
|
||||
|
||||
<Checkbox
|
||||
checked={selectedProjectDetails?.developed_technology_type === "توسعه درونزا"}
|
||||
|
|
@ -953,7 +952,7 @@ export function ProductInnovationPage() {
|
|||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-white">همکاری فناورانه</span>
|
||||
<span className="text-sm text-white font-light">همکاری فناورانه</span>
|
||||
|
||||
<Checkbox
|
||||
checked={selectedProjectDetails?.developed_technology_type === "همکاری فناوری"}
|
||||
|
|
@ -962,7 +961,7 @@ export function ProductInnovationPage() {
|
|||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-white">سایر</span>
|
||||
<span className="text-sm text-white font-light">سایر</span>
|
||||
<Checkbox
|
||||
checked={selectedProjectDetails?.developed_technology_type === "سایر"}
|
||||
className="data-[state=checked]:bg-emerald-600 data-[state=checked]:border-emerald-600"
|
||||
|
|
@ -973,7 +972,7 @@ export function ProductInnovationPage() {
|
|||
|
||||
{/* Standards */}
|
||||
<div className="rounded-lg py-4">
|
||||
<h3 className="text-sm text-gray-400 mb-4">
|
||||
<h3 className="text-sm text-white font-semibold mb-4">
|
||||
استانداردهای ملی و بینالمللی اخذ شده
|
||||
</h3>
|
||||
|
||||
|
|
@ -985,7 +984,7 @@ export function ProductInnovationPage() {
|
|||
).map((standard, index) => (
|
||||
<div key={index} className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-emerald-500 rounded-full"></div>
|
||||
<span className="text-sm text-white">{standard}</span>
|
||||
<span className="text-sm text-white font-light">{standard}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -997,21 +996,21 @@ export function ProductInnovationPage() {
|
|||
</div>
|
||||
|
||||
{/* Knowledge-based Certificate Button */}
|
||||
<div className="justify-self-centerr py-1 mx-auto">
|
||||
<div className="justify-self-centerr grid py-1 mx-auto">
|
||||
{selectedProjectDetails?.knowledge_based_certificate_obtained === "خیر" ? (
|
||||
<div className=" border border-red-600 rounded-lg p-2 text-center">
|
||||
<button className="text-red-400 font-medium">
|
||||
<div className=" border border-pr-red mx-auto rounded-lg p-2 text-center">
|
||||
<button className="text-pr-red font-bold text-sm">
|
||||
گواهی دانشبنیان ندارد
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<Card className="justify-self-center border-emerald-600 bg-transparent py-0">
|
||||
<Card className="justify-self-center border-pr-green bg-transparent py-0">
|
||||
<CardContent className="p-2 text-center">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="default"
|
||||
className=" text-emerald-400 hover:bg-transparent cursor-pointer bg-transparent"
|
||||
className=" text-pr-green font-bold text-sm hover:bg-transparent cursor-pointer bg-transparent"
|
||||
>
|
||||
مشاهده اطلاعات گواهی دانشبنیان
|
||||
</Button>
|
||||
|
|
@ -1070,103 +1069,37 @@ export function ProductInnovationPage() {
|
|||
</div>
|
||||
) : (
|
||||
<div className="lg:col-span-2 border-r-2 flex flex-col gap-2 pr-4 pb-2 border-r-[#5F6284]/50">
|
||||
{/* Project Description */}
|
||||
<div className=" rounded-lg pt-4 flex w-full gap-2">
|
||||
<Card
|
||||
className="bg-[linear-gradient(to_bottom_left,#464861,45%,#111628)] flex-1 backdrop-blur-sm border-gray-700/50 col-span-2"
|
||||
>
|
||||
<CardContent className="p-2 h-full">
|
||||
<div className="grid grid-cols-2 justify-between gap-2 h-full">
|
||||
<div className="flex justify-between rows-start-1 col-span-2 items-center border-b-2 mx-4 border-gray-500/20">
|
||||
<h3 className="text-lg text-white font-persian py-2">
|
||||
میزان صادارت محصول جدید
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex col-span-1 items-center row-start-2 my-auto col-start-1 justify-center flex-col p-1 my-auto">
|
||||
<p
|
||||
className={`text-2xl font-bold mb-1`}
|
||||
>
|
||||
{formatNumber(Math.round(popupStats?.new_products_export > 0 ? popupStats?.new_products_export : 0)) || formatNumber(0)}
|
||||
</p>
|
||||
<p className="text-xs font-thin text-gray-300 font-persian">
|
||||
میلیون ریال
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-gray-600 row-start-2 self-center col-start-2 font-thin text-5xl">/</span>
|
||||
<div className="flex col-span-1 items-center row-start-2 my-auto col-start-2 justify-center flex-col p-1 my-auto">
|
||||
<p
|
||||
className={`text-2xl font-bold mb-1`}
|
||||
>
|
||||
{formatNumber(Math.round(popupStats?.new_products_export_percent > 0 ? popupStats?.new_products_export_percent : 0)) || formatNumber(0)}%
|
||||
</p>
|
||||
<p className="text-xs font-thin text-gray-300 font-persian">
|
||||
درصد به کل صادرات
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
className="bg-[linear-gradient(to_bottom_left,#464861,45%,#111628)] flex-1 backdrop-blur-sm border-gray-700/50 col-span-2"
|
||||
>
|
||||
<CardContent className="p-2 h-full">
|
||||
<div className="grid grid-cols-2 justify-between gap-2 h-full">
|
||||
<div className="flex justify-between rows-start-1 col-span-2 items-center border-b-2 mx-4 border-gray-500/20">
|
||||
<h3 className="text-lg text-white font-persian py-2">
|
||||
تاثیر در واردات
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex col-span-1 items-center row-start-2 my-auto col-start-1 justify-center flex-col p-1 my-auto">
|
||||
<p
|
||||
className={`text-2xl font-bold mb-1`}
|
||||
>
|
||||
{formatNumber(Math.round(popupStats?.import_impact > 0 ? popupStats?.import_impact : 0)) || formatNumber(0)}
|
||||
</p>
|
||||
<p className="text-xs font-thin text-gray-300 font-persian">
|
||||
میلیون ریال
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-gray-600 row-start-2 self-center col-start-2 font-thin text-5xl">/</span>
|
||||
<div className="flex col-span-1 items-center row-start-2 my-auto col-start-2 justify-center flex-col p-1 my-auto">
|
||||
<p
|
||||
className={`text-2xl font-bold mb-1`}
|
||||
>
|
||||
{formatNumber(Math.round(popupStats?.import_impact_percent > 0 ? popupStats?.import_impact_percent : 0)) || formatNumber(0)}%
|
||||
</p>
|
||||
<p className="text-xs font-thin text-gray-300 font-persian">
|
||||
درصد صرفه جویی
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
||||
{/* Project Description - two MetricCards side by side */}
|
||||
<div className="rounded-lg pt-4 grid grid-cols-2 gap-4 w-full">
|
||||
<MetricCard
|
||||
title="میزان صادارت محصول جدید"
|
||||
value={Math.round(popupStats?.new_products_export > 0 ? popupStats?.new_products_export : 0)}
|
||||
percentValue={Math.round(popupStats?.new_products_export_percent > 0 ? popupStats?.new_products_export_percent : 0)}
|
||||
valueLabel="میلیون ریال"
|
||||
percentLabel="درصد به کل صادرات"
|
||||
/>
|
||||
|
||||
<MetricCard
|
||||
title="تاثیر در واردات"
|
||||
value={Math.round(popupStats?.import_impact > 0 ? popupStats?.import_impact : 0)}
|
||||
percentValue={Math.round(popupStats?.import_impact_percent > 0 ? popupStats?.import_impact_percent : 0)}
|
||||
valueLabel="میلیون ریال"
|
||||
percentLabel="درصد صرفه جویی"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Export Revenue Bar Chart */}
|
||||
<div className="bg-[linear-gradient(to_bottom_left,#464861,45%,#111628)] rounded-lg px-6 py-4">
|
||||
<h3 className="text-lg font-semibold text-white">ظرفیت صادر شده</h3>
|
||||
<h3 className="text-sm font-semibold text-white">ظرفیت صادر شده</h3>
|
||||
<div className="h-60">
|
||||
{popupLoading ? (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="animate-pulse my-auto text-gray-400">در حال بارگذاری...</div>
|
||||
</div>
|
||||
) : exportChartData.length > 0 ? (
|
||||
{exportChartData.length > 0 ? (
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart className="aspect-auto w-full"
|
||||
<BarChart
|
||||
className="aspect-auto w-full"
|
||||
data={sortedBarData}
|
||||
barGap={15}
|
||||
barSize={30}
|
||||
margin={{
|
||||
top : 18
|
||||
}}
|
||||
margin={{ top: 18 }}
|
||||
>
|
||||
<CartesianGrid vertical={false} stroke="#475569" />
|
||||
<XAxis
|
||||
|
|
@ -1176,126 +1109,44 @@ export function ProductInnovationPage() {
|
|||
stroke="#C3C3C3"
|
||||
tickMargin={8}
|
||||
tickFormatter={(value: string) => `${value.split(" ")[0]} ${formatNumber(value.split(" ")[1]).replaceAll('٬','')}`}
|
||||
fontSize={11}
|
||||
/>
|
||||
<YAxis
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
stroke="#9CA3AF"
|
||||
fontSize={11} tick={{ dx: -50 }} tickFormatter={(value: number) => `${formatNumber(value)} میلیون`}/>
|
||||
<Bar
|
||||
dataKey="value"
|
||||
fill="#10B981"
|
||||
radius={10}
|
||||
>
|
||||
<LabelList
|
||||
formatter={(value : number) => `${formatNumber(value)}`}
|
||||
position="top"
|
||||
offset={15}
|
||||
fill="F9FAFB"
|
||||
className="fill-foreground"
|
||||
fontSize={16}
|
||||
/>
|
||||
<YAxis tickLine={false} axisLine={false} stroke="#9CA3AF" fontSize={11} tick={{ dx: -50 }} tickFormatter={(value: number) => `${formatNumber(value)} میلیون`} />
|
||||
<Bar dataKey="value" fill="#10B981" radius={10}>
|
||||
<LabelList formatter={(value: number) => `${formatNumber(value)}`} position="top" offset={15} fill="F9FAFB" className="fill-foreground" fontSize={16} />
|
||||
</Bar>
|
||||
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full text-gray-400">
|
||||
دادهای برای نمایش وجود ندارد
|
||||
</div>
|
||||
<div className="flex items-center justify-center h-full text-gray-400">دادهای برای نمایش وجود ندارد</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Export Revenue Line Chart */}
|
||||
<div className="bg-[linear-gradient(to_bottom_left,#464861,45%,#111628)] rounded-lg px-6 py-4">
|
||||
<h3 className="text-lg font-semibold text-white">ظرفیت صادر شده</h3>
|
||||
<h3 className="text-sm font-semibold text-white">ظرفیت صادر شده</h3>
|
||||
<div className="h-60">
|
||||
{popupLoading ? (
|
||||
<div className="flex items-center justify-center ">
|
||||
<div className="animate-pulse my-auto text-gray-400">در حال بارگذاری...</div>
|
||||
</div>
|
||||
) : allExportData.length > 0 ? (
|
||||
{allExportData.length > 0 ? (
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart
|
||||
accessibilityLayer
|
||||
className="aspect-auto w-full "
|
||||
data={transformDataForLineChart(allExportData)}
|
||||
margin={{ top: 20, right: 30, left: 10, bottom: 50 }}
|
||||
>
|
||||
<LineChart className="aspect-auto w-full" data={transformDataForLineChart(allExportData)} margin={{ top: 20, right: 30, left: 10, bottom: 50 }}>
|
||||
<CartesianGrid vertical={false} stroke="#374151" />
|
||||
<XAxis
|
||||
dataKey="season"
|
||||
stroke="#9CA3AF"
|
||||
fontSize={11}
|
||||
tick={({ x, y, payload }) => (
|
||||
<XAxis dataKey="season" stroke="#9CA3AF" fontSize={11} tick={({ x, y, payload }) => (
|
||||
<g transform={`translate(${x},${y + 10})`}>
|
||||
<text
|
||||
x={-40}
|
||||
y={15}
|
||||
dy={0}
|
||||
textAnchor="end"
|
||||
fill="#9CA3AF"
|
||||
fontSize={11}
|
||||
transform="rotate(-45)"
|
||||
>
|
||||
{payload.value}
|
||||
</text>
|
||||
<text x={-40} y={15} dy={0} textAnchor="end" fill="#9CA3AF" fontSize={11} transform="rotate(-45)">{(payload as any).value}</text>
|
||||
</g>
|
||||
)}
|
||||
/>
|
||||
<YAxis
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
stroke="#9CA3AF"
|
||||
fontSize={11}
|
||||
tick={{ dx: -50 }}
|
||||
tickFormatter={(value) => `${formatNumber(value)} میلیون`} // 👈 اضافه کردن M کنار اعداد
|
||||
/>
|
||||
|
||||
<Tooltip
|
||||
formatter={(value : number) => `${formatNumber(value)} میلیون`}
|
||||
contentStyle={{
|
||||
backgroundColor: "#1F2937",
|
||||
border: "1px solid #374151",
|
||||
borderRadius: "6px",
|
||||
padding: "6px 10px",
|
||||
fontSize: "11px",
|
||||
color: "#F9FAFB",
|
||||
}}
|
||||
/>
|
||||
<Legend
|
||||
layout="vertical"
|
||||
verticalAlign="middle"
|
||||
align="right"
|
||||
iconType={"plainline"}display={"flex !important"}
|
||||
className="!flex"
|
||||
wrapperStyle={{ fontSize: 11 , paddingLeft : 12 , display : "flex !important" , gap : 10} }
|
||||
/>
|
||||
|
||||
{[...new Set(allExportData.map((item) => item.product_title))]
|
||||
.slice(0, 5)
|
||||
.map((product, index) => {
|
||||
)} />
|
||||
<YAxis tickLine={false} axisLine={false} stroke="#9CA3AF" fontSize={11} tick={{ dx: -50 }} tickFormatter={(value) => `${formatNumber(value)} میلیون`} />
|
||||
<Tooltip formatter={(value: number) => `${formatNumber(value)} میلیون`} contentStyle={{ backgroundColor: "#1F2937", border: "1px solid #374151", borderRadius: "6px", padding: "6px 10px", fontSize: "11px", color: "#F9FAFB" }} />
|
||||
<Legend layout="vertical" verticalAlign="middle" align="right" iconType={"plainline"} className="!flex" wrapperStyle={{ fontSize: 11, paddingLeft: 12, gap: 10 }} />
|
||||
{[...new Set(allExportData.map((item) => item.product_title))].slice(0, 5).map((product, index) => {
|
||||
const colors = ["#10B981", "#EF4444", "#3B82F6", "#F59E0B", "#8B5CF6"];
|
||||
return (
|
||||
<Line
|
||||
key={product.product_title}
|
||||
type="linear"
|
||||
dot={false}
|
||||
activeDot={{ r: 5 }}
|
||||
dataKey={product}
|
||||
stroke={colors[index % colors.length]}
|
||||
strokeWidth={2}
|
||||
/>
|
||||
);
|
||||
return <Line key={product} type="linear" dot={false} activeDot={{ r: 5 }} dataKey={product} stroke={colors[index % colors.length]} strokeWidth={2} />;
|
||||
})}
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full text-gray-400">
|
||||
دادهای برای نمایش وجود ندارد
|
||||
</div>
|
||||
<div className="flex items-center justify-center h-full text-gray-400">دادهای برای نمایش وجود ندارد</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,18 +15,28 @@ import {
|
|||
Settings,
|
||||
Star,
|
||||
Workflow,
|
||||
DiscAlbum
|
||||
DiscAlbum,
|
||||
House,
|
||||
ListTodo,
|
||||
LightbulbIcon,
|
||||
Radar
|
||||
} from "lucide-react";
|
||||
import React, { useState } from "react";
|
||||
import { Link, useLocation } from "react-router";
|
||||
import { useAuth } from "~/contexts/auth-context";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
interface TitleInfo {
|
||||
title: string;
|
||||
icon?: React.ComponentType<{ className?: string }> | null;
|
||||
}
|
||||
|
||||
interface SidebarProps {
|
||||
isCollapsed?: boolean;
|
||||
onToggleCollapse?: () => void;
|
||||
className?: string;
|
||||
onStrategicAlignmentClick?: () => void;
|
||||
onTitleChange?: (info: TitleInfo) => void;
|
||||
}
|
||||
|
||||
interface MenuItem {
|
||||
|
|
@ -43,48 +53,48 @@ const menuItems: MenuItem[] = [
|
|||
{
|
||||
id: "dashboard",
|
||||
label: "صفحه اصلی",
|
||||
icon: LayoutDashboard,
|
||||
icon: House,
|
||||
href: "/dashboard",
|
||||
},
|
||||
{
|
||||
id: "project-management",
|
||||
label: "مدیریت اجرای پروژهها",
|
||||
icon: FolderKanban,
|
||||
icon: ListTodo,
|
||||
href: "/dashboard/project-management",
|
||||
},
|
||||
{
|
||||
id: "innovation-basket",
|
||||
label: "سبد فناوری و نوآوری",
|
||||
icon: Box,
|
||||
icon: LightbulbIcon,
|
||||
children: [
|
||||
{
|
||||
id: "product-innovation",
|
||||
label: "نوآوری در محصول",
|
||||
icon: Package,
|
||||
icon: null,
|
||||
href: "/dashboard/innovation-basket/product-innovation",
|
||||
},
|
||||
{
|
||||
id: "process-innovation",
|
||||
label: "نوآوری در فرآیند",
|
||||
icon: Workflow,
|
||||
icon: null,
|
||||
href: "/dashboard/innovation-basket/process-innovation",
|
||||
},
|
||||
{
|
||||
id: "digital-innovation",
|
||||
label: "نوآوری دیجیتال",
|
||||
icon: MonitorSmartphone,
|
||||
icon: null,
|
||||
href: "/dashboard/innovation-basket/digital-innovation",
|
||||
},
|
||||
{
|
||||
id: "green-innovation",
|
||||
label: "نوآوری سبز",
|
||||
icon: Leaf,
|
||||
icon: null,
|
||||
href: "/dashboard/innovation-basket/green-innovation",
|
||||
},
|
||||
{
|
||||
id: "internal-innovation",
|
||||
label: "نوآوری ساخت داخل",
|
||||
icon: Building2,
|
||||
icon: null,
|
||||
href: "/dashboard/innovation-basket/internal-innovation",
|
||||
},
|
||||
],
|
||||
|
|
@ -92,13 +102,13 @@ const menuItems: MenuItem[] = [
|
|||
{
|
||||
id: "ecosystem",
|
||||
label: "زیست بوم فناوری و نوآوری",
|
||||
icon: Globe,
|
||||
icon: Radar,
|
||||
href: "/dashboard/ecosystem",
|
||||
},
|
||||
{
|
||||
id: "ideas",
|
||||
label: "ایدههای فناوری و نوآوری",
|
||||
icon: Lightbulb,
|
||||
icon: House,
|
||||
href: "/dashboard/manage-ideas-tech",
|
||||
},
|
||||
{
|
||||
|
|
@ -136,6 +146,7 @@ export function Sidebar({
|
|||
onToggleCollapse,
|
||||
className,
|
||||
onStrategicAlignmentClick,
|
||||
onTitleChange,
|
||||
}: SidebarProps) {
|
||||
const location = useLocation();
|
||||
const [expandedItems, setExpandedItems] = useState<string[]>([]);
|
||||
|
|
@ -158,6 +169,29 @@ export function Sidebar({
|
|||
});
|
||||
|
||||
setExpandedItems(newExpandedItems);
|
||||
// Update header title based on current route
|
||||
// If a child route is active, use that child's label prefixed by parent label
|
||||
let activeTitle: string | undefined = undefined;
|
||||
let activeIcon: React.ComponentType<{ className?: string }> | null | undefined = undefined;
|
||||
menuItems.forEach((item) => {
|
||||
if (item.children) {
|
||||
const activeChild = item.children.find(
|
||||
(child) => child.href && location.pathname === child.href
|
||||
);
|
||||
if (activeChild) {
|
||||
activeTitle = `${item.label}-${activeChild.label}`;
|
||||
// prefer child icon for the page; fallback to parent
|
||||
activeIcon = activeChild.icon ?? item.icon ?? null;
|
||||
}
|
||||
}
|
||||
if (!activeTitle && item.href && location.pathname === item.href) {
|
||||
activeTitle = item.label;
|
||||
activeIcon = item.icon ?? null;
|
||||
}
|
||||
});
|
||||
if (onTitleChange) {
|
||||
onTitleChange({ title: activeTitle ?? "صفحه اول", icon: activeIcon ?? null });
|
||||
}
|
||||
};
|
||||
|
||||
autoExpandParents();
|
||||
|
|
@ -207,8 +241,13 @@ export function Sidebar({
|
|||
const ItemIcon = item.icon;
|
||||
|
||||
const handleClick = () => {
|
||||
// Only update header title for navigable items (those with href)
|
||||
if (item.href && item.href !== "#") {
|
||||
const icon = item.icon ?? null;
|
||||
onTitleChange?.({ title: item.label, icon });
|
||||
}
|
||||
|
||||
if (item.id === "strategic-alignment") {
|
||||
console.log("test")
|
||||
onStrategicAlignmentClick?.();
|
||||
} else if (item.id === "logout") {
|
||||
logout();
|
||||
|
|
@ -222,7 +261,7 @@ export function Sidebar({
|
|||
<button
|
||||
key={item.id}
|
||||
className={cn(
|
||||
"flex items-center justify-center w-full px-2 rounded-lg mt-4 transition-all duration-200 group",
|
||||
"flex items-center justify-center w-full px-2 rounded-none mt-4 transition-all duration-200 group",
|
||||
)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
|
|
@ -242,22 +281,24 @@ export function Sidebar({
|
|||
<Link to={item.href} className="block">
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center justify-between w-full py-2 px-3 rounded-lg transition-all duration-200 group",
|
||||
"flex items-center justify-between rounded-none w-full py-2 px-3 transition-all duration-200 group",
|
||||
level === 0 ? "mb-1" : "mb-0.5 mr-4",
|
||||
isActive
|
||||
? " text-emerald-400 border-r-2 border-emerald-400"
|
||||
: "text-gray-300 hover:bg-gradient-to-r hover:from-emerald-500/10 hover:to-teal-500/10 hover:text-emerald-300",
|
||||
? " text-pr-green border-r-2 border-pr-green"
|
||||
: "text-gray-300 hover:text-pr-green",
|
||||
isCollapsed && level === 0 && "justify-center px-2",
|
||||
item.id === "logout" && "hover:bg-red-500/10 hover:text-red-400"
|
||||
item.id === "logout" && "hover:text-pr-red"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-3 min-w-0 flex-1">
|
||||
{ItemIcon && (
|
||||
<ItemIcon
|
||||
className={cn(
|
||||
"w-5 h-5 flex-shrink-0",
|
||||
isActive ? "text-emerald-400" : "text-current"
|
||||
isActive ? "text-pr-green" : "text-current"
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{!isCollapsed && (
|
||||
<span className="font-persian text-sm font-medium truncate">
|
||||
{item.label}
|
||||
|
|
@ -268,7 +309,7 @@ export function Sidebar({
|
|||
{!isCollapsed && (
|
||||
<div className="flex items-center gap-2 flex-shrink-0">
|
||||
{item.badge && (
|
||||
<span className="bg-gradient-to-r from-emerald-500/20 to-teal-500/20 text-emerald-400 text-xs font-medium px-1.5 py-0.5 rounded-full min-w-[20px] text-center font-persian">
|
||||
<span className="bg-gradient-to-r from-emerald-500/20 to-teal-500/20 text-pr-green text-xs font-medium px-1.5 py-0.5 rounded-full min-w-[20px] text-center font-persian">
|
||||
{item.badge}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -299,22 +340,24 @@ export function Sidebar({
|
|||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center justify-between w-full py-2 px-3 rounded-lg transition-all duration-200 group",
|
||||
"flex items-center justify-between w-full py-2 px-3 rounded-none transition-all duration-200 group",
|
||||
level === 0 ? "mb-1" : "mb-0.5 mr-4",
|
||||
isActive
|
||||
? " text-emerald-400 border-r-2 border-emerald-400"
|
||||
: "text-gray-300 hover:bg-gradient-to-r hover:from-emerald-500/10 hover:to-teal-500/10 hover:text-emerald-300",
|
||||
? " text-pr-green border-r-2 border-pr-green"
|
||||
: "text-gray-300 cursor-pointer hover:text-pr-green",
|
||||
isCollapsed && level === 0 && "justify-center px-2",
|
||||
item.id === "logout" && "hover:bg-red-500/10 hover:text-red-400"
|
||||
item.id === "logout" && "hover:text-pr-red"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-3 min-w-0 flex-1">
|
||||
{ItemIcon && (
|
||||
<ItemIcon
|
||||
className={cn(
|
||||
"w-5 h-5 flex-shrink-0",
|
||||
isActive ? "text-emerald-400" : "text-current"
|
||||
isActive ? "text-pr-green" : "text-current"
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{!isCollapsed && (
|
||||
<span className="font-persian text-sm font-medium truncate">
|
||||
{item.label}
|
||||
|
|
@ -325,7 +368,7 @@ export function Sidebar({
|
|||
{!isCollapsed && (
|
||||
<div className="flex items-center gap-2 flex-shrink-0">
|
||||
{item.badge && (
|
||||
<span className="bg-gradient-to-r from-emerald-500/20 to-teal-500/10 text-emerald-400 text-xs font-medium px-1.5 py-0.5 rounded-full min-w-[20px] text-center font-persian">
|
||||
<span className="bg-gradient-to-r from-emerald-500/20 to-teal-500/10 text-pr-green text-xs font-medium px-1.5 py-0.5 rounded-full min-w-[20px] text-center font-persian">
|
||||
{item.badge}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -340,7 +383,7 @@ export function Sidebar({
|
|||
(child) =>
|
||||
child.href && location.pathname === child.href
|
||||
)
|
||||
? "text-emerald-400"
|
||||
? "text-pr-green"
|
||||
: "text-current"
|
||||
)}
|
||||
/>
|
||||
|
|
@ -392,7 +435,7 @@ export function Sidebar({
|
|||
/>
|
||||
<div className="font-persian">
|
||||
<div className="text-sm font-semibold text-white">
|
||||
داشبورد اینوژن
|
||||
اینوژن بندر امام
|
||||
</div>
|
||||
<div className="text-xs text-gray-400">نسخه ۰.۱</div>
|
||||
</div>
|
||||
|
|
@ -431,7 +474,7 @@ export function Sidebar({
|
|||
</div>
|
||||
|
||||
{/* Collapse Toggle */}
|
||||
{onToggleCollapse && (
|
||||
{/* {onToggleCollapse && (
|
||||
<div className="p-3 border-t border-gray-500/30">
|
||||
<button
|
||||
onClick={onToggleCollapse}
|
||||
|
|
@ -448,7 +491,7 @@ export function Sidebar({
|
|||
)}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,18 +24,18 @@ export function FunnelChart({ data, title, className = "" }: FunnelChartProps) {
|
|||
return (
|
||||
<div className={`w-full ${className}`}>
|
||||
{title && (
|
||||
<h3 className="text-lg font-semibold text-white mb-4 py-2 text-right border-b-2 border-gray-400/20">
|
||||
<h3 className="text-sm px-4 font-semibold text-white mb-4 py-2 text-right border-b-2 border-gray-400/20">
|
||||
{title}
|
||||
</h3>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col items-center gap-2 space-y-2">
|
||||
<div className="flex px-4 flex-col items-center gap-2 space-y-2">
|
||||
{/* Start Process Line */}
|
||||
<div className="flex items-center w-full gap-10 mt-6">
|
||||
<div className="text-lg text-gray-600 min-w-[max-content]">ابتدا فرآیند</div>
|
||||
<div className="flex items-center w-full gap-10 mt-6 px-4">
|
||||
<div className="text-sm font-normal text-[#5F6284] min-w-[max-content]">ابتدا فرآیند</div>
|
||||
<div className="flex items-center w-full gap-4">
|
||||
<div className="w-full h-0.5 bg-gray-600 relative">
|
||||
<div className="text-2xl text-white absolute left-1/2 -translate-x-1/2 top-[-1rem] -translate-y-1/2">۱۰۰%</div>
|
||||
<div className="text-base text-white font-semibold absolute left-1/2 -translate-x-1/2 top-[-1rem] -translate-y-1/2">۱۰۰%</div>
|
||||
<div className="absolute -top-1 left-0 w-1 h-3 bg-gray-600"></div>
|
||||
<div className="absolute -top-1 right-0 w-1 h-3 bg-gray-600"></div>
|
||||
</div>
|
||||
|
|
@ -50,7 +50,7 @@ export function FunnelChart({ data, title, className = "" }: FunnelChartProps) {
|
|||
|
||||
return (
|
||||
<div key={index} className="grid grid-cols-[6rem_1fr] gap-2 w-full">
|
||||
<div className="text-lg text-white cols-start-1 justify-self-start font-thin min-w-[max-content] text-center">
|
||||
<div className="text-sm font-light text-white cols-start-1 justify-self-start font-thin min-w-[max-content] text-center">
|
||||
{item.label}
|
||||
</div>
|
||||
<div className="flex items-center gap-10 w-full cols-start-2 flex items-center justify-center w-full">
|
||||
|
|
@ -60,7 +60,7 @@ export function FunnelChart({ data, title, className = "" }: FunnelChartProps) {
|
|||
className="bg-[#3BC47A] h-8 rounded-2xl flex items-center justify-center text-lg relative"
|
||||
style={{ width: `${barWidth}%` }}
|
||||
>
|
||||
<span className="text-[#3F415A] font-semibold">
|
||||
<span className="text-pr-gray text-base font-semibold">
|
||||
{item.value.toLocaleString('fa-IR')}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -73,15 +73,15 @@ export function FunnelChart({ data, title, className = "" }: FunnelChartProps) {
|
|||
</div>
|
||||
|
||||
{/* End Process Line */}
|
||||
<div className="flex items-center w-full gap-10">
|
||||
<div className="text-lg text-gray-600 min-w-[max-content]">انتها فرآیند</div>
|
||||
<div className="flex items-center w-full gap-10 px-4">
|
||||
<div className="text-sm text-[#5F6284] min-w-[max-content]">انتها فرآیند</div>
|
||||
<div className="flex items-center w-full gap-4">
|
||||
{(() => {
|
||||
const lastValue = data[data.length - 1]?.value ?? 0;
|
||||
const percent = toPercent(lastValue);
|
||||
return (
|
||||
<div style={{ width: `${percent}%` }} className={`mx-auto h-0.5 bg-gray-600 relative ${percent === 0 ? "hidden" : ""}`}>
|
||||
<div className="text-2xl text-white absolute left-1/2 -translate-x-1/2 bottom-[-2.5rem] -translate-y-1">{formatNumber(percent)}%</div>
|
||||
<div className="text-base font-semibold text-white absolute left-1/2 -translate-x-1/2 bottom-[-2.5rem] -translate-y-1">{formatNumber(percent)}%</div>
|
||||
<div className="absolute -top-1 left-0 w-1 h-3 bg-gray-600"></div>
|
||||
<div className="absolute -top-1 right-0 w-1 h-3 bg-gray-600"></div>
|
||||
</div>
|
||||
|
|
|
|||
536
public/font/Fa Numral Help.html
Normal file
536
public/font/Fa Numral Help.html
Normal file
File diff suppressed because one or more lines are too long
426
public/font/IranYekanX.html
Normal file
426
public/font/IranYekanX.html
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
<!doctype html>
|
||||
<html lang="fa">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IRANYekanX Family Type face: خانواده فونت ایرانسنس</title>
|
||||
|
||||
<meta name="fontiran.com:license" content="کد ۵ رقمی لایسنس">
|
||||
|
||||
<link href="style.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
|
||||
<body dir="rtl">
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="titelbox">
|
||||
<h1>بِسْمِ اللهِ الرَّحْمَنِ الرَّحِيمِ</h1>
|
||||
</div>
|
||||
<div class="alphabet" style="line-height:200px" > د </div>
|
||||
<div class="rightbox">
|
||||
<br>
|
||||
<span class="text-xlarge">ن وَالْقَلَمِ وَ مَا يَسْطُرُون</span>
|
||||
<br>
|
||||
<span class="text-xlarge"> نون؛ سوگند به قلم و آنچه می نويسند. </span>
|
||||
<br>
|
||||
<span class="text-large"> Noon. I swear by the pen and what the angels write </span>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
|
||||
<div class="titelbox" style="letter-spacing: 0px">
|
||||
<h1>نکاتی درباره تایپوگرافی وب</h1>
|
||||
</div>
|
||||
|
||||
<div class="alphabet" style="line-height:250px" > ج </div>
|
||||
<div class="rightbox">
|
||||
<p>از زمان پیدایش نخستین وب سایت، متن ها یکی از اجزای مهم صفحات وب بودند. هر چند به مرور زمان با ورود تصاویر، صوت و فیلم کمی از بار مسئولیت متون کم شد اما هنوز جایگاه خود را از دست نداده اند و بخش مهمی از کار را به عهده دارند.</p>
|
||||
<p>بسیاری از طراحان وب سایت به صورت تجربی بهترین ترکیب و ظاهر را برای نمایش متن ها انتخاب می کنند. اما اصولی وجود دارد که با رعایت آن ها، تاثیرپذیری و زیبایی سایت چند برابر خواهد شد.</p>
|
||||
<p>در ادامه مطلب قصد داریم تعدادی از اصول مقدماتی تایپوگرافی را به اختصار مرور کنیم. هرچند بسیاری از دوستان با این نکات آشنا هستند؛ اما شاید مرور آن ها خالی از لطف نباشد.</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="titelbox" style="letter-spacing: 0px">
|
||||
<h1>تاثیر اندازه فونت و سلسله مراتب تگها</h1>
|
||||
</div>
|
||||
<div class="alphabet" style="line-height:170px"> ن </div>
|
||||
<div class="rightbox">
|
||||
<p>فونت های داخل سایت باید به گونه ای قرار گیرند که کاربر به راحتی بتواند آن ها را بخواند. نوع فونت، وزن و کوچک (یا بزرگ) بودن اندازه آن ممکن است تمایل کاربر برای بازگشت به وب سایت را کاهش دهد. قواعد و قوانین زیادی برای انتخاب بهترین فونت وجود دارد.</p>
|
||||
<p>در زیر می توانید ۱۲ وزن مختلف <strong>خانواده فونت ایرانسنس</strong> را در شرایط یکسان مشاهده کنید. لازم به ذکر است برای این صفحه از وزن معمولی (Normal) استفاده شده است.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2">
|
||||
<div class="text-thin" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Thin)</div>
|
||||
<div class="text-UltraLight" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (UltraLight)</div>
|
||||
<div class="text-light" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Light)</div>
|
||||
<div class="text-regular" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Regular)</div>
|
||||
<div class="text-medium" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Medium)</div>
|
||||
<div class="text-demibold" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (demiBold)</div>
|
||||
<div class="text-bold" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Bold)</div>
|
||||
<div class="text-extrabold" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (ExtraBold)</div>
|
||||
<div class="text-black" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Black)</div>
|
||||
<div class="text-extrablack" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (ExtraBlack)</div>
|
||||
<div class="text-heavy" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Heavy)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2">
|
||||
|
||||
<div class="text-thin" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Thin)</div>
|
||||
<div class="text-UltraLight" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (UltraLight)</div>
|
||||
<div class="text-light" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Light)</div>
|
||||
<div class="text-regular" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Regular)</div>
|
||||
<div class="text-medium" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Medium)</div>
|
||||
<div class="text-demibold" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (demiBold)</div>
|
||||
<div class="text-bold" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Bold)</div>
|
||||
<div class="text-extrabold" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (ExtraBold)</div>
|
||||
<div class="text-black" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Black)</div>
|
||||
<div class="text-extrablack" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (ExtraBlack)</div>
|
||||
<div class="text-heavy" style="font-size:2.2em">من نه آنم که زبونی کشم از چرخ فلک (Heavy)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="titelbox" style="letter-spacing: 0px">
|
||||
<h1>تگهای هدینگ</h1>
|
||||
</div>
|
||||
<div class="alphabet" style="line-height:180px"> و </div>
|
||||
<div class="rightbox">
|
||||
<p>در این بین، استفاده از تگ های هدینگ مناسب و رعایت سلسله مراتب آن ها، هم مفهوم نوشته را بهتر منتقل می کند و هم تاثیر قابل توجهی در نتایج موتورهای جستجو خواهد داشت. این نکته یکی از فاکتورهای مهم در بهینه سازی وب سایت برای موتورهای جستجو (Search Engine Optimization) است.</p>
|
||||
<p>نمونه ای از خروجی تگ های هدینگ با سایز استاندارد مربوطه به فونت های فونت ایرانسنس را در زیر مشاهده می کنید.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2">
|
||||
<h1>(H1) نابرده رنج گنج میسر نمی شود. No gain without pain </h1>
|
||||
<h2>(H2) نابرده رنج گنج میسر نمی شود. No gain without pain</h2>
|
||||
<h3>(H3) نابرده رنج گنج میسر نمی شود. No gain without pain</h3>
|
||||
<h4>(H4) نابرده رنج گنج میسر نمی شود. No gain without pain </h4>
|
||||
<h5>(H5) نابرده رنج گنج میسر نمی شود. No gain without pain</h5>
|
||||
<h6>(H6) نابرده رنج گنج میسر نمی شود. No gain without pain</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2">
|
||||
<h1>(H1) نابرده رنج گنج میسر نمی شود. No gain without pain </h1>
|
||||
<h2>(H2) نابرده رنج گنج میسر نمی شود. No gain without pain</h2>
|
||||
<h3>(H3) نابرده رنج گنج میسر نمی شود. No gain without pain</h3>
|
||||
<h4>(H4) نابرده رنج گنج میسر نمی شود. No gain without pain </h4>
|
||||
<h5>(H5) نابرده رنج گنج میسر نمی شود. No gain without pain</h5>
|
||||
<h6>(H6) نابرده رنج گنج میسر نمی شود. No gain without pain</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="titelbox" style="letter-spacing: 0px">
|
||||
<h1>سطر و ستون بندی</h1>
|
||||
</div>
|
||||
<div class="alphabet" style="line-height:200px"> م </div>
|
||||
<div class="rightbox">
|
||||
<p>معمولاً هرگاه مقدار نوشته از یک سطر بیشتر شود ناگزیر به ستون بندی هستیم. و این کار ما را با چند متغییر مواجه خواهد کرد:</p>
|
||||
<p>۱- <strong>عرض ستونهای متنی</strong> که حاوی حداقل۷ کلمه باشد بهترین انتخاب است. اگر ستون کوتاهتر باشد چشم بیننده در اثر حرکتهای زود به زود از پایان یک سطر به ابتدای سطر بعدی خسته خواهد شد. علاوه بر این لبه ستونهایی با عرض کم نیز همیشه دندانه ای و بی نظم خواهد بود. ستونهایی با عرض طولانی هم برای خواننده آزار دهنده است چرا که چشم در حرکت بازگشت از انتهای یک سطر به ابتدای سطر بعدی ممکن است دچار اشتباه شود.
|
||||
|
||||
<p>۲- <strong>لدینگ یا همان فاصله سطر </strong> هم در ستون بندی اهمیت دارد. ستونهای فشرده اگرچه به لحاظ گرافیکی منسجم و زیبا هستند اما عمل خواندن را مختل می کنند و در مقابل، فاصله سطر زیاد نیز باعث نازیبایی و خستگی چشم خواننده میشود. فاصله سطر همیشه می تواند با توجه به نوع فونت و عرض ستونها تغییر کند. بدین ترتیب که فونتهایی با دندانههای بلندتر و ستونهایی با عرض بیشتر به لدینگ بیشتری نیاز دارند.
|
||||
<p>۳- <strong>همترازی </strong> هم یکی از متغییرهای پر بحث در ستون بندی است. اما به طور کوتاه و خلاصه باید گفت که بهتر است در متن فارسی از همترازی یا همان Justification استفاده نکنید. این عمل اگرچه لبه پاراگراف شما را مرتب خواهد کرد اما تنظیمات فاصله حروف را تغییر خواهد داد و در نتیجه باعث کاهش خوانایی خواهد شد. </div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX Thin)</div>
|
||||
<div class="farsiparagraph"><span class="text-thin">ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-thin">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX UltraLight)</div>
|
||||
<div class="farsiparagraph"><span class="text-UltraLight">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-UltraLight">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX Light)</div>
|
||||
<div class="farsiparagraph"><span class="text-light">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-light">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX Regular)</div>
|
||||
<div class="farsiparagraph"><span class="text-regular">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-regular">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX Mediume)</div>
|
||||
<div class="farsiparagraph"><span class="text-medium">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-medium">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX DemiBold)</div>
|
||||
<div class="farsiparagraph"><span class="text-demibold">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-demibold">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX Bold)</div>
|
||||
<div class="farsiparagraph"><span class="text-bold">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-bold">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX ExtraBold)</div>
|
||||
<div class="farsiparagraph"><span class="text-extrabold">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-extrabold">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX Black)</div>
|
||||
<div class="farsiparagraph"><span class="text-black">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-black">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX ExtraBlack)</div>
|
||||
<div class="farsiparagraph"><span class="text-extrablack">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-extrablack">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="mainbox2negativ">(IRANYekanX Heavy)</div>
|
||||
<div class="farsiparagraph"><span class="text-heavy">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-heavy">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX Thin)</div>
|
||||
<div class="farsiparagraph"><span class="text-thin">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-thin">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX UltraLight)</div>
|
||||
<div class="farsiparagraph"><span class="text-UltraLight">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-UltraLight">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX Light)</div>
|
||||
<div class="farsiparagraph"><span class="text-light">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-light">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX Regular)</div>
|
||||
<div class="farsiparagraph"><span class="text-regular">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-regular">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX Mediume)</div>
|
||||
<div class="farsiparagraph"><span class="text-medium">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-medium">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX DemiBold)</div>
|
||||
<div class="farsiparagraph"><span class="text-demibold">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-demibold">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX Bold)</div>
|
||||
<div class="farsiparagraph"><span class="text-bold">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-bold">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX ExtraBold)</div>
|
||||
<div class="farsiparagraph"><span class="text-extrabold">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-extrabold">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX Black)</div>
|
||||
<div class="farsiparagraph"><span class="text-black">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-black">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX ExtraBlack)</div>
|
||||
<div class="farsiparagraph"><span class="text-extrablack">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-extrablack">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainboxnegativ">
|
||||
<div class="mainbox2negativ">(IRANYekanX Heavy)</div>
|
||||
<div class="farsiparagraph"><span class="text-heavy">
|
||||
ایرانیکان IRANYekanX از ترکیب دو فونت پر طرفدار یکان و ایرانسنس پدید آمده است. بخشی از منحنیهای ایرانسنس به ساختار عمودی و افقی یکان اضافه شده است تا ایرانیکان IRANYekanX فونتی باشد که با وجود هندسی بودن خشک و مکانیکی نباشد. این فونت با سبکهای طراحی کمینهگرا Minimal سازگاری خوبی دارد و همنشین مناسبی برای فونتهای سنسریف لاتین است. </span></div>
|
||||
|
||||
<div class="englishparagraph"><span class="text-heavy">
|
||||
Roboto has a dual nature. It has a mechanical skeleton and the forms are largely geometric. At the same time, the font features friendly and open curves. While some grotesks distort their letterforms to force a rigid rhythm, Roboto doesn’t compromise, allowing letters to be settled into their natural width. This makes for a more natural reading rhythm more commonly found in humanist and serif types.</span></div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="titelbox" style="letter-spacing: 0px">
|
||||
<h1>اعداد و علائم در فونت فارسی</h1>
|
||||
</div>
|
||||
<div class="alphabet" style="line-height:470px"> ظ </div>
|
||||
<div class="rightbox">
|
||||
<p><span class="text-xlarge">اعداد فارسی: <strong>۱۲۳۴۵۶۷۸۹۰</strong></span><br>
|
||||
<span class="text-xlarge">اعداد عربی: <strong>۱۲۳٤٥٦۷۸۹۰</strong></span><br>
|
||||
<span class="text-xlarge">اعداد انگلیسی: <strong>1234567890</strong></span></p>
|
||||
<p>برای تایپ اعداد فارسی در محیط وب از <a href="http://fontiran.com/%d9%86%d8%b5%d8%a8-%da%a9%db%8c%d8%a8%d9%88%d8%b1%d8%af-%d9%81%d8%a7%d8%b1%d8%b3%db%8c-%d8%a7%d8%b3%d8%aa%d8%a7%d9%86%d8%af%d8%a7%d8%b1%d8%af-%d8%af%d8%b1-%d9%88%db%8c%d9%86%d8%af%d9%88%d8%b28-%d9%88/">کیبورد استاندارد فارسی</a> استفاده کنید. در ویندوز ۸ و یا بالاتر این کیبورد، با نام Persian(Standard)Keyboard در لیست کیبوردهای ویندوز وجود دارد. همچنین می توانید از <a href="http://persian-computing.ir/download/Iranian_Standard_Persian_Keyboard_(ISIRI_9147)_(Version_2.0).zip">این آدرس</a> آن را دانلود و نصب کنید.</p>
|
||||
<span>
|
||||
<p>با استفاده از کیبورد استاندارد میتوانید ممیز فارسی را تایپ کنید.<br>
|
||||
<span>میانبر این علامت کلیدهای <span class="text-medium">Shift+3</span> است. به این شکل: <strong class="text-xlarge">۳٫۱۴</strong></span><br>
|
||||
<span >ممیز فارسی با علامت اسلش تفاوت دارد :<strong class="text-xlarge">۳/۱۴</strong></span>
|
||||
</p>
|
||||
<p>با استفاده از کیبورد استاندارد میتوانید جداکننده هزارگان فارسی را تایپ کنید.<br>
|
||||
<span>میانبر این علامت کلیدهای <strong>Shift+2</strong> است. به این شکل: <strong class="text-xlarge">۹٬۲۱۰٬۰۰۰</strong></span><br>
|
||||
<span >این علامت با جدا کننده هزارگان انگلیسی تفاوت دارد : <strong class="text-xlarge">۹,۲۱۰,۰۰۰</strong></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="titelbox" style="letter-spacing: 0px">
|
||||
<h1> نسبتهای طلایی</h1>
|
||||
</div>
|
||||
<div class="alphabet2">
|
||||
<div style="padding-left:20px">
|
||||
۳٫۷۷۷ ÷ ۱٫۶۱۸ = <span class="text-regular text-underline">۲٫۳۳۵</span>
|
||||
<br>
|
||||
۶٫۱۱۲ ÷ ۱٫۶۱۸ = <span class="text-regular text-underline">۳٫۷۷۷</span>
|
||||
<br>
|
||||
۹٫۸۸۹ ÷ ۱٫۶۱۸ = <span class="text-regular text-underline">۶٫۱۱۲</span>
|
||||
<br>
|
||||
۱۶ ÷ ۱٫۶۱۸ = <span class="text-regular text-underline">۹٫۸۸۹</span>
|
||||
<br>
|
||||
.......................................
|
||||
<br>
|
||||
۱۶ × ۱٫۶۱۸ = <span class="text-regular text-underline">۲۵٫۸۸۸</span>
|
||||
<br>
|
||||
۲۵٫۸۸۸ × ۱٫۶۱۸ = <span class="text-regular text-underline">۴۱٫۸۸۷</span>
|
||||
<br>
|
||||
۴۱٫۸۸۷ × ۱٫۶۱۸ = <span class="text-regular text-underline">۶۷٫۷۷۳</span>
|
||||
<br>
|
||||
۶۷٫۷۷۳ × ۱٫۶۱۸ = <span class="text-regular text-underline">۱۰۹٫۶۵۶</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rightbox">
|
||||
<p>اهمیت اندازه فونت در خوانایی و زیبا شدن صفحه وب سایت بر کسی پوشیده نیست. در کنار این بحث، موارد دیگری مانند ارتفاع خطوط، فاصله ها، ابعاد قسمت های مختلف و ... نیز در بحث تایپوگرافی اهمیت زیادی دارند.</p>
|
||||
<p>برای محاسبه این اعداد می توانیم از سری اعداد متناسب (Modular Scale) استفاده کنیم. در حقیقت از تعدادی عدد پشت سر هم که بر اساس مضرب خاصی تشکیل شده اند برای تنظیمات ارتفاع خط، فاصله ها، ابعاد و ... استفاده می کنیم. نسبت (عدد) طلایی همان مضرب اعداد است.</p>
|
||||
<p>به عنوان مثال می خواهیم از سایز 16px <strong>فونت ایرانسنس</strong> به عنوان فونت و سایز اصلی متن صفحات استفاده کنیم. عدد فی (phi) یونانی که معادل ۱٫۶۱۸۰۳۳۹۸۸۷ (به اختصار ۱٫۶۱۸) است را به عنوان نسبت طلایی در نظر می گیریم. بنابراین سری اعدادی به شکل روبرو خواهیم داشت:</p>
|
||||
|
||||
<p>
|
||||
به کمک این اعداد و استفاده از آن ها در صفحات وب سایت خود می توانیم خوانایی و زیبایی آن را افزایش دهیم. علاوه بر آن، اگر از واحدهای نسبی مانند em استفاده شود، امکانات بیشتری در اختیار طراح و بازدیدکننده خواهد بود. البته <strong>سری اعداد بر مبنای نسبت طلایی</strong> فقط در تایپوگرافی وب سایت کاربرد ندارد.
|
||||
این اعداد می تواند ادامه داشته باشد (<span class="text-regular text-underline">۱٬۲۱۵٫۹۸۱</span> ، <span class="text-regular text-underline">۱٬۹۶۷٫۴۵۷</span> ، <span class="text-regular text-underline">۳٬۱۸۳٫۳۴۵</span> و ...).
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mainbox">
|
||||
<div class="rightbox">
|
||||
<br>
|
||||
در این فایل سعی کردیم همراه با یک مطلب آموزشی کوتاه، نحوه استفاده از خانواده فونت ایرانسنس و پیش نمایشی از قسمت های مختلف آن را مرور کنیم.
|
||||
<br>
|
||||
برای مشاهده راهنمای نحوه قراردادن فونت ها در وب سایت خود، به <a href="http://fontiran.com/%d9%86%d8%b5%d8%a8-%d9%81%d9%88%d9%86%d8%aa-%d8%a7%db%8c%d8%b1%d8%a7%d9%86-%d8%b3%d9%86%d8%b3-iransans-%d8%b1%d9%88%db%8c-%d9%88%d8%a8%d8%b3%d8%a7%db%8c%d8%aa/" target="_blank">این آدرس</a> مراجعه کنید.
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
<div class="alphabet" style="line-height:180px">ء</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="footer">
|
||||
Copyright (c) 2021 by <a href="http://fontiran.com">www.fontiran.com</a> (Moslem Ebrahimi). All rights reserved.
|
||||
<br>
|
||||
To use this font, it is necessary to obtain the license from www.fontiran.com
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
108
public/font/fontiran.css
Normal file
108
public/font/fontiran.css
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
*
|
||||
* Name: IRANYekanX Fonts
|
||||
* Version: 2.4
|
||||
* Author: Moslem Ebrahimi (moslemebrahimi.com)
|
||||
* Created on: Aug 02, 2022
|
||||
* Updated on: Aug 02, 2022
|
||||
* Website: http://fontiran.com
|
||||
* Copyright: Commercial/Proprietary Software
|
||||
--------------------------------------------------------------------------------------
|
||||
فونت ایران یکان X یک نرم افزار مالکیتی محسوب می شود. جهت آگاهی از قوانین استفاده از این فونت ها لطفا به وب سایت (فونت ایران دات کام) مراجعه نمایید
|
||||
--------------------------------------------------------------------------------------
|
||||
IRANYekanX fonts are considered a proprietary software. To gain information about the laws regarding the use of these fonts, please visit www.fontiran.com
|
||||
--------------------------------------------------------------------------------------
|
||||
This set of fonts are used in this project under the license: (.....)
|
||||
------------------------------------------------------------------------------------- fonts/-
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: url('woff/IRANYekanX-Thin.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-Thin.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url('woff/IRANYekanX-UltraLight.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-UltraLight.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url('woff/IRANYekanX-Light.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-Light.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('woff/IRANYekanX-Medium.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-Medium.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url('woff/IRANYekanX-DemiBold.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-DemiBold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
src: url('woff/IRANYekanX-ExtraBold.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-ExtraBold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url('woff/IRANYekanX-Black.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-Black.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 950;
|
||||
src: url('woff/IRANYekanX-ExtraBlack.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-ExtraBlack.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: 1000;
|
||||
src: url('woff/IRANYekanX-Heavy.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-Heavy.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
src: url('woff/IRANYekanX-Bold.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-Bold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANYekanX;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: url('woff/IRANYekanX-Regular.woff') format('woff'),
|
||||
url('woff2/IRANYekanX-Regular.woff2') format('woff2');
|
||||
}
|
||||
|
||||
|
||||
463
public/font/fonttest.html
Normal file
463
public/font/fonttest.html
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
<head>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9" />
|
||||
<title>IRANYekanX</title>
|
||||
<style type="text/css" media="screen">
|
||||
@font-face { font-family: 'WOFF IRANYekanX-Thin'; src: url('woff/IRANYekanX-Thin.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-UltraLight'; src: url('woff/IRANYekanX-UltraLight.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-Light'; src: url('woff/IRANYekanX-Light.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-Regular'; src: url('woff/IRANYekanX-Regular.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-Medium'; src: url('woff/IRANYekanX-Medium.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-DemiBold'; src: url('woff/IRANYekanX-DemiBold.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-Bold'; src: url('woff/IRANYekanX-Bold.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-ExtraBold'; src: url('woff/IRANYekanX-ExtraBold.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-Black'; src: url('woff/IRANYekanX-Black.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-ExtraBlack'; src: url('woff/IRANYekanX-ExtraBlack.woff'); }
|
||||
@font-face { font-family: 'WOFF IRANYekanX-Heavy'; src: url('woff/IRANYekanX-Heavy.woff'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-Thin'; src: url('woff2/IRANYekanX-Thin.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-UltraLight'; src: url('woff2/IRANYekanX-UltraLight.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-Light'; src: url('woff2/IRANYekanX-Light.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-Regular'; src: url('woff2/IRANYekanX-Regular.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-Medium'; src: url('woff2/IRANYekanX-Medium.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-DemiBold'; src: url('woff2/IRANYekanX-DemiBold.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-Bold'; src: url('woff2/IRANYekanX-Bold.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-ExtraBold'; src: url('woff2/IRANYekanX-ExtraBold.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-Black'; src: url('woff2/IRANYekanX-Black.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-ExtraBlack'; src: url('woff2/IRANYekanX-ExtraBlack.woff2'); }
|
||||
@font-face { font-family: 'WOFF2 IRANYekanX-Heavy'; src: url('woff2/IRANYekanX-Heavy.woff2'); }
|
||||
|
||||
body {
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
.features, .label, a, #controls {
|
||||
font: normal normal normal small sans-serif;
|
||||
}
|
||||
.features .emojiButton {
|
||||
vertical-align: -5%;
|
||||
font-size: small;
|
||||
}
|
||||
.emojiButton {
|
||||
cursor: pointer;
|
||||
}
|
||||
#flexbox {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
height: 100%;
|
||||
}
|
||||
#controls {
|
||||
flex: 0 1 auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
border: 0px solid transparent;
|
||||
height: auto;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
#metricsLine {
|
||||
background-color: #EEE;
|
||||
border-top: 1px solid #AAA;
|
||||
border-bottom: 1px solid #AAA;
|
||||
width: 100%;
|
||||
margin: 0.2em 0;
|
||||
padding: 0 0;
|
||||
font-size: 2em;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
text-overflow: none;
|
||||
display: none;
|
||||
scrollbar-width: none; /* Firefox */
|
||||
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
||||
}
|
||||
#metricsLine::-webkit-scrollbar { /* WebKit */
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
#waterfall {
|
||||
flex: 1 1 auto;
|
||||
border: 0 solid transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
color: black;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
font-family: "WOFF IRANYekanX-Thin";
|
||||
font-feature-settings: "kern" on, "liga" on, "calt" on;
|
||||
-moz-font-feature-settings: "kern" on, "liga" on, "calt" on;
|
||||
-webkit-font-feature-settings: "kern" on, "liga" on, "calt" on;
|
||||
-ms-font-feature-settings: "kern" on, "liga" on, "calt" on;
|
||||
-o-font-feature-settings: "kern" on, "liga" on, "calt" on;
|
||||
}
|
||||
div, p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#waterfall p {
|
||||
margin-bottom: 0.8em;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
.○ .sampletext {
|
||||
-webkit-text-stroke: 1px black;
|
||||
-webkit-text-fill-color: #FFF0;
|
||||
}
|
||||
.features, .label, a {
|
||||
color: #888;
|
||||
}
|
||||
.label {
|
||||
background-color: #ddd;
|
||||
padding: 2px 3px;
|
||||
}
|
||||
|
||||
span#p08 { font-size: 08pt; padding: 08pt 0; }
|
||||
span#p09 { font-size: 09pt; padding: 09pt 0; }
|
||||
span#p10 { font-size: 10pt; padding: 10pt 0; }
|
||||
span#p11 { font-size: 11pt; padding: 11pt 0; }
|
||||
span#p12 { font-size: 12pt; padding: 12pt 0; }
|
||||
span#p13 { font-size: 13pt; padding: 13pt 0; }
|
||||
span#p14 { font-size: 14pt; padding: 14pt 0; }
|
||||
span#p15 { font-size: 15pt; padding: 15pt 0; }
|
||||
span#p16 { font-size: 16pt; padding: 16pt 0; }
|
||||
span#largeParagraph { font-size: 32pt; padding: 32pt 0; }
|
||||
span#veryLargeParagraph { font-size: 100pt; padding: 100pt 0; }
|
||||
|
||||
.otFeatureLabel {
|
||||
color: #666;
|
||||
background-color: #ddd;
|
||||
padding: 0.2em 0.5em 0.3em 0.5em;
|
||||
margin: 0 .04em;
|
||||
line-height: 2em;
|
||||
border-radius: 0.3em;
|
||||
border: 0;
|
||||
text-align:center;
|
||||
}
|
||||
.otFeatureLabel, .otFeature {
|
||||
position: relative;
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.otFeatureLabel {
|
||||
padding: 0.2em 0.5em 0.3em 0.5em;
|
||||
margin: 0 .04em;
|
||||
line-height: 2em;
|
||||
color: #666;
|
||||
background-color: #ddd;
|
||||
border-radius: 0.3em;
|
||||
border: 0;
|
||||
text-align: center;
|
||||
z-index: 6;
|
||||
}
|
||||
.wrapper {
|
||||
width: auto;
|
||||
overflow: hidden;
|
||||
border: 0 solid transparent;
|
||||
}
|
||||
select {
|
||||
float: left;
|
||||
margin: 0 0.5em 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
input[type=text] {
|
||||
border: 1px solid #999;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.features {
|
||||
clear: left;
|
||||
}
|
||||
input[type=checkbox]:checked + label {
|
||||
visibility: visible;
|
||||
color: #fff;
|
||||
background-color: #888;
|
||||
}
|
||||
.otFeature {
|
||||
visibility: collapse;
|
||||
margin: 0 -1em 0 0;
|
||||
}
|
||||
.otFeatureLabel .tooltip {
|
||||
visibility: hidden;
|
||||
background-color: #333;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 0px 5px;
|
||||
top: -2em;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
z-index: 8;
|
||||
}
|
||||
.otFeatureLabel:hover .tooltip {
|
||||
visibility: visible;
|
||||
}
|
||||
#featureLine {
|
||||
display: none;
|
||||
border-bottom: 1px solid #999;
|
||||
padding: 0.5em 0;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/* Footer paragraph: */
|
||||
#helptext {
|
||||
color: black;
|
||||
background-color: #ddd;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
padding: 2px
|
||||
width: 100%;
|
||||
font: x-small sans-serif;
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: #333;
|
||||
}
|
||||
.features, .label, a, body, p, #metricsLine {
|
||||
color: white;
|
||||
}
|
||||
.label {
|
||||
background-color: black;
|
||||
padding: 2px 3px;
|
||||
}
|
||||
.otFeatureLabel, input[type=text] {
|
||||
color: white;
|
||||
background-color: black;
|
||||
}
|
||||
input[type=checkbox]:checked + label {
|
||||
color: black;
|
||||
background-color: #aaa;
|
||||
}
|
||||
#helptext {
|
||||
background-color: #777;
|
||||
}
|
||||
.○ .sampletext {
|
||||
-webkit-text-stroke: 1px white;
|
||||
-webkit-text-fill-color: #0000;
|
||||
}
|
||||
#metricsLine {
|
||||
background-color: #222;
|
||||
border-color: #777;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="document.getElementById('textInput').focus();setCharset();">
|
||||
<div id="flexbox">
|
||||
<div id="controls">
|
||||
<div>
|
||||
<select size="1" id="fontFamilySelector" name="fontFamilySelector" onchange="changeFont()">
|
||||
<option value="IRANYekanX-Thin.woff">WOFF IRANYekanX-Thin</option>
|
||||
<option value="IRANYekanX-UltraLight.woff">WOFF IRANYekanX-UltraLight</option>
|
||||
<option value="IRANYekanX-Light.woff">WOFF IRANYekanX-Light</option>
|
||||
<option value="IRANYekanX-Regular.woff">WOFF IRANYekanX-Regular</option>
|
||||
<option value="IRANYekanX-Medium.woff">WOFF IRANYekanX-Medium</option>
|
||||
<option value="IRANYekanX-DemiBold.woff">WOFF IRANYekanX-DemiBold</option>
|
||||
<option value="IRANYekanX-Bold.woff">WOFF IRANYekanX-Bold</option>
|
||||
<option value="IRANYekanX-ExtraBold.woff">WOFF IRANYekanX-ExtraBold</option>
|
||||
<option value="IRANYekanX-Black.woff">WOFF IRANYekanX-Black</option>
|
||||
<option value="IRANYekanX-ExtraBlack.woff">WOFF IRANYekanX-ExtraBlack</option>
|
||||
<option value="IRANYekanX-Heavy.woff">WOFF IRANYekanX-Heavy</option>
|
||||
<option value="IRANYekanX-Thin.woff2">WOFF2 IRANYekanX-Thin</option>
|
||||
<option value="IRANYekanX-UltraLight.woff2">WOFF2 IRANYekanX-UltraLight</option>
|
||||
<option value="IRANYekanX-Light.woff2">WOFF2 IRANYekanX-Light</option>
|
||||
<option value="IRANYekanX-Regular.woff2">WOFF2 IRANYekanX-Regular</option>
|
||||
<option value="IRANYekanX-Medium.woff2">WOFF2 IRANYekanX-Medium</option>
|
||||
<option value="IRANYekanX-DemiBold.woff2">WOFF2 IRANYekanX-DemiBold</option>
|
||||
<option value="IRANYekanX-Bold.woff2">WOFF2 IRANYekanX-Bold</option>
|
||||
<option value="IRANYekanX-ExtraBold.woff2">WOFF2 IRANYekanX-ExtraBold</option>
|
||||
<option value="IRANYekanX-Black.woff2">WOFF2 IRANYekanX-Black</option>
|
||||
<option value="IRANYekanX-ExtraBlack.woff2">WOFF2 IRANYekanX-ExtraBlack</option>
|
||||
<option value="IRANYekanX-Heavy.woff2">WOFF2 IRANYekanX-Heavy</option>
|
||||
</select>
|
||||
<div class="wrapper" spellcheck="false">
|
||||
<input type="text" value="Type Text Here." id="textInput" onclick="this.select();" onkeyup="updateParagraph()" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="features">
|
||||
<a href="javascript:setCharset();">Charset</a>
|
||||
<a href="javascript:setLat1();">Lat1</a>
|
||||
 
|
||||
<a href="https://caniuse.com/#feat=woff">woff</a>
|
||||
<a href="https://caniuse.com/#feat=woff2">woff2</a>
|
||||
 
|
||||
<a onclick="toggleInverse();" id="invert" class="emojiButton">🔲</a>
|
||||
<label><input type="checkbox" id="kern" value="kern" class="otFeature" onchange="updateFeatures()" checked><label for="kern" class="otFeatureLabel">kern</label>
|
||||
<label><input type="checkbox" id="liga" value="liga" class="otFeature" onchange="updateFeatures()" checked><label for="liga" class="otFeatureLabel">liga/clig</label>
|
||||
<label><input type="checkbox" id="calt" value="calt" class="otFeature" onchange="updateFeatures()" checked><label for="calt" class="otFeatureLabel">calt</label>
|
||||
<input type="checkbox" id="numr" value="numr" class="otFeature" onchange="updateFeatures()"><label for="numr" class="otFeatureLabel">numr</label>
|
||||
<input type="checkbox" id="dnom" value="dnom" class="otFeature" onchange="updateFeatures()"><label for="dnom" class="otFeatureLabel">dnom</label>
|
||||
<input type="checkbox" id="frac" value="frac" class="otFeature" onchange="updateFeatures()"><label for="frac" class="otFeatureLabel">frac</label>
|
||||
<input type="checkbox" id="init" value="init" class="otFeature" onchange="updateFeatures()"><label for="init" class="otFeatureLabel">init</label>
|
||||
<input type="checkbox" id="medi" value="medi" class="otFeature" onchange="updateFeatures()"><label for="medi" class="otFeatureLabel">medi</label>
|
||||
<input type="checkbox" id="fina" value="fina" class="otFeature" onchange="updateFeatures()"><label for="fina" class="otFeatureLabel">fina</label>
|
||||
<input type="checkbox" id="rlig" value="rlig" class="otFeature" onchange="updateFeatures()"><label for="rlig" class="otFeatureLabel">rlig</label>
|
||||
<input type="checkbox" id="dlig" value="dlig" class="otFeature" onchange="updateFeatures()"><label for="dlig" class="otFeatureLabel">dlig</label>
|
||||
<input type="checkbox" id="salt" value="salt" class="otFeature" onchange="updateFeatures()"><label for="salt" class="otFeatureLabel">salt</label>
|
||||
<input type="checkbox" id="ss01" value="ss01" class="otFeature" onchange="updateFeatures()"><label for="ss01" class="otFeatureLabel">ss01</label>
|
||||
<input type="checkbox" id="ss02" value="ss02" class="otFeature" onchange="updateFeatures()"><label for="ss02" class="otFeatureLabel">ss02</label>
|
||||
<input type="checkbox" id="ss03" value="ss03" class="otFeature" onchange="updateFeatures()"><label for="ss03" class="otFeatureLabel">ss03</label>
|
||||
<input type="checkbox" id="ss04" value="ss04" class="otFeature" onchange="updateFeatures()"><label for="ss04" class="otFeatureLabel">ss04</label>
|
||||
<label><input type="checkbox" value="show" onchange="updateFeatures();document.getElementById('featureLine').style.display=this.checked?'block':'none'">CSS</label>
|
||||
<label><input type="checkbox" value="show" onchange="updateFeatures();document.getElementById('metricsLine').style.display=this.checked?'block':'none'">Metrics</label>
|
||||
</p>
|
||||
<p class="features" id="featureLine">font-feature-settings: "kern" on, "liga" on, "calt" on;</p>
|
||||
</div>
|
||||
<div id="waterfall" class="●">
|
||||
<div id="metricsLine"></div>
|
||||
<p><span class="label">08</span> <span class="sampletext" id="p08"></span></p>
|
||||
<p><span class="label">09</span> <span class="sampletext" id="p09"></span></p>
|
||||
<p><span class="label">10</span> <span class="sampletext" id="p10"></span></p>
|
||||
<p><span class="label">11</span> <span class="sampletext" id="p11"></span></p>
|
||||
<p><span class="label">12</span> <span class="sampletext" id="p12"></span></p>
|
||||
<p><span class="label">13</span> <span class="sampletext" id="p13"></span></p>
|
||||
<p><span class="label">14</span> <span class="sampletext" id="p14"></span></p>
|
||||
<p><span class="label">15</span> <span class="sampletext" id="p15"></span></p>
|
||||
<p><span class="label">16</span> <span class="sampletext" id="p16"></span></p>
|
||||
<p><span class="sampletext" id="largeParagraph"></span></p>
|
||||
<p><span class="sampletext" id="veryLargeParagraph"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Disclaimer -->
|
||||
<p id="helptext" onmouseleave="vanish(this);">
|
||||
Ctrl-R: Reset Charset. Ctrl-L: Latin1. Ctrl-J: LTR/RTL. Ctrl-comma/period: step through fonts. Pull mouse across this note to make it disappear.
|
||||
</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
const selector = document.getElementById("fontFamilySelector");
|
||||
const selectorOptions = selector.options;
|
||||
const selectorLength = selectorOptions.length;
|
||||
|
||||
document.addEventListener('keyup', keyAnalysis);
|
||||
|
||||
function keyAnalysis(event) {
|
||||
if (event.ctrlKey) {
|
||||
if (event.code == 'KeyR') {
|
||||
setCharset();
|
||||
} else if (event.code == 'KeyL') {
|
||||
setLat1();
|
||||
} else if (event.code == 'KeyJ') {
|
||||
toggleLeftRight();
|
||||
} else if (event.code == 'Period') {
|
||||
selector.selectedIndex = (selector.selectedIndex + 1) % selectorLength;
|
||||
changeFont();
|
||||
} else if (event.code == 'Comma') {
|
||||
var newIndex = selector.selectedIndex - 1;
|
||||
if (newIndex<0) {
|
||||
newIndex = selectorLength - 1;
|
||||
}
|
||||
selector.selectedIndex = newIndex;
|
||||
changeFont();
|
||||
}
|
||||
}
|
||||
}
|
||||
function updateParagraph() {
|
||||
// update paragraph text based on user input:
|
||||
const txt = document.getElementById('textInput');
|
||||
const paragraphs = document.getElementsByClassName('sampletext');
|
||||
for (i = 0; i < paragraphs.length; i++) {
|
||||
paragraph = paragraphs[i];
|
||||
paragraph.textContent = txt.value;
|
||||
}
|
||||
|
||||
// update other elements:
|
||||
document.getElementById('metricsLine').textContent = txt.value;
|
||||
}
|
||||
function updateFeatures() {
|
||||
// update features based on user input:
|
||||
// first, get feature on/off line:
|
||||
var cssCode = "";
|
||||
var codeLine = "";
|
||||
var checkboxes = document.getElementsByClassName("otFeature")
|
||||
for (i = 0; i < checkboxes.length; i++) {
|
||||
var checkbox = checkboxes[i];
|
||||
codeLine += '"'+checkbox.id+'" ';
|
||||
codeLine += checkbox.checked ? 'on, ' : 'off, ';
|
||||
if (checkbox.name=="kern") {
|
||||
cssCode += "font-kerning: "
|
||||
cssCode += checkbox.checked ? 'normal; ' : 'none; ';
|
||||
} else if (checkbox.name=="liga") {
|
||||
codeLine += '"clig" '
|
||||
codeLine += checkbox.checked ? 'on, ' : 'off, ';
|
||||
cssCode += "font-variant-ligatures: "
|
||||
cssCode += checkbox.checked ? 'common-ligatures contextual; ' : 'no-common-ligatures no-contextual; ';
|
||||
} else if (checkbox.name=="dlig") {
|
||||
cssCode += "font-variant-ligatures: "
|
||||
cssCode += checkbox.checked ? 'discretionary-ligatures; ' : 'no-discretionary-ligatures; ';
|
||||
} else if (checkbox.name=="hlig") {
|
||||
cssCode += "font-variant-ligatures: "
|
||||
cssCode += checkbox.checked ? 'historical-ligatures; ' : 'no-historical-ligatures; ';
|
||||
}
|
||||
}
|
||||
codeLine = codeLine.slice(0, -2)
|
||||
|
||||
// then, apply line for every browser:
|
||||
const prefixes = ["","-moz-","-webkit-","-ms-","-o-",];
|
||||
const suffix = "font-feature-settings: "
|
||||
for (i = 0; i < prefixes.length; i++) {
|
||||
var prefix = prefixes[i];
|
||||
cssCode += prefix
|
||||
cssCode += suffix
|
||||
cssCode += codeLine
|
||||
cssCode += "; "
|
||||
}
|
||||
|
||||
document.getElementById('waterfall').style.cssText = cssCode;
|
||||
document.getElementById('featureLine').innerHTML = cssCode.replace(/;/g,";<br/>");
|
||||
changeFont();
|
||||
}
|
||||
function changeFont() {
|
||||
var selected_index = selector.selectedIndex;
|
||||
var selected_option_text = selector.options[selected_index].text;
|
||||
document.getElementById('waterfall').style.fontFamily = selected_option_text;
|
||||
}
|
||||
function setDefaultText(defaultText) {
|
||||
document.getElementById('textInput').value = decodeEntities(defaultText);
|
||||
updateParagraph();
|
||||
}
|
||||
function setLat1() {
|
||||
const lat1 = "من نه آنم که زبونی کشم از چرخ فلک";
|
||||
return setDefaultText(lat1);
|
||||
}
|
||||
function setCharset() {
|
||||
const completeCharSet =
|
||||
'من نه آنم که زبونی کشم از چرخ فلک'
|
||||
setDefaultText(completeCharSet);
|
||||
}
|
||||
function decodeEntities(string){
|
||||
var elem = document.createElement('div');
|
||||
elem.innerHTML = string;
|
||||
return elem.textContent;
|
||||
}
|
||||
function vanish(item) {
|
||||
item.style.setProperty("display", "none");
|
||||
}
|
||||
function toggleLeftRight() {
|
||||
const waterfall = document.getElementById("waterfall");
|
||||
if (waterfall.dir != "rtl") {
|
||||
waterfall.dir = "rtl";
|
||||
waterfall.align = "right";
|
||||
} else {
|
||||
waterfall.dir = "";
|
||||
waterfall.align = "";
|
||||
}
|
||||
}
|
||||
function toggleInverse() {
|
||||
const testText = document.getElementById("waterfall");
|
||||
if (testText) {
|
||||
const link = document.getElementById("invert");
|
||||
if (testText.className == "●") {
|
||||
testText.className = "○";
|
||||
link.textContent = "🔳";
|
||||
} else {
|
||||
testText.className = "●";
|
||||
link.textContent = "🔲";
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
BIN
public/font/letter-spacing-1.psd
Normal file
BIN
public/font/letter-spacing-1.psd
Normal file
Binary file not shown.
243
public/font/style.css
Normal file
243
public/font/style.css
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
@import url(fontiran.css); /* لینک فایلی که وظیفه بارگذاری فونت ها را برعهده دارد */
|
||||
body {
|
||||
font-family: IRANYekanX !important;
|
||||
direction: rtl;
|
||||
background-color: #cdcdcd;
|
||||
margin: 0;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6,input, textarea {
|
||||
font-family: IRANYekanX !important;
|
||||
}
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
}
|
||||
.wrapper {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.ltr {
|
||||
direction: ltr;
|
||||
}
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
.text-small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.text-xsmall {
|
||||
font-size: 0.6em;
|
||||
}
|
||||
.text-large {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.text-xlarge {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
.text-underline {
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
.text-thin {
|
||||
font-weight: 100;
|
||||
}
|
||||
.text-UltraLight {
|
||||
font-weight: 200;
|
||||
}
|
||||
.text-light {
|
||||
font-weight: 300;
|
||||
}
|
||||
.text-regular {
|
||||
font-weight: normal;
|
||||
}
|
||||
.text-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
.text-demibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
.text-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text-extrabold {
|
||||
font-weight: 800;
|
||||
}
|
||||
.text-black {
|
||||
font-weight: 900;
|
||||
}
|
||||
.text-extrablack {
|
||||
font-weight: 950;
|
||||
}
|
||||
.text-heavy {
|
||||
font-weight: 1000;
|
||||
}
|
||||
blockquote {
|
||||
font-weight: 700;
|
||||
padding: 10px;
|
||||
border: 1px dashed #666666;
|
||||
}
|
||||
|
||||
.mainbox {
|
||||
width: 100%;
|
||||
background-color: #EFEFEF;
|
||||
display: table;
|
||||
margin-bottom: 30px;
|
||||
border-right: 8px solid #00adb5;
|
||||
}
|
||||
|
||||
.mainboxnegativ {
|
||||
width: 100%;
|
||||
background-color: #303841;
|
||||
display: table;
|
||||
margin-bottom: 30px;
|
||||
border-right: 8px solid #00adb5;
|
||||
color: #F9F9F9;
|
||||
}
|
||||
|
||||
.mainbox2 {
|
||||
font-size: 1em;
|
||||
width: 90%;
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.mainboxitalic {
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
width: 90%;
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.mainbox3 {
|
||||
width: 100%;
|
||||
background-color: #DFDFDF;
|
||||
display: table;
|
||||
margin-bottom: 30px;
|
||||
border-right: 8px solid #FF5EAA;
|
||||
}
|
||||
|
||||
.mainbox2negativ {
|
||||
font-size: 1em;
|
||||
color: #F9F9F9;
|
||||
background-color: #000000;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
|
||||
.farsiparagraph {
|
||||
font-size: 1em;
|
||||
width: 47%;
|
||||
float:right;
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
}
|
||||
|
||||
.farsiparagraph_negativ {
|
||||
font-size: 1em;
|
||||
color: #F9F9F9;
|
||||
background-color: #000000;
|
||||
width: 47%;
|
||||
float:right;
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.englishparagraph {
|
||||
font-size: 1em;
|
||||
width: 47%;
|
||||
float: left;
|
||||
direction:ltr;
|
||||
padding-left: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.englishparagraph_negativ {
|
||||
font-size: 1em;
|
||||
color: #F9F9F9;
|
||||
background-color: #000000;
|
||||
width: 47%;
|
||||
float: left;
|
||||
direction:ltr;
|
||||
padding-left: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
|
||||
}
|
||||
.rightbox {
|
||||
width: 60%;
|
||||
padding-right: 20px;
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
margin-bottom: 0px;
|
||||
min-width: 0px;
|
||||
background-color: #F7F7F7;
|
||||
|
||||
}
|
||||
|
||||
.titelbox {
|
||||
width: 60%;
|
||||
padding-right: 25px;
|
||||
padding-left: 0px;
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
margin-bottom: 0px;
|
||||
min-width: 0px;
|
||||
background-color: #d5d5d5;
|
||||
color: #4B4B4B;
|
||||
}
|
||||
|
||||
|
||||
.lefttbox {
|
||||
|
||||
padding-right: 20px;
|
||||
padding-left: 4px;
|
||||
float: right;
|
||||
margin-bottom: 10px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
.alphabet {
|
||||
width: 35%;
|
||||
float: left;
|
||||
font-size: 20em;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.alphabet2 {
|
||||
width: 35%;
|
||||
float: left;
|
||||
direction: ltr;
|
||||
font-size: 1.6em;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-top: 100px;
|
||||
}
|
||||
.footer {
|
||||
font-weight: 400;
|
||||
font-size: 0.7em;
|
||||
text-align: center;
|
||||
direction: ltr;
|
||||
margin-bottom: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
BIN
public/font/woff/IRANYekanX-Black.woff
Normal file
BIN
public/font/woff/IRANYekanX-Black.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-Bold.woff
Normal file
BIN
public/font/woff/IRANYekanX-Bold.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-DemiBold.woff
Normal file
BIN
public/font/woff/IRANYekanX-DemiBold.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-ExtraBlack.woff
Normal file
BIN
public/font/woff/IRANYekanX-ExtraBlack.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-ExtraBold.woff
Normal file
BIN
public/font/woff/IRANYekanX-ExtraBold.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-Heavy.woff
Normal file
BIN
public/font/woff/IRANYekanX-Heavy.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-Light.woff
Normal file
BIN
public/font/woff/IRANYekanX-Light.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-Medium.woff
Normal file
BIN
public/font/woff/IRANYekanX-Medium.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-Regular.woff
Normal file
BIN
public/font/woff/IRANYekanX-Regular.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-Thin.woff
Normal file
BIN
public/font/woff/IRANYekanX-Thin.woff
Normal file
Binary file not shown.
BIN
public/font/woff/IRANYekanX-UltraLight.woff
Normal file
BIN
public/font/woff/IRANYekanX-UltraLight.woff
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-Black.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-Black.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-Bold.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-Bold.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-DemiBold.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-DemiBold.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-ExtraBlack.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-ExtraBlack.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-ExtraBold.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-ExtraBold.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-Heavy.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-Heavy.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-Light.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-Light.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-Medium.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-Medium.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-Regular.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-Regular.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-Thin.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-Thin.woff2
Normal file
Binary file not shown.
BIN
public/font/woff2/IRANYekanX-UltraLight.woff2
Normal file
BIN
public/font/woff2/IRANYekanX-UltraLight.woff2
Normal file
Binary file not shown.
|
|
@ -1,7 +1,5 @@
|
|||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
export default {
|
||||
// Config options...
|
||||
// Server-side render by default, to enable SPA mode set this to `false`
|
||||
ssr: true,
|
||||
ssr: false,
|
||||
} satisfies Config;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user