1
0
Fork 0

Added some finishing touches here and there

This commit is contained in:
Techognito 2025-08-26 18:02:25 +02:00
parent ddd77d9f82
commit 656b1ba417
42 changed files with 9344 additions and 30 deletions

View file

@ -4,6 +4,7 @@
"": {
"name": "bun-react-template",
"dependencies": {
"@iconify/react": "^6.0.0",
"@mui/icons-material": "^7.3.1",
"i18next": "^25.3.2",
"i18next-browser-languagedetector": "^8.2.0",
@ -40,6 +41,10 @@
"@emotion/weak-memoize": ["@emotion/weak-memoize@0.4.0", "", {}, "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="],
"@iconify/react": ["@iconify/react@6.0.0", "", { "dependencies": { "@iconify/types": "^2.0.0" }, "peerDependencies": { "react": ">=16" } }, "sha512-eqNscABVZS8eCpZLU/L5F5UokMS9mnCf56iS1nM9YYHdH8ZxqZL9zyjSwW60IOQFsXZkilbBiv+1paMXBhSQnw=="],
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
"@mui/core-downloads-tracker": ["@mui/core-downloads-tracker@7.3.1", "", {}, "sha512-+mIK1Z0BhOaQ0vCgOkT1mSrIpEHLo338h4/duuL4TBLXPvUMit732mnwJY3W40Avy30HdeSfwUAAGRkKmwRaEQ=="],
"@mui/icons-material": ["@mui/icons-material@7.3.1", "", { "dependencies": { "@babel/runtime": "^7.28.2" }, "peerDependencies": { "@mui/material": "^7.3.1", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-upzCtG6awpL6noEZlJ5Z01khZ9VnLNLaj7tb6iPbN6G97eYfUTs8e9OyPKy3rEms3VQWmVBfri7jzeaRxdFIzA=="],

1904
node_modules/@iconify/react/dist/iconify.cjs generated vendored Normal file

File diff suppressed because it is too large Load diff

428
node_modules/@iconify/react/dist/iconify.d.cts generated vendored Normal file
View file

@ -0,0 +1,428 @@
import { IconifyIcon } from '@iconify/types';
import { IconifyJSON } from '@iconify/types';
import { IconifyTransformations } from '@iconify/types';
import type { JSX as JSX_2 } from 'react';
import type { ReactNode } from 'react';
import type { SVGProps } from 'react';
/**
* Add custom config for provider
*/
export declare function addAPIProvider(provider: string, customConfig: PartialIconifyAPIConfig): boolean;
/**
* Add icon set
*/
export declare function addCollection(data: IconifyJSON, provider?: string): boolean;
/**
* Add one icon
*/
export declare function addIcon(name: string, data: IconifyIcon | null): boolean;
/**
* Internal API
*/
export declare const _api: IconifyAPIInternalFunctions;
/**
* Get SVG attributes and content from icon + customisations
*
* Does not generate style to make it compatible with frameworks that use objects for style, such as React.
* Instead, it generates 'inline' value. If true, rendering engine should add verticalAlign: -0.125em to icon.
*
* Customisations should be normalised by platform specific parser.
* Result should be converted to <svg> by platform specific parser.
* Use replaceIDs to generate unique IDs for body.
*/
export declare function buildIcon(icon: IconifyIcon, customisations?: IconifyIconCustomisations_2): IconifyIconBuildResult;
/**
* Calculate second dimension when only 1 dimension is set
*/
export declare function calculateSize(size: string, ratio: number, precision?: number): string;
export declare function calculateSize(size: number, ratio: number, precision?: number): number;
export declare function calculateSize(size: string | number, ratio: number, precision?: number): string | number;
/**
* Signature for getAPIConfig
*/
export declare type GetAPIConfig = (provider: string) => IconifyAPIConfig | undefined;
/**
* Get full icon
*/
export declare function getIcon(name: string): Required<IconifyIcon> | null | undefined;
/**
* Block icon
*
* @param props - Component properties
*/
export declare const Icon: IconComponentType;
declare type IconComponentType = (props: IconProps) => JSX_2.Element;
/**
* API config
*/
export declare interface IconifyAPIConfig extends RedundancyConfig {
path: string;
maxURL: number;
}
export declare interface IconifyAPICustomQueryParams {
type: 'custom';
provider?: string;
uri: string;
}
/**
* Iconify API functions
*/
export declare interface IconifyAPIFunctions {
/**
* Load icons
*/
loadIcons: (icons: (IconifyIconName | string)[], callback?: IconifyIconLoaderCallback) => IconifyIconLoaderAbort;
/**
* Load one icon, using Promise syntax
*/
loadIcon: (icon: IconifyIconName | string) => Promise<Required<IconifyIcon>>;
/**
* Add API provider
*/
addAPIProvider: (provider: string, customConfig: PartialIconifyAPIConfig) => boolean;
/**
* Set custom loader for multple icons
*/
setCustomIconsLoader: (callback: IconifyCustomIconsLoader, prefix: string, provider?: string) => void;
/**
* Set custom loader for one icon
*/
setCustomIconLoader: (callback: IconifyCustomIconLoader, prefix: string, provider?: string) => void;
}
/**
* Params for sendQuery()
*/
declare interface IconifyAPIIconsQueryParams {
type: 'icons';
provider: string;
prefix: string;
icons: string[];
}
/**
* Exposed internal functions
*
* Used by plug-ins, such as Icon Finder
*
* Important: any changes published in a release must be backwards compatible.
*/
export declare interface IconifyAPIInternalFunctions {
/**
* Get API config, used by custom modules
*/
getAPIConfig: GetAPIConfig;
/**
* Set custom API module
*/
setAPIModule: (provider: string, item: IconifyAPIModule) => void;
/**
* Send API query
*/
sendAPIQuery: (target: string | PartialIconifyAPIConfig, query: IconifyAPIQueryParams, callback: QueryDoneCallback) => QueryAbortCallback;
/**
* Set and get fetch()
*/
setFetch: (item: typeof fetch) => void;
getFetch: () => typeof fetch | undefined;
/**
* List all API providers (from config)
*/
listAPIProviders: () => string[];
}
/**
* API modules
*/
export declare interface IconifyAPIModule {
prepare: IconifyAPIPrepareIconsQuery;
send: IconifyAPISendQuery;
}
/**
* Functions to implement in module
*/
export declare type IconifyAPIPrepareIconsQuery = (provider: string, prefix: string, icons: string[]) => IconifyAPIIconsQueryParams[];
export declare type IconifyAPIQueryParams = IconifyAPIIconsQueryParams | IconifyAPICustomQueryParams;
export declare type IconifyAPISendQuery = (host: string, params: IconifyAPIQueryParams, callback: QueryModuleResponse) => void;
/**
* Interface for exported builder functions
*/
export declare interface IconifyBuilderFunctions {
replaceIDs?: (body: string, prefix?: string | (() => string)) => string;
calculateSize: (size: string | number, ratio: number, precision?: number) => string | number;
buildIcon: (icon: IconifyIcon, customisations?: IconifyIconCustomisations_2) => IconifyIconBuildResult;
}
/**
* Custom loader for one icon
*/
export declare type IconifyCustomIconLoader = (name: string, prefix: string, provider: string) => Promise<IconifyIcon | null> | IconifyIcon | null;
/**
* Custom icons loader
*/
export declare type IconifyCustomIconsLoader = (icons: string[], prefix: string, provider: string) => Promise<IconifyJSON | null> | IconifyJSON | null;
/**
* React component properties: generic element for Icon component, SVG for generated component
*/
declare type IconifyElementProps = SVGProps<SVGSVGElement>;
export { IconifyIcon }
/**
* Interface for getSVGData() result
*/
export declare interface IconifyIconBuildResult {
attributes: {
width?: string;
height?: string;
viewBox: string;
};
viewBox: SVGViewBox;
body: string;
}
/**
* Icon customisations
*/
export declare type IconifyIconCustomisations = IconifyIconCustomisations_2 & {
rotate?: string | number;
inline?: boolean;
};
/**
* Icon customisations
*/
declare interface IconifyIconCustomisations_2 extends IconifyTransformations, IconifyIconSizeCustomisations {
}
/**
* Function to abort loading (usually just removes callback because loading is already in progress)
*/
export declare type IconifyIconLoaderAbort = () => void;
/**
* Loader callback
*
* Provides list of icons that have been loaded
*/
export declare type IconifyIconLoaderCallback = (loaded: IconifyIconName[], missing: IconifyIconName[], pending: IconifyIconName[], unsubscribe: IconifyIconLoaderAbort) => void;
/**
* Icon name
*/
export declare interface IconifyIconName {
readonly provider: string;
readonly prefix: string;
readonly name: string;
}
/**
* Callback for when icon has been loaded (only triggered for icons loaded from API)
*/
export declare type IconifyIconOnLoad = (name: string) => void;
/**
* Icon properties
*/
export declare interface IconifyIconProps extends IconifyIconCustomisations {
icon: IconifyIcon | string;
mode?: IconifyRenderMode;
color?: string;
flip?: string;
id?: string;
ssr?: boolean;
fallback?: ReactNode;
onLoad?: IconifyIconOnLoad;
}
/**
* Icon size
*/
export declare type IconifyIconSize = null | string | number;
/**
* Dimensions
*/
declare interface IconifyIconSizeCustomisations {
width?: IconifyIconSize;
height?: IconifyIconSize;
}
export { IconifyJSON }
/**
* Function to load icons
*/
declare type IconifyLoadIcons = (icons: (IconifyIconName | string)[], callback?: IconifyIconLoaderCallback) => IconifyIconLoaderAbort;
/**
* Icon render mode
*
* 'style' = 'bg' or 'mask', depending on icon content
* 'bg' = <span> with style using `background`
* 'mask' = <span> with style using `mask`
* 'svg' = <svg>
*/
export declare type IconifyRenderMode = 'style' | 'bg' | 'mask' | 'svg';
/**
* Interface for exported storage functions
*/
export declare interface IconifyStorageFunctions {
/**
* Check if icon data is available
*/
iconLoaded: (name: string) => boolean;
/**
* Get icon data with all properties
*
* Returns null if icon is missing (attempted to load, but failed)
* Returns undefined if icon was not loaded
*/
getIcon: (name: string) => Required<IconifyIcon> | null | undefined;
/**
* List all available icons
*/
listIcons: (provider?: string, prefix?: string) => string[];
/**
* Add icon to storage
*
* Data is null if icon is missing
*/
addIcon: (name: string, data: IconifyIcon | null) => boolean;
/**
* Add icon set to storage
*/
addCollection: (data: IconifyJSON, provider?: string) => boolean;
}
/**
* Check if icon data is available
*/
export declare function iconLoaded(name: string): boolean;
/**
* Mix of icon properties and SVGSVGElement properties
*/
export declare type IconProps = IconifyElementProps & IconifyIconProps;
/**
* Inline icon (has negative verticalAlign that makes it behave like icon font)
*
* @param props - Component properties
*/
export declare const InlineIcon: IconComponentType;
/**
* List available icons
*/
export declare function listIcons(provider?: string, prefix?: string): string[];
/**
* Load one icon using Promise
*/
export declare const loadIcon: (icon: IconifyIconName | string) => Promise<Required<IconifyIcon>>;
/**
* Load icons
*/
export declare const loadIcons: IconifyLoadIcons;
export declare type PartialIconifyAPIConfig = Partial<IconifyAPIConfig> & Pick<IconifyAPIConfig, 'resources'>;
/**
* Callback for "abort" pending item.
*/
declare type QueryAbortCallback = () => void;
/**
* Callback
*
* If error is present, something went wrong and data is undefined. If error is undefined, data is set.
*/
declare type QueryDoneCallback = (data?: QueryModuleResponseData, error?: QueryModuleResponseData) => void;
declare type QueryModuleResponse = (status: QueryModuleResponseType, data: QueryModuleResponseData) => void;
/**
* Response from query module
*/
declare type QueryModuleResponseData = unknown;
/**
* Response from query module
*/
declare type QueryModuleResponseType = 'success' | 'next' | 'abort';
/**
* Configuration object
*/
declare interface RedundancyConfig {
resources: RedundancyResource[];
index: number;
timeout: number;
rotate: number;
random: boolean;
dataAfterTimeout: boolean;
}
/**
* Resource to rotate (usually hostname or partial URL)
*/
declare type RedundancyResource = string;
/**
* IDs usage:
*
* id="{id}"
* xlink:href="#{id}"
* url(#{id})
*
* From SVG animations:
*
* begin="0;{id}.end"
* begin="{id}.end"
* begin="{id}.click"
*/
/**
* Replace IDs in SVG output with unique IDs
*/
export declare function replaceIDs(body: string, prefix?: string | ((id: string) => string)): string;
/**
* Set custom loader for one icon
*/
export declare function setCustomIconLoader(loader: IconifyCustomIconLoader, prefix: string, provider?: string): void;
/**
* Set custom loader for multiple icons
*/
export declare function setCustomIconsLoader(loader: IconifyCustomIconsLoader, prefix: string, provider?: string): void;
/**
* SVG viewBox: x, y, width, height
*/
declare type SVGViewBox = [x: number, y: number, width: number, height: number];
export { }

428
node_modules/@iconify/react/dist/iconify.d.ts generated vendored Normal file
View file

@ -0,0 +1,428 @@
import { IconifyIcon } from '@iconify/types';
import { IconifyJSON } from '@iconify/types';
import { IconifyTransformations } from '@iconify/types';
import type { JSX as JSX_2 } from 'react';
import type { ReactNode } from 'react';
import type { SVGProps } from 'react';
/**
* Add custom config for provider
*/
export declare function addAPIProvider(provider: string, customConfig: PartialIconifyAPIConfig): boolean;
/**
* Add icon set
*/
export declare function addCollection(data: IconifyJSON, provider?: string): boolean;
/**
* Add one icon
*/
export declare function addIcon(name: string, data: IconifyIcon | null): boolean;
/**
* Internal API
*/
export declare const _api: IconifyAPIInternalFunctions;
/**
* Get SVG attributes and content from icon + customisations
*
* Does not generate style to make it compatible with frameworks that use objects for style, such as React.
* Instead, it generates 'inline' value. If true, rendering engine should add verticalAlign: -0.125em to icon.
*
* Customisations should be normalised by platform specific parser.
* Result should be converted to <svg> by platform specific parser.
* Use replaceIDs to generate unique IDs for body.
*/
export declare function buildIcon(icon: IconifyIcon, customisations?: IconifyIconCustomisations_2): IconifyIconBuildResult;
/**
* Calculate second dimension when only 1 dimension is set
*/
export declare function calculateSize(size: string, ratio: number, precision?: number): string;
export declare function calculateSize(size: number, ratio: number, precision?: number): number;
export declare function calculateSize(size: string | number, ratio: number, precision?: number): string | number;
/**
* Signature for getAPIConfig
*/
export declare type GetAPIConfig = (provider: string) => IconifyAPIConfig | undefined;
/**
* Get full icon
*/
export declare function getIcon(name: string): Required<IconifyIcon> | null | undefined;
/**
* Block icon
*
* @param props - Component properties
*/
export declare const Icon: IconComponentType;
declare type IconComponentType = (props: IconProps) => JSX_2.Element;
/**
* API config
*/
export declare interface IconifyAPIConfig extends RedundancyConfig {
path: string;
maxURL: number;
}
export declare interface IconifyAPICustomQueryParams {
type: 'custom';
provider?: string;
uri: string;
}
/**
* Iconify API functions
*/
export declare interface IconifyAPIFunctions {
/**
* Load icons
*/
loadIcons: (icons: (IconifyIconName | string)[], callback?: IconifyIconLoaderCallback) => IconifyIconLoaderAbort;
/**
* Load one icon, using Promise syntax
*/
loadIcon: (icon: IconifyIconName | string) => Promise<Required<IconifyIcon>>;
/**
* Add API provider
*/
addAPIProvider: (provider: string, customConfig: PartialIconifyAPIConfig) => boolean;
/**
* Set custom loader for multple icons
*/
setCustomIconsLoader: (callback: IconifyCustomIconsLoader, prefix: string, provider?: string) => void;
/**
* Set custom loader for one icon
*/
setCustomIconLoader: (callback: IconifyCustomIconLoader, prefix: string, provider?: string) => void;
}
/**
* Params for sendQuery()
*/
declare interface IconifyAPIIconsQueryParams {
type: 'icons';
provider: string;
prefix: string;
icons: string[];
}
/**
* Exposed internal functions
*
* Used by plug-ins, such as Icon Finder
*
* Important: any changes published in a release must be backwards compatible.
*/
export declare interface IconifyAPIInternalFunctions {
/**
* Get API config, used by custom modules
*/
getAPIConfig: GetAPIConfig;
/**
* Set custom API module
*/
setAPIModule: (provider: string, item: IconifyAPIModule) => void;
/**
* Send API query
*/
sendAPIQuery: (target: string | PartialIconifyAPIConfig, query: IconifyAPIQueryParams, callback: QueryDoneCallback) => QueryAbortCallback;
/**
* Set and get fetch()
*/
setFetch: (item: typeof fetch) => void;
getFetch: () => typeof fetch | undefined;
/**
* List all API providers (from config)
*/
listAPIProviders: () => string[];
}
/**
* API modules
*/
export declare interface IconifyAPIModule {
prepare: IconifyAPIPrepareIconsQuery;
send: IconifyAPISendQuery;
}
/**
* Functions to implement in module
*/
export declare type IconifyAPIPrepareIconsQuery = (provider: string, prefix: string, icons: string[]) => IconifyAPIIconsQueryParams[];
export declare type IconifyAPIQueryParams = IconifyAPIIconsQueryParams | IconifyAPICustomQueryParams;
export declare type IconifyAPISendQuery = (host: string, params: IconifyAPIQueryParams, callback: QueryModuleResponse) => void;
/**
* Interface for exported builder functions
*/
export declare interface IconifyBuilderFunctions {
replaceIDs?: (body: string, prefix?: string | (() => string)) => string;
calculateSize: (size: string | number, ratio: number, precision?: number) => string | number;
buildIcon: (icon: IconifyIcon, customisations?: IconifyIconCustomisations_2) => IconifyIconBuildResult;
}
/**
* Custom loader for one icon
*/
export declare type IconifyCustomIconLoader = (name: string, prefix: string, provider: string) => Promise<IconifyIcon | null> | IconifyIcon | null;
/**
* Custom icons loader
*/
export declare type IconifyCustomIconsLoader = (icons: string[], prefix: string, provider: string) => Promise<IconifyJSON | null> | IconifyJSON | null;
/**
* React component properties: generic element for Icon component, SVG for generated component
*/
declare type IconifyElementProps = SVGProps<SVGSVGElement>;
export { IconifyIcon }
/**
* Interface for getSVGData() result
*/
export declare interface IconifyIconBuildResult {
attributes: {
width?: string;
height?: string;
viewBox: string;
};
viewBox: SVGViewBox;
body: string;
}
/**
* Icon customisations
*/
export declare type IconifyIconCustomisations = IconifyIconCustomisations_2 & {
rotate?: string | number;
inline?: boolean;
};
/**
* Icon customisations
*/
declare interface IconifyIconCustomisations_2 extends IconifyTransformations, IconifyIconSizeCustomisations {
}
/**
* Function to abort loading (usually just removes callback because loading is already in progress)
*/
export declare type IconifyIconLoaderAbort = () => void;
/**
* Loader callback
*
* Provides list of icons that have been loaded
*/
export declare type IconifyIconLoaderCallback = (loaded: IconifyIconName[], missing: IconifyIconName[], pending: IconifyIconName[], unsubscribe: IconifyIconLoaderAbort) => void;
/**
* Icon name
*/
export declare interface IconifyIconName {
readonly provider: string;
readonly prefix: string;
readonly name: string;
}
/**
* Callback for when icon has been loaded (only triggered for icons loaded from API)
*/
export declare type IconifyIconOnLoad = (name: string) => void;
/**
* Icon properties
*/
export declare interface IconifyIconProps extends IconifyIconCustomisations {
icon: IconifyIcon | string;
mode?: IconifyRenderMode;
color?: string;
flip?: string;
id?: string;
ssr?: boolean;
fallback?: ReactNode;
onLoad?: IconifyIconOnLoad;
}
/**
* Icon size
*/
export declare type IconifyIconSize = null | string | number;
/**
* Dimensions
*/
declare interface IconifyIconSizeCustomisations {
width?: IconifyIconSize;
height?: IconifyIconSize;
}
export { IconifyJSON }
/**
* Function to load icons
*/
declare type IconifyLoadIcons = (icons: (IconifyIconName | string)[], callback?: IconifyIconLoaderCallback) => IconifyIconLoaderAbort;
/**
* Icon render mode
*
* 'style' = 'bg' or 'mask', depending on icon content
* 'bg' = <span> with style using `background`
* 'mask' = <span> with style using `mask`
* 'svg' = <svg>
*/
export declare type IconifyRenderMode = 'style' | 'bg' | 'mask' | 'svg';
/**
* Interface for exported storage functions
*/
export declare interface IconifyStorageFunctions {
/**
* Check if icon data is available
*/
iconLoaded: (name: string) => boolean;
/**
* Get icon data with all properties
*
* Returns null if icon is missing (attempted to load, but failed)
* Returns undefined if icon was not loaded
*/
getIcon: (name: string) => Required<IconifyIcon> | null | undefined;
/**
* List all available icons
*/
listIcons: (provider?: string, prefix?: string) => string[];
/**
* Add icon to storage
*
* Data is null if icon is missing
*/
addIcon: (name: string, data: IconifyIcon | null) => boolean;
/**
* Add icon set to storage
*/
addCollection: (data: IconifyJSON, provider?: string) => boolean;
}
/**
* Check if icon data is available
*/
export declare function iconLoaded(name: string): boolean;
/**
* Mix of icon properties and SVGSVGElement properties
*/
export declare type IconProps = IconifyElementProps & IconifyIconProps;
/**
* Inline icon (has negative verticalAlign that makes it behave like icon font)
*
* @param props - Component properties
*/
export declare const InlineIcon: IconComponentType;
/**
* List available icons
*/
export declare function listIcons(provider?: string, prefix?: string): string[];
/**
* Load one icon using Promise
*/
export declare const loadIcon: (icon: IconifyIconName | string) => Promise<Required<IconifyIcon>>;
/**
* Load icons
*/
export declare const loadIcons: IconifyLoadIcons;
export declare type PartialIconifyAPIConfig = Partial<IconifyAPIConfig> & Pick<IconifyAPIConfig, 'resources'>;
/**
* Callback for "abort" pending item.
*/
declare type QueryAbortCallback = () => void;
/**
* Callback
*
* If error is present, something went wrong and data is undefined. If error is undefined, data is set.
*/
declare type QueryDoneCallback = (data?: QueryModuleResponseData, error?: QueryModuleResponseData) => void;
declare type QueryModuleResponse = (status: QueryModuleResponseType, data: QueryModuleResponseData) => void;
/**
* Response from query module
*/
declare type QueryModuleResponseData = unknown;
/**
* Response from query module
*/
declare type QueryModuleResponseType = 'success' | 'next' | 'abort';
/**
* Configuration object
*/
declare interface RedundancyConfig {
resources: RedundancyResource[];
index: number;
timeout: number;
rotate: number;
random: boolean;
dataAfterTimeout: boolean;
}
/**
* Resource to rotate (usually hostname or partial URL)
*/
declare type RedundancyResource = string;
/**
* IDs usage:
*
* id="{id}"
* xlink:href="#{id}"
* url(#{id})
*
* From SVG animations:
*
* begin="0;{id}.end"
* begin="{id}.end"
* begin="{id}.click"
*/
/**
* Replace IDs in SVG output with unique IDs
*/
export declare function replaceIDs(body: string, prefix?: string | ((id: string) => string)): string;
/**
* Set custom loader for one icon
*/
export declare function setCustomIconLoader(loader: IconifyCustomIconLoader, prefix: string, provider?: string): void;
/**
* Set custom loader for multiple icons
*/
export declare function setCustomIconsLoader(loader: IconifyCustomIconsLoader, prefix: string, provider?: string): void;
/**
* SVG viewBox: x, y, width, height
*/
declare type SVGViewBox = [x: number, y: number, width: number, height: number];
export { }

1887
node_modules/@iconify/react/dist/iconify.js generated vendored Normal file

File diff suppressed because it is too large Load diff

823
node_modules/@iconify/react/dist/offline.cjs generated vendored Normal file
View file

@ -0,0 +1,823 @@
'use client';
'use strict';
var react = require('react');
const defaultIconDimensions = Object.freeze(
{
left: 0,
top: 0,
width: 16,
height: 16
}
);
const defaultIconTransformations = Object.freeze({
rotate: 0,
vFlip: false,
hFlip: false
});
const defaultIconProps = Object.freeze({
...defaultIconDimensions,
...defaultIconTransformations
});
const defaultExtendedIconProps = Object.freeze({
...defaultIconProps,
body: "",
hidden: false
});
function mergeIconTransformations(obj1, obj2) {
const result = {};
if (!obj1.hFlip !== !obj2.hFlip) {
result.hFlip = true;
}
if (!obj1.vFlip !== !obj2.vFlip) {
result.vFlip = true;
}
const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4;
if (rotate) {
result.rotate = rotate;
}
return result;
}
function mergeIconData(parent, child) {
const result = mergeIconTransformations(parent, child);
for (const key in defaultExtendedIconProps) {
if (key in defaultIconTransformations) {
if (key in parent && !(key in result)) {
result[key] = defaultIconTransformations[key];
}
} else if (key in child) {
result[key] = child[key];
} else if (key in parent) {
result[key] = parent[key];
}
}
return result;
}
function getIconsTree(data, names) {
const icons = data.icons;
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
const resolved = /* @__PURE__ */ Object.create(null);
function resolve(name) {
if (icons[name]) {
return resolved[name] = [];
}
if (!(name in resolved)) {
resolved[name] = null;
const parent = aliases[name] && aliases[name].parent;
const value = parent && resolve(parent);
if (value) {
resolved[name] = [parent].concat(value);
}
}
return resolved[name];
}
(Object.keys(icons).concat(Object.keys(aliases))).forEach(resolve);
return resolved;
}
function internalGetIconData(data, name, tree) {
const icons = data.icons;
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
let currentProps = {};
function parse(name2) {
currentProps = mergeIconData(
icons[name2] || aliases[name2],
currentProps
);
}
parse(name);
tree.forEach(parse);
return mergeIconData(data, currentProps);
}
function parseIconSet(data, callback) {
const names = [];
if (typeof data !== "object" || typeof data.icons !== "object") {
return names;
}
if (data.not_found instanceof Array) {
data.not_found.forEach((name) => {
callback(name, null);
names.push(name);
});
}
const tree = getIconsTree(data);
for (const name in tree) {
const item = tree[name];
if (item) {
callback(name, internalGetIconData(data, name, item));
names.push(name);
}
}
return names;
}
const optionalPropertyDefaults = {
provider: "",
aliases: {},
not_found: {},
...defaultIconDimensions
};
function checkOptionalProps(item, defaults) {
for (const prop in defaults) {
if (prop in item && typeof item[prop] !== typeof defaults[prop]) {
return false;
}
}
return true;
}
function quicklyValidateIconSet(obj) {
if (typeof obj !== "object" || obj === null) {
return null;
}
const data = obj;
if (typeof data.prefix !== "string" || !obj.icons || typeof obj.icons !== "object") {
return null;
}
if (!checkOptionalProps(obj, optionalPropertyDefaults)) {
return null;
}
const icons = data.icons;
for (const name in icons) {
const icon = icons[name];
if (
// Name cannot be empty
!name || // Must have body
typeof icon.body !== "string" || // Check other props
!checkOptionalProps(
icon,
defaultExtendedIconProps
)
) {
return null;
}
}
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
for (const name in aliases) {
const icon = aliases[name];
const parent = icon.parent;
if (
// Name cannot be empty
!name || // Parent must be set and point to existing icon
typeof parent !== "string" || !icons[parent] && !aliases[parent] || // Check other props
!checkOptionalProps(
icon,
defaultExtendedIconProps
)
) {
return null;
}
}
return data;
}
const defaultIconSizeCustomisations = Object.freeze({
width: null,
height: null
});
const defaultIconCustomisations = Object.freeze({
// Dimensions
...defaultIconSizeCustomisations,
// Transformations
...defaultIconTransformations
});
function mergeCustomisations(defaults, item) {
const result = {
...defaults
};
for (const key in item) {
const value = item[key];
const valueType = typeof value;
if (key in defaultIconSizeCustomisations) {
if (value === null || value && (valueType === "string" || valueType === "number")) {
result[key] = value;
}
} else if (valueType === typeof result[key]) {
result[key] = key === "rotate" ? value % 4 : value;
}
}
return result;
}
const separator = /[\s,]+/;
function flipFromString(custom, flip) {
flip.split(separator).forEach((str) => {
const value = str.trim();
switch (value) {
case "horizontal":
custom.hFlip = true;
break;
case "vertical":
custom.vFlip = true;
break;
}
});
}
function rotateFromString(value, defaultValue = 0) {
const units = value.replace(/^-?[0-9.]*/, "");
function cleanup(value2) {
while (value2 < 0) {
value2 += 4;
}
return value2 % 4;
}
if (units === "") {
const num = parseInt(value);
return isNaN(num) ? 0 : cleanup(num);
} else if (units !== value) {
let split = 0;
switch (units) {
case "%":
split = 25;
break;
case "deg":
split = 90;
}
if (split) {
let num = parseFloat(value.slice(0, value.length - units.length));
if (isNaN(num)) {
return 0;
}
num = num / split;
return num % 1 === 0 ? cleanup(num) : 0;
}
}
return defaultValue;
}
const unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g;
const unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g;
function calculateSize(size, ratio, precision) {
if (ratio === 1) {
return size;
}
precision = precision || 100;
if (typeof size === "number") {
return Math.ceil(size * ratio * precision) / precision;
}
if (typeof size !== "string") {
return size;
}
const oldParts = size.split(unitsSplit);
if (oldParts === null || !oldParts.length) {
return size;
}
const newParts = [];
let code = oldParts.shift();
let isNumber = unitsTest.test(code);
while (true) {
if (isNumber) {
const num = parseFloat(code);
if (isNaN(num)) {
newParts.push(code);
} else {
newParts.push(Math.ceil(num * ratio * precision) / precision);
}
} else {
newParts.push(code);
}
code = oldParts.shift();
if (code === void 0) {
return newParts.join("");
}
isNumber = !isNumber;
}
}
function splitSVGDefs(content, tag = "defs") {
let defs = "";
const index = content.indexOf("<" + tag);
while (index >= 0) {
const start = content.indexOf(">", index);
const end = content.indexOf("</" + tag);
if (start === -1 || end === -1) {
break;
}
const endEnd = content.indexOf(">", end);
if (endEnd === -1) {
break;
}
defs += content.slice(start + 1, end).trim();
content = content.slice(0, index).trim() + content.slice(endEnd + 1);
}
return {
defs,
content
};
}
function mergeDefsAndContent(defs, content) {
return defs ? "<defs>" + defs + "</defs>" + content : content;
}
function wrapSVGContent(body, start, end) {
const split = splitSVGDefs(body);
return mergeDefsAndContent(split.defs, start + split.content + end);
}
const isUnsetKeyword = (value) => value === "unset" || value === "undefined" || value === "none";
function iconToSVG(icon, customisations) {
const fullIcon = {
...defaultIconProps,
...icon
};
const fullCustomisations = {
...defaultIconCustomisations,
...customisations
};
const box = {
left: fullIcon.left,
top: fullIcon.top,
width: fullIcon.width,
height: fullIcon.height
};
let body = fullIcon.body;
[fullIcon, fullCustomisations].forEach((props) => {
const transformations = [];
const hFlip = props.hFlip;
const vFlip = props.vFlip;
let rotation = props.rotate;
if (hFlip) {
if (vFlip) {
rotation += 2;
} else {
transformations.push(
"translate(" + (box.width + box.left).toString() + " " + (0 - box.top).toString() + ")"
);
transformations.push("scale(-1 1)");
box.top = box.left = 0;
}
} else if (vFlip) {
transformations.push(
"translate(" + (0 - box.left).toString() + " " + (box.height + box.top).toString() + ")"
);
transformations.push("scale(1 -1)");
box.top = box.left = 0;
}
let tempValue;
if (rotation < 0) {
rotation -= Math.floor(rotation / 4) * 4;
}
rotation = rotation % 4;
switch (rotation) {
case 1:
tempValue = box.height / 2 + box.top;
transformations.unshift(
"rotate(90 " + tempValue.toString() + " " + tempValue.toString() + ")"
);
break;
case 2:
transformations.unshift(
"rotate(180 " + (box.width / 2 + box.left).toString() + " " + (box.height / 2 + box.top).toString() + ")"
);
break;
case 3:
tempValue = box.width / 2 + box.left;
transformations.unshift(
"rotate(-90 " + tempValue.toString() + " " + tempValue.toString() + ")"
);
break;
}
if (rotation % 2 === 1) {
if (box.left !== box.top) {
tempValue = box.left;
box.left = box.top;
box.top = tempValue;
}
if (box.width !== box.height) {
tempValue = box.width;
box.width = box.height;
box.height = tempValue;
}
}
if (transformations.length) {
body = wrapSVGContent(
body,
'<g transform="' + transformations.join(" ") + '">',
"</g>"
);
}
});
const customisationsWidth = fullCustomisations.width;
const customisationsHeight = fullCustomisations.height;
const boxWidth = box.width;
const boxHeight = box.height;
let width;
let height;
if (customisationsWidth === null) {
height = customisationsHeight === null ? "1em" : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
width = calculateSize(height, boxWidth / boxHeight);
} else {
width = customisationsWidth === "auto" ? boxWidth : customisationsWidth;
height = customisationsHeight === null ? calculateSize(width, boxHeight / boxWidth) : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
}
const attributes = {};
const setAttr = (prop, value) => {
if (!isUnsetKeyword(value)) {
attributes[prop] = value.toString();
}
};
setAttr("width", width);
setAttr("height", height);
const viewBox = [box.left, box.top, boxWidth, boxHeight];
attributes.viewBox = viewBox.join(" ");
return {
attributes,
viewBox,
body
};
}
const regex = /\sid="(\S+)"/g;
const randomPrefix = "IconifyId" + Date.now().toString(16) + (Math.random() * 16777216 | 0).toString(16);
let counter = 0;
function replaceIDs(body, prefix = randomPrefix) {
const ids = [];
let match;
while (match = regex.exec(body)) {
ids.push(match[1]);
}
if (!ids.length) {
return body;
}
const suffix = "suffix" + (Math.random() * 16777216 | Date.now()).toString(16);
ids.forEach((id) => {
const newID = typeof prefix === "function" ? prefix(id) : prefix + (counter++).toString();
const escapedID = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
body = body.replace(
// Allowed characters before id: [#;"]
// Allowed characters after id: [)"], .[a-z]
new RegExp('([#;"])(' + escapedID + ')([")]|\\.[a-z])', "g"),
"$1" + newID + suffix + "$3"
);
});
body = body.replace(new RegExp(suffix, "g"), "");
return body;
}
function iconToHTML(body, attributes) {
let renderAttribsHTML = body.indexOf("xlink:") === -1 ? "" : ' xmlns:xlink="http://www.w3.org/1999/xlink"';
for (const attr in attributes) {
renderAttribsHTML += " " + attr + '="' + attributes[attr] + '"';
}
return '<svg xmlns="http://www.w3.org/2000/svg"' + renderAttribsHTML + ">" + body + "</svg>";
}
function encodeSVGforURL(svg) {
return svg.replace(/"/g, "'").replace(/%/g, "%25").replace(/#/g, "%23").replace(/</g, "%3C").replace(/>/g, "%3E").replace(/\s+/g, " ");
}
function svgToData(svg) {
return "data:image/svg+xml," + encodeSVGforURL(svg);
}
function svgToURL(svg) {
return 'url("' + svgToData(svg) + '")';
}
let policy;
function createPolicy() {
try {
policy = window.trustedTypes.createPolicy("iconify", {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
createHTML: (s) => s
});
} catch (err) {
policy = null;
}
}
function cleanUpInnerHTML(html) {
if (policy === void 0) {
createPolicy();
}
return policy ? policy.createHTML(html) : html;
}
const defaultExtendedIconCustomisations = {
...defaultIconCustomisations,
inline: false,
};
const stringToIcon = (value, validate, allowSimpleName, provider = "") => {
const colonSeparated = value.split(":");
if (value.slice(0, 1) === "@") {
if (colonSeparated.length < 2 || colonSeparated.length > 3) {
return null;
}
provider = colonSeparated.shift().slice(1);
}
if (colonSeparated.length > 3 || !colonSeparated.length) {
return null;
}
if (colonSeparated.length > 1) {
const name2 = colonSeparated.pop();
const prefix = colonSeparated.pop();
const result = {
// Allow provider without '@': "provider:prefix:name"
provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,
prefix,
name: name2
};
return result;
}
const name = colonSeparated[0];
const dashSeparated = name.split("-");
if (dashSeparated.length > 1) {
const result = {
provider,
prefix: dashSeparated.shift(),
name: dashSeparated.join("-")
};
return result;
}
if (provider === "") {
const result = {
provider,
prefix: "",
name
};
return result;
}
return null;
};
/**
* Default SVG attributes
*/
const svgDefaults = {
'xmlns': 'http://www.w3.org/2000/svg',
'xmlnsXlink': 'http://www.w3.org/1999/xlink',
'aria-hidden': true,
'role': 'img',
};
/**
* Style modes
*/
const commonProps = {
display: 'inline-block',
};
const monotoneProps = {
backgroundColor: 'currentColor',
};
const coloredProps = {
backgroundColor: 'transparent',
};
// Dynamically add common props to variables above
const propsToAdd = {
Image: 'var(--svg)',
Repeat: 'no-repeat',
Size: '100% 100%',
};
const propsToAddTo = {
WebkitMask: monotoneProps,
mask: monotoneProps,
background: coloredProps,
};
for (const prefix in propsToAddTo) {
const list = propsToAddTo[prefix];
for (const prop in propsToAdd) {
list[prefix + prop] = propsToAdd[prop];
}
}
/**
* Default values for customisations for inline icon
*/
const inlineDefaults = {
...defaultExtendedIconCustomisations,
inline: true,
};
/**
* Fix size: add 'px' to numbers
*/
function fixSize(value) {
return value + (value.match(/^[-0-9.]+$/) ? 'px' : '');
}
/**
* Render icon
*/
const render = (
// Icon must be validated before calling this function
icon,
// Partial properties
props,
// Icon name
name) => {
// Get default properties
const defaultProps = props.inline
? inlineDefaults
: defaultExtendedIconCustomisations;
// Get all customisations
const customisations = mergeCustomisations(defaultProps, props);
// Check mode
const mode = props.mode || 'svg';
// Create style
const style = {};
const customStyle = props.style || {};
// Create SVG component properties
const componentProps = {
...(mode === 'svg' ? svgDefaults : {}),
};
if (name) {
const iconName = stringToIcon(name);
if (iconName) {
const classNames = ['iconify'];
const props = [
'provider',
'prefix',
];
for (const prop of props) {
if (iconName[prop]) {
classNames.push('iconify--' + iconName[prop]);
}
}
componentProps.className = classNames.join(' ');
}
}
// Get element properties
for (let key in props) {
const value = props[key];
if (value === void 0) {
continue;
}
switch (key) {
// Properties to ignore
case 'icon':
case 'style':
case 'children':
case 'onLoad':
case 'mode':
case 'ssr':
break;
// Forward ref
case '_ref':
componentProps.ref = value;
break;
// Merge class names
case 'className':
componentProps[key] =
(componentProps[key] ? componentProps[key] + ' ' : '') +
value;
break;
// Boolean attributes
case 'inline':
case 'hFlip':
case 'vFlip':
customisations[key] =
value === true || value === 'true' || value === 1;
break;
// Flip as string: 'horizontal,vertical'
case 'flip':
if (typeof value === 'string') {
flipFromString(customisations, value);
}
break;
// Color: copy to style
case 'color':
style.color = value;
break;
// Rotation as string
case 'rotate':
if (typeof value === 'string') {
customisations[key] = rotateFromString(value);
}
else if (typeof value === 'number') {
customisations[key] = value;
}
break;
// Remove aria-hidden
case 'ariaHidden':
case 'aria-hidden':
if (value !== true && value !== 'true') {
delete componentProps['aria-hidden'];
}
break;
// Copy missing property if it does not exist in customisations
default:
if (defaultProps[key] === void 0) {
componentProps[key] = value;
}
}
}
// Generate icon
const item = iconToSVG(icon, customisations);
const renderAttribs = item.attributes;
// Inline display
if (customisations.inline) {
style.verticalAlign = '-0.125em';
}
if (mode === 'svg') {
// Add style
componentProps.style = {
...style,
...customStyle,
};
// Add icon stuff
Object.assign(componentProps, renderAttribs);
// Counter for ids based on "id" property to render icons consistently on server and client
let localCounter = 0;
let id = props.id;
if (typeof id === 'string') {
// Convert '-' to '_' to avoid errors in animations
id = id.replace(/-/g, '_');
}
// Add icon stuff
componentProps.dangerouslySetInnerHTML = {
__html: cleanUpInnerHTML(replaceIDs(item.body, id ? () => id + 'ID' + localCounter++ : 'iconifyReact')),
};
return react.createElement('svg', componentProps);
}
// Render <span> with style
const { body, width, height } = icon;
const useMask = mode === 'mask' ||
(mode === 'bg' ? false : body.indexOf('currentColor') !== -1);
// Generate SVG
const html = iconToHTML(body, {
...renderAttribs,
width: width + '',
height: height + '',
});
// Generate style
componentProps.style = {
...style,
'--svg': svgToURL(html),
'width': fixSize(renderAttribs.width),
'height': fixSize(renderAttribs.height),
...commonProps,
...(useMask ? monotoneProps : coloredProps),
...customStyle,
};
return react.createElement('span', componentProps);
};
/**
* Storage for icons referred by name
*/
const storage = Object.create(null);
function IconComponent(props) {
const icon = props.icon;
const data = typeof icon === 'string' ? storage[icon] : icon;
if (!data) {
return props.children
? props.children
: react.createElement('span', {});
}
return render({
...defaultIconProps,
...data,
}, props, typeof icon === 'string' ? icon : undefined);
}
/**
* Block icon
*
* @param props - Component properties
*/
const Icon = react.memo(react.forwardRef((props, ref) => IconComponent({
...props,
_ref: ref,
})));
/**
* Inline icon (has negative verticalAlign that makes it behave like icon font)
*
* @param props - Component properties
*/
const InlineIcon = react.memo(react.forwardRef((props, ref) => IconComponent({
inline: true,
...props,
_ref: ref,
})));
/**
* Add icon to storage, allowing to call it by name
*
* @param name
* @param data
*/
function addIcon(name, data) {
storage[name] = data;
}
/**
* Add collection to storage, allowing to call icons by name
*
* @param data Icon set
* @param prefix Optional prefix to add to icon names, true (default) if prefix from icon set should be used.
*/
function addCollection(data, prefix) {
const iconPrefix = typeof prefix === 'string'
? prefix
: prefix !== false && typeof data.prefix === 'string'
? data.prefix + ':'
: '';
quicklyValidateIconSet(data) &&
parseIconSet(data, (name, icon) => {
if (icon) {
storage[iconPrefix + name] = icon;
}
});
}
exports.Icon = Icon;
exports.InlineIcon = InlineIcon;
exports.addCollection = addCollection;
exports.addIcon = addIcon;

110
node_modules/@iconify/react/dist/offline.d.cts generated vendored Normal file
View file

@ -0,0 +1,110 @@
import type { IconifyIcon } from '@iconify/types';
import type { IconifyJSON } from '@iconify/types';
import { IconifyTransformations } from '@iconify/types';
import type { JSX as JSX_2 } from 'react';
import type { ReactNode } from 'react';
import type { SVGProps } from 'react';
/**
* Add collection to storage, allowing to call icons by name
*
* @param data Icon set
* @param prefix Optional prefix to add to icon names, true (default) if prefix from icon set should be used.
*/
export declare function addCollection(data: IconifyJSON, prefix?: string | boolean): void;
/**
* Add icon to storage, allowing to call it by name
*
* @param name
* @param data
*/
export declare function addIcon(name: string, data: IconifyIcon): void;
/**
* Block icon
*
* @param props - Component properties
*/
export declare const Icon: IconComponentType;
declare type IconComponentType = (props: IconProps) => JSX_2.Element;
/**
* React component properties: generic element for Icon component, SVG for generated component
*/
declare type IconifyElementProps = SVGProps<SVGSVGElement>;
export { IconifyIcon }
/**
* Icon customisations
*/
export declare type IconifyIconCustomisations = IconifyIconCustomisations_2 & {
rotate?: string | number;
inline?: boolean;
};
/**
* Icon customisations
*/
declare interface IconifyIconCustomisations_2 extends IconifyTransformations, IconifyIconSizeCustomisations {
}
/**
* Callback for when icon has been loaded (only triggered for icons loaded from API)
*/
declare type IconifyIconOnLoad = (name: string) => void;
/**
* Icon properties
*/
export declare interface IconifyIconProps extends IconifyIconCustomisations {
icon: IconifyIcon | string;
mode?: IconifyRenderMode;
color?: string;
flip?: string;
id?: string;
ssr?: boolean;
fallback?: ReactNode;
onLoad?: IconifyIconOnLoad;
}
/**
* Icon size
*/
export declare type IconifyIconSize = null | string | number;
/**
* Dimensions
*/
declare interface IconifyIconSizeCustomisations {
width?: IconifyIconSize;
height?: IconifyIconSize;
}
export { IconifyJSON }
/**
* Icon render mode
*
* 'style' = 'bg' or 'mask', depending on icon content
* 'bg' = <span> with style using `background`
* 'mask' = <span> with style using `mask`
* 'svg' = <svg>
*/
export declare type IconifyRenderMode = 'style' | 'bg' | 'mask' | 'svg';
/**
* Mix of icon properties and SVGSVGElement properties
*/
export declare type IconProps = IconifyElementProps & IconifyIconProps;
/**
* Inline icon (has negative verticalAlign that makes it behave like icon font)
*
* @param props - Component properties
*/
export declare const InlineIcon: IconComponentType;
export { }

110
node_modules/@iconify/react/dist/offline.d.ts generated vendored Normal file
View file

@ -0,0 +1,110 @@
import type { IconifyIcon } from '@iconify/types';
import type { IconifyJSON } from '@iconify/types';
import { IconifyTransformations } from '@iconify/types';
import type { JSX as JSX_2 } from 'react';
import type { ReactNode } from 'react';
import type { SVGProps } from 'react';
/**
* Add collection to storage, allowing to call icons by name
*
* @param data Icon set
* @param prefix Optional prefix to add to icon names, true (default) if prefix from icon set should be used.
*/
export declare function addCollection(data: IconifyJSON, prefix?: string | boolean): void;
/**
* Add icon to storage, allowing to call it by name
*
* @param name
* @param data
*/
export declare function addIcon(name: string, data: IconifyIcon): void;
/**
* Block icon
*
* @param props - Component properties
*/
export declare const Icon: IconComponentType;
declare type IconComponentType = (props: IconProps) => JSX_2.Element;
/**
* React component properties: generic element for Icon component, SVG for generated component
*/
declare type IconifyElementProps = SVGProps<SVGSVGElement>;
export { IconifyIcon }
/**
* Icon customisations
*/
export declare type IconifyIconCustomisations = IconifyIconCustomisations_2 & {
rotate?: string | number;
inline?: boolean;
};
/**
* Icon customisations
*/
declare interface IconifyIconCustomisations_2 extends IconifyTransformations, IconifyIconSizeCustomisations {
}
/**
* Callback for when icon has been loaded (only triggered for icons loaded from API)
*/
declare type IconifyIconOnLoad = (name: string) => void;
/**
* Icon properties
*/
export declare interface IconifyIconProps extends IconifyIconCustomisations {
icon: IconifyIcon | string;
mode?: IconifyRenderMode;
color?: string;
flip?: string;
id?: string;
ssr?: boolean;
fallback?: ReactNode;
onLoad?: IconifyIconOnLoad;
}
/**
* Icon size
*/
export declare type IconifyIconSize = null | string | number;
/**
* Dimensions
*/
declare interface IconifyIconSizeCustomisations {
width?: IconifyIconSize;
height?: IconifyIconSize;
}
export { IconifyJSON }
/**
* Icon render mode
*
* 'style' = 'bg' or 'mask', depending on icon content
* 'bg' = <span> with style using `background`
* 'mask' = <span> with style using `mask`
* 'svg' = <svg>
*/
export declare type IconifyRenderMode = 'style' | 'bg' | 'mask' | 'svg';
/**
* Mix of icon properties and SVGSVGElement properties
*/
export declare type IconProps = IconifyElementProps & IconifyIconProps;
/**
* Inline icon (has negative verticalAlign that makes it behave like icon font)
*
* @param props - Component properties
*/
export declare const InlineIcon: IconComponentType;
export { }

818
node_modules/@iconify/react/dist/offline.js generated vendored Normal file
View file

@ -0,0 +1,818 @@
'use client';
import { createElement, memo, forwardRef } from 'react';
const defaultIconDimensions = Object.freeze(
{
left: 0,
top: 0,
width: 16,
height: 16
}
);
const defaultIconTransformations = Object.freeze({
rotate: 0,
vFlip: false,
hFlip: false
});
const defaultIconProps = Object.freeze({
...defaultIconDimensions,
...defaultIconTransformations
});
const defaultExtendedIconProps = Object.freeze({
...defaultIconProps,
body: "",
hidden: false
});
function mergeIconTransformations(obj1, obj2) {
const result = {};
if (!obj1.hFlip !== !obj2.hFlip) {
result.hFlip = true;
}
if (!obj1.vFlip !== !obj2.vFlip) {
result.vFlip = true;
}
const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4;
if (rotate) {
result.rotate = rotate;
}
return result;
}
function mergeIconData(parent, child) {
const result = mergeIconTransformations(parent, child);
for (const key in defaultExtendedIconProps) {
if (key in defaultIconTransformations) {
if (key in parent && !(key in result)) {
result[key] = defaultIconTransformations[key];
}
} else if (key in child) {
result[key] = child[key];
} else if (key in parent) {
result[key] = parent[key];
}
}
return result;
}
function getIconsTree(data, names) {
const icons = data.icons;
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
const resolved = /* @__PURE__ */ Object.create(null);
function resolve(name) {
if (icons[name]) {
return resolved[name] = [];
}
if (!(name in resolved)) {
resolved[name] = null;
const parent = aliases[name] && aliases[name].parent;
const value = parent && resolve(parent);
if (value) {
resolved[name] = [parent].concat(value);
}
}
return resolved[name];
}
(Object.keys(icons).concat(Object.keys(aliases))).forEach(resolve);
return resolved;
}
function internalGetIconData(data, name, tree) {
const icons = data.icons;
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
let currentProps = {};
function parse(name2) {
currentProps = mergeIconData(
icons[name2] || aliases[name2],
currentProps
);
}
parse(name);
tree.forEach(parse);
return mergeIconData(data, currentProps);
}
function parseIconSet(data, callback) {
const names = [];
if (typeof data !== "object" || typeof data.icons !== "object") {
return names;
}
if (data.not_found instanceof Array) {
data.not_found.forEach((name) => {
callback(name, null);
names.push(name);
});
}
const tree = getIconsTree(data);
for (const name in tree) {
const item = tree[name];
if (item) {
callback(name, internalGetIconData(data, name, item));
names.push(name);
}
}
return names;
}
const optionalPropertyDefaults = {
provider: "",
aliases: {},
not_found: {},
...defaultIconDimensions
};
function checkOptionalProps(item, defaults) {
for (const prop in defaults) {
if (prop in item && typeof item[prop] !== typeof defaults[prop]) {
return false;
}
}
return true;
}
function quicklyValidateIconSet(obj) {
if (typeof obj !== "object" || obj === null) {
return null;
}
const data = obj;
if (typeof data.prefix !== "string" || !obj.icons || typeof obj.icons !== "object") {
return null;
}
if (!checkOptionalProps(obj, optionalPropertyDefaults)) {
return null;
}
const icons = data.icons;
for (const name in icons) {
const icon = icons[name];
if (
// Name cannot be empty
!name || // Must have body
typeof icon.body !== "string" || // Check other props
!checkOptionalProps(
icon,
defaultExtendedIconProps
)
) {
return null;
}
}
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
for (const name in aliases) {
const icon = aliases[name];
const parent = icon.parent;
if (
// Name cannot be empty
!name || // Parent must be set and point to existing icon
typeof parent !== "string" || !icons[parent] && !aliases[parent] || // Check other props
!checkOptionalProps(
icon,
defaultExtendedIconProps
)
) {
return null;
}
}
return data;
}
const defaultIconSizeCustomisations = Object.freeze({
width: null,
height: null
});
const defaultIconCustomisations = Object.freeze({
// Dimensions
...defaultIconSizeCustomisations,
// Transformations
...defaultIconTransformations
});
function mergeCustomisations(defaults, item) {
const result = {
...defaults
};
for (const key in item) {
const value = item[key];
const valueType = typeof value;
if (key in defaultIconSizeCustomisations) {
if (value === null || value && (valueType === "string" || valueType === "number")) {
result[key] = value;
}
} else if (valueType === typeof result[key]) {
result[key] = key === "rotate" ? value % 4 : value;
}
}
return result;
}
const separator = /[\s,]+/;
function flipFromString(custom, flip) {
flip.split(separator).forEach((str) => {
const value = str.trim();
switch (value) {
case "horizontal":
custom.hFlip = true;
break;
case "vertical":
custom.vFlip = true;
break;
}
});
}
function rotateFromString(value, defaultValue = 0) {
const units = value.replace(/^-?[0-9.]*/, "");
function cleanup(value2) {
while (value2 < 0) {
value2 += 4;
}
return value2 % 4;
}
if (units === "") {
const num = parseInt(value);
return isNaN(num) ? 0 : cleanup(num);
} else if (units !== value) {
let split = 0;
switch (units) {
case "%":
split = 25;
break;
case "deg":
split = 90;
}
if (split) {
let num = parseFloat(value.slice(0, value.length - units.length));
if (isNaN(num)) {
return 0;
}
num = num / split;
return num % 1 === 0 ? cleanup(num) : 0;
}
}
return defaultValue;
}
const unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g;
const unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g;
function calculateSize(size, ratio, precision) {
if (ratio === 1) {
return size;
}
precision = precision || 100;
if (typeof size === "number") {
return Math.ceil(size * ratio * precision) / precision;
}
if (typeof size !== "string") {
return size;
}
const oldParts = size.split(unitsSplit);
if (oldParts === null || !oldParts.length) {
return size;
}
const newParts = [];
let code = oldParts.shift();
let isNumber = unitsTest.test(code);
while (true) {
if (isNumber) {
const num = parseFloat(code);
if (isNaN(num)) {
newParts.push(code);
} else {
newParts.push(Math.ceil(num * ratio * precision) / precision);
}
} else {
newParts.push(code);
}
code = oldParts.shift();
if (code === void 0) {
return newParts.join("");
}
isNumber = !isNumber;
}
}
function splitSVGDefs(content, tag = "defs") {
let defs = "";
const index = content.indexOf("<" + tag);
while (index >= 0) {
const start = content.indexOf(">", index);
const end = content.indexOf("</" + tag);
if (start === -1 || end === -1) {
break;
}
const endEnd = content.indexOf(">", end);
if (endEnd === -1) {
break;
}
defs += content.slice(start + 1, end).trim();
content = content.slice(0, index).trim() + content.slice(endEnd + 1);
}
return {
defs,
content
};
}
function mergeDefsAndContent(defs, content) {
return defs ? "<defs>" + defs + "</defs>" + content : content;
}
function wrapSVGContent(body, start, end) {
const split = splitSVGDefs(body);
return mergeDefsAndContent(split.defs, start + split.content + end);
}
const isUnsetKeyword = (value) => value === "unset" || value === "undefined" || value === "none";
function iconToSVG(icon, customisations) {
const fullIcon = {
...defaultIconProps,
...icon
};
const fullCustomisations = {
...defaultIconCustomisations,
...customisations
};
const box = {
left: fullIcon.left,
top: fullIcon.top,
width: fullIcon.width,
height: fullIcon.height
};
let body = fullIcon.body;
[fullIcon, fullCustomisations].forEach((props) => {
const transformations = [];
const hFlip = props.hFlip;
const vFlip = props.vFlip;
let rotation = props.rotate;
if (hFlip) {
if (vFlip) {
rotation += 2;
} else {
transformations.push(
"translate(" + (box.width + box.left).toString() + " " + (0 - box.top).toString() + ")"
);
transformations.push("scale(-1 1)");
box.top = box.left = 0;
}
} else if (vFlip) {
transformations.push(
"translate(" + (0 - box.left).toString() + " " + (box.height + box.top).toString() + ")"
);
transformations.push("scale(1 -1)");
box.top = box.left = 0;
}
let tempValue;
if (rotation < 0) {
rotation -= Math.floor(rotation / 4) * 4;
}
rotation = rotation % 4;
switch (rotation) {
case 1:
tempValue = box.height / 2 + box.top;
transformations.unshift(
"rotate(90 " + tempValue.toString() + " " + tempValue.toString() + ")"
);
break;
case 2:
transformations.unshift(
"rotate(180 " + (box.width / 2 + box.left).toString() + " " + (box.height / 2 + box.top).toString() + ")"
);
break;
case 3:
tempValue = box.width / 2 + box.left;
transformations.unshift(
"rotate(-90 " + tempValue.toString() + " " + tempValue.toString() + ")"
);
break;
}
if (rotation % 2 === 1) {
if (box.left !== box.top) {
tempValue = box.left;
box.left = box.top;
box.top = tempValue;
}
if (box.width !== box.height) {
tempValue = box.width;
box.width = box.height;
box.height = tempValue;
}
}
if (transformations.length) {
body = wrapSVGContent(
body,
'<g transform="' + transformations.join(" ") + '">',
"</g>"
);
}
});
const customisationsWidth = fullCustomisations.width;
const customisationsHeight = fullCustomisations.height;
const boxWidth = box.width;
const boxHeight = box.height;
let width;
let height;
if (customisationsWidth === null) {
height = customisationsHeight === null ? "1em" : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
width = calculateSize(height, boxWidth / boxHeight);
} else {
width = customisationsWidth === "auto" ? boxWidth : customisationsWidth;
height = customisationsHeight === null ? calculateSize(width, boxHeight / boxWidth) : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
}
const attributes = {};
const setAttr = (prop, value) => {
if (!isUnsetKeyword(value)) {
attributes[prop] = value.toString();
}
};
setAttr("width", width);
setAttr("height", height);
const viewBox = [box.left, box.top, boxWidth, boxHeight];
attributes.viewBox = viewBox.join(" ");
return {
attributes,
viewBox,
body
};
}
const regex = /\sid="(\S+)"/g;
const randomPrefix = "IconifyId" + Date.now().toString(16) + (Math.random() * 16777216 | 0).toString(16);
let counter = 0;
function replaceIDs(body, prefix = randomPrefix) {
const ids = [];
let match;
while (match = regex.exec(body)) {
ids.push(match[1]);
}
if (!ids.length) {
return body;
}
const suffix = "suffix" + (Math.random() * 16777216 | Date.now()).toString(16);
ids.forEach((id) => {
const newID = typeof prefix === "function" ? prefix(id) : prefix + (counter++).toString();
const escapedID = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
body = body.replace(
// Allowed characters before id: [#;"]
// Allowed characters after id: [)"], .[a-z]
new RegExp('([#;"])(' + escapedID + ')([")]|\\.[a-z])', "g"),
"$1" + newID + suffix + "$3"
);
});
body = body.replace(new RegExp(suffix, "g"), "");
return body;
}
function iconToHTML(body, attributes) {
let renderAttribsHTML = body.indexOf("xlink:") === -1 ? "" : ' xmlns:xlink="http://www.w3.org/1999/xlink"';
for (const attr in attributes) {
renderAttribsHTML += " " + attr + '="' + attributes[attr] + '"';
}
return '<svg xmlns="http://www.w3.org/2000/svg"' + renderAttribsHTML + ">" + body + "</svg>";
}
function encodeSVGforURL(svg) {
return svg.replace(/"/g, "'").replace(/%/g, "%25").replace(/#/g, "%23").replace(/</g, "%3C").replace(/>/g, "%3E").replace(/\s+/g, " ");
}
function svgToData(svg) {
return "data:image/svg+xml," + encodeSVGforURL(svg);
}
function svgToURL(svg) {
return 'url("' + svgToData(svg) + '")';
}
let policy;
function createPolicy() {
try {
policy = window.trustedTypes.createPolicy("iconify", {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
createHTML: (s) => s
});
} catch (err) {
policy = null;
}
}
function cleanUpInnerHTML(html) {
if (policy === void 0) {
createPolicy();
}
return policy ? policy.createHTML(html) : html;
}
const defaultExtendedIconCustomisations = {
...defaultIconCustomisations,
inline: false,
};
const stringToIcon = (value, validate, allowSimpleName, provider = "") => {
const colonSeparated = value.split(":");
if (value.slice(0, 1) === "@") {
if (colonSeparated.length < 2 || colonSeparated.length > 3) {
return null;
}
provider = colonSeparated.shift().slice(1);
}
if (colonSeparated.length > 3 || !colonSeparated.length) {
return null;
}
if (colonSeparated.length > 1) {
const name2 = colonSeparated.pop();
const prefix = colonSeparated.pop();
const result = {
// Allow provider without '@': "provider:prefix:name"
provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,
prefix,
name: name2
};
return result;
}
const name = colonSeparated[0];
const dashSeparated = name.split("-");
if (dashSeparated.length > 1) {
const result = {
provider,
prefix: dashSeparated.shift(),
name: dashSeparated.join("-")
};
return result;
}
if (provider === "") {
const result = {
provider,
prefix: "",
name
};
return result;
}
return null;
};
/**
* Default SVG attributes
*/
const svgDefaults = {
'xmlns': 'http://www.w3.org/2000/svg',
'xmlnsXlink': 'http://www.w3.org/1999/xlink',
'aria-hidden': true,
'role': 'img',
};
/**
* Style modes
*/
const commonProps = {
display: 'inline-block',
};
const monotoneProps = {
backgroundColor: 'currentColor',
};
const coloredProps = {
backgroundColor: 'transparent',
};
// Dynamically add common props to variables above
const propsToAdd = {
Image: 'var(--svg)',
Repeat: 'no-repeat',
Size: '100% 100%',
};
const propsToAddTo = {
WebkitMask: monotoneProps,
mask: monotoneProps,
background: coloredProps,
};
for (const prefix in propsToAddTo) {
const list = propsToAddTo[prefix];
for (const prop in propsToAdd) {
list[prefix + prop] = propsToAdd[prop];
}
}
/**
* Default values for customisations for inline icon
*/
const inlineDefaults = {
...defaultExtendedIconCustomisations,
inline: true,
};
/**
* Fix size: add 'px' to numbers
*/
function fixSize(value) {
return value + (value.match(/^[-0-9.]+$/) ? 'px' : '');
}
/**
* Render icon
*/
const render = (
// Icon must be validated before calling this function
icon,
// Partial properties
props,
// Icon name
name) => {
// Get default properties
const defaultProps = props.inline
? inlineDefaults
: defaultExtendedIconCustomisations;
// Get all customisations
const customisations = mergeCustomisations(defaultProps, props);
// Check mode
const mode = props.mode || 'svg';
// Create style
const style = {};
const customStyle = props.style || {};
// Create SVG component properties
const componentProps = {
...(mode === 'svg' ? svgDefaults : {}),
};
if (name) {
const iconName = stringToIcon(name);
if (iconName) {
const classNames = ['iconify'];
const props = [
'provider',
'prefix',
];
for (const prop of props) {
if (iconName[prop]) {
classNames.push('iconify--' + iconName[prop]);
}
}
componentProps.className = classNames.join(' ');
}
}
// Get element properties
for (let key in props) {
const value = props[key];
if (value === void 0) {
continue;
}
switch (key) {
// Properties to ignore
case 'icon':
case 'style':
case 'children':
case 'onLoad':
case 'mode':
case 'ssr':
break;
// Forward ref
case '_ref':
componentProps.ref = value;
break;
// Merge class names
case 'className':
componentProps[key] =
(componentProps[key] ? componentProps[key] + ' ' : '') +
value;
break;
// Boolean attributes
case 'inline':
case 'hFlip':
case 'vFlip':
customisations[key] =
value === true || value === 'true' || value === 1;
break;
// Flip as string: 'horizontal,vertical'
case 'flip':
if (typeof value === 'string') {
flipFromString(customisations, value);
}
break;
// Color: copy to style
case 'color':
style.color = value;
break;
// Rotation as string
case 'rotate':
if (typeof value === 'string') {
customisations[key] = rotateFromString(value);
}
else if (typeof value === 'number') {
customisations[key] = value;
}
break;
// Remove aria-hidden
case 'ariaHidden':
case 'aria-hidden':
if (value !== true && value !== 'true') {
delete componentProps['aria-hidden'];
}
break;
// Copy missing property if it does not exist in customisations
default:
if (defaultProps[key] === void 0) {
componentProps[key] = value;
}
}
}
// Generate icon
const item = iconToSVG(icon, customisations);
const renderAttribs = item.attributes;
// Inline display
if (customisations.inline) {
style.verticalAlign = '-0.125em';
}
if (mode === 'svg') {
// Add style
componentProps.style = {
...style,
...customStyle,
};
// Add icon stuff
Object.assign(componentProps, renderAttribs);
// Counter for ids based on "id" property to render icons consistently on server and client
let localCounter = 0;
let id = props.id;
if (typeof id === 'string') {
// Convert '-' to '_' to avoid errors in animations
id = id.replace(/-/g, '_');
}
// Add icon stuff
componentProps.dangerouslySetInnerHTML = {
__html: cleanUpInnerHTML(replaceIDs(item.body, id ? () => id + 'ID' + localCounter++ : 'iconifyReact')),
};
return createElement('svg', componentProps);
}
// Render <span> with style
const { body, width, height } = icon;
const useMask = mode === 'mask' ||
(mode === 'bg' ? false : body.indexOf('currentColor') !== -1);
// Generate SVG
const html = iconToHTML(body, {
...renderAttribs,
width: width + '',
height: height + '',
});
// Generate style
componentProps.style = {
...style,
'--svg': svgToURL(html),
'width': fixSize(renderAttribs.width),
'height': fixSize(renderAttribs.height),
...commonProps,
...(useMask ? monotoneProps : coloredProps),
...customStyle,
};
return createElement('span', componentProps);
};
/**
* Storage for icons referred by name
*/
const storage = Object.create(null);
function IconComponent(props) {
const icon = props.icon;
const data = typeof icon === 'string' ? storage[icon] : icon;
if (!data) {
return props.children
? props.children
: createElement('span', {});
}
return render({
...defaultIconProps,
...data,
}, props, typeof icon === 'string' ? icon : undefined);
}
/**
* Block icon
*
* @param props - Component properties
*/
const Icon = memo(forwardRef((props, ref) => IconComponent({
...props,
_ref: ref,
})));
/**
* Inline icon (has negative verticalAlign that makes it behave like icon font)
*
* @param props - Component properties
*/
const InlineIcon = memo(forwardRef((props, ref) => IconComponent({
inline: true,
...props,
_ref: ref,
})));
/**
* Add icon to storage, allowing to call it by name
*
* @param name
* @param data
*/
function addIcon(name, data) {
storage[name] = data;
}
/**
* Add collection to storage, allowing to call icons by name
*
* @param data Icon set
* @param prefix Optional prefix to add to icon names, true (default) if prefix from icon set should be used.
*/
function addCollection(data, prefix) {
const iconPrefix = typeof prefix === 'string'
? prefix
: prefix !== false && typeof data.prefix === 'string'
? data.prefix + ':'
: '';
quicklyValidateIconSet(data) &&
parseIconSet(data, (name, icon) => {
if (icon) {
storage[iconPrefix + name] = icon;
}
});
}
export { Icon, InlineIcon, addCollection, addIcon };

21
node_modules/@iconify/react/license.txt generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019-PRESENT Vjacheslav Trushkin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

14
node_modules/@iconify/react/offline/package.json generated vendored Normal file
View file

@ -0,0 +1,14 @@
{
"name": "@iconify/react/offline",
"main": "../dist/offline.js",
"types": "../dist/offline.d.ts",
"exports": {
"./*": "./*",
".": {
"types": "../dist/offline.d.ts",
"require": "../dist/offline.cjs",
"import": "../dist/offline.js",
"default": "../dist/offline.js"
}
}
}

5
node_modules/@iconify/react/offline/readme.md generated vendored Normal file
View file

@ -0,0 +1,5 @@
# @iconify/react/offline
This sub-directory contains `package.json` with entry points for importing `@iconify/react/offline`.
There is a duplicate entry in `exports` section of `package.json` in the parent directory, but at moment of coding this, TypeScript does not support conditional exports properly, so this directory is used as a duplicate to make everything work with TypeScript.

75
node_modules/@iconify/react/package.json generated vendored Normal file
View file

@ -0,0 +1,75 @@
{
"name": "@iconify/react",
"description": "Iconify icon component for React.",
"author": "Vjacheslav Trushkin",
"type": "module",
"version": "6.0.0",
"publishConfig": {
"tag": "next"
},
"license": "MIT",
"bugs": "https://github.com/iconify/iconify/issues",
"homepage": "https://iconify.design/",
"funding": "https://github.com/sponsors/cyberalien",
"repository": {
"type": "git",
"url": "https://github.com/iconify/iconify.git",
"directory": "components/react"
},
"main": "dist/iconify.js",
"types": "dist/iconify.d.ts",
"exports": {
"./*": "./*",
".": {
"types": "./dist/iconify.d.ts",
"require": "./dist/iconify.cjs",
"import": "./dist/iconify.js",
"default": "./dist/iconify.js"
},
"./offline": {
"types": "./dist/offline.d.ts",
"require": "./dist/offline.cjs",
"import": "./dist/offline.js",
"default": "./dist/offline.js"
},
"./dist/offline": {
"types": "./dist/offline.d.ts",
"require": "./dist/offline.cjs",
"import": "./dist/offline.js",
"default": "./dist/offline.js"
}
},
"dependencies": {
"@iconify/types": "^2.0.0"
},
"devDependencies": {
"@microsoft/api-extractor": "^7.52.2",
"@rollup/plugin-node-resolve": "^15.3.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@types/react": "^18.3.20",
"@types/react-dom": "^18.3.5",
"jsdom": "^25.0.1",
"react": "^18.3.1",
"rimraf": "^6.0.1",
"rollup": "^4.38.0",
"typescript": "^5.8.2",
"vitest": "^2.1.9",
"@iconify/core": "^3.1.0",
"@iconify/utils": "^2.3.0"
},
"peerDependencies": {
"react": ">=16"
},
"scripts": {
"clean": "rimraf lib dist tsconfig.tsbuildinfo",
"prebuild": "pnpm run clean",
"build": "node build",
"build:lib": "tsc -b tsconfig.src.json",
"build:dist": "rollup -c rollup.config.js",
"prebuild:api": "api-extractor run --local --verbose --config api-extractor.offline.json",
"build:api": "api-extractor run --local --verbose --config api-extractor.iconify.json",
"build:cleanup": "node cleanup",
"test": "vitest"
}
}

371
node_modules/@iconify/react/readme.md generated vendored Normal file
View file

@ -0,0 +1,371 @@
# Iconify for React
Iconify for React is not yet another icon component! There are many of them already.
What you get with other components:
- Limited set of icons.
- Large bundle size because all icons are bundled.
Iconify icon component is nothing like that. Component does not include any icon data, it is not tied to any specific icon set. Instead, all data is retrieved from public API on demand.
That means:
- One syntax for over 200,000 icons from 150+ icon sets.
- Renders SVG. Many components simply render icon fonts, which look ugly. Iconify renders pixel perfect SVG.
- Loads icons on demand. No need to bundle icons, component will automatically load icon data for icons that you use from Iconify API.
For more information about Iconify project visit [https://iconify.design/](https://iconify.design/).
For extended documentation visit [Iconify for React documentation](https://iconify.design/docs/icon-components/react/).
## Installation
If you are using NPM:
```bash
npm install --save-dev @iconify/react
```
If you are using Yarn:
```bash
yarn add --dev @iconify/react
```
## Usage with API
Install `@iconify/react` and import `Icon` from it:
```typescript
import { Icon } from '@iconify/react';
```
Then use `Icon` component with icon name or data as "icon" parameter:
```jsx
<Icon icon="mdi-light:home" />
```
Component will automatically retrieve data for "mdi-light:home" from Iconify API and render it. There are over 200,000 icons available on Iconify API from various free and open source icon sets, including all the most popular icon sets.
## Offline usage
This icon component is designed to be used with Iconify API, loading icon data on demand instead of bundling it.
If you want to use icons without Iconify API, [there are many other options available](https://iconify.design/docs/usage/).
## Icon Names
Icon name is a string. Few examples:
- `@api-provider:icon-set-prefix:icon-name`
- `mdi-light:home` (in this example API provider is empty, so it is skipped)
It has 3 parts, separated by ":":
- provider points to API source. Starts with "@", can be empty (empty value is used for public Iconify API).
- prefix is name of icon set.
- name is name of icon.
See [Iconify for React icon names documentation](https://iconify.design/docs/icon-components/react/icon-name.html) for more detailed explanation.
## Using icon data
Instead of icon name, you can pass icon data to component:
```jsx
import { Icon } from '@iconify/react';
import home from '@iconify-icons/mdi-light/home';
function renderHomeIcon() {
return <Icon icon={home} />;
}
```
See [icon packages documentation](https://iconify.design/docs/icons/) for more details.
### Next.js notice
Example above will currently fail with Next.js. This is because Next.js uses outdated packaging software that does not support ES modules. But do not worry, there is a simple solution: switch to CommonJS icon packages.
To switch to CommonJS package, replace this line in example above:
```js
import home from '@iconify-icons/mdi-light/home';
```
with
```js
import home from '@iconify/icons-mdi-light/home';
```
All icons are available as ES modules for modern bundler and as CommonJS modules for outdated bundlers. ES modules use format `@iconify-icons/{prefix}`, CommonJS modules use `@iconify/icons-{prefix}`.
For more details, see [icon packages documentation](https://iconify.design/docs/icons/).
## Vertical alignment
Icons have 2 modes: inline and block. Difference between modes is `vertical-align` that is added to inline icons.
Inline icons are aligned slightly below baseline, so they look centred compared to text, like glyph fonts.
Block icons do not have alignment, like images, which aligns them to baseline by default.
Alignment option was added to make icons look like continuation of text, behaving like glyph fonts. This should make migration from glyph fonts easier.
```jsx
import React from 'react';
import { Icon, InlineIcon } from '@iconify/react';
export function inlineDemo() {
return (
<div>
<p>
Block:
<Icon icon="line-md:image-twotone" />
<Icon icon="mdi:account-box-outline" />
</p>
<p>
Inline:
<InlineIcon icon="line-md:image-twotone" />
<InlineIcon icon="mdi:account-box-outline" />
</p>
</div>
);
}
```
To toggle between block and inline modes, you can either use `InlineIcon` or use boolean `inline` property:
```jsx
import React from 'react';
import { Icon } from '@iconify/react';
export function inlineDemo() {
return (
<div>
<p>
Block:
<Icon icon="line-md:image-twotone" />
<Icon icon="mdi:account-box-outline" />
</p>
<p>
Inline:
<Icon icon="line-md:image-twotone" inline={true} />
<Icon icon="mdi:account-box-outline" inline={true} />
</p>
</div>
);
}
```
Visual example to show the difference between inline and block modes:
![Inline icon](https://iconify.design/assets/images/inline.png)
## Icon component properties
`icon` property is mandatory. It tells component what icon to render. The value can be a string containing the icon name or an object containing the icon data.
The icon component has the following optional properties:
- `inline`. Changes icon behaviour to match icon fonts. See "Inline icon" section above.
- `width` and `height`. Icon dimensions. The default values are "1em" for both. See "Dimensions" section below.
- `color`. Icon colour. This is the same as setting colour in style. See "Icon colour" section below.
- `flip`, `hFlip`, `vFlip`. Flip icon horizontally and/or vertically. See "Transformations" section below.
- `rotate`. Rotate icon by 90, 180 or 270 degrees. See "Transformations" section below.
- `align`, `vAlign`, `hAlign`, `slice`. Icon alignment. See "Alignment" section below.
- `onLoad`. Callback function that is called when icon data has been loaded. See "onLoad" section below.
### Other properties and events
In addition to the properties mentioned above, the icon component accepts any other properties and events. All other properties and events will be passed to generated `SVG` element, so you can do stuff like assigning `onClick` event, setting the inline style, add title and so on.
### Dimensions
By default, icon height is "1em". With is dynamic, calculated using the icon's width to height ratio. This makes it easy to change icon size by changing `font-size` in the stylesheet, just like icon fonts.
There are several ways to change icon dimensions:
- Setting `font-size` in style (or `fontSize` if you are using inline style).
- Setting `width` and/or `height` property.
Values for `width` and `height` can be numbers or strings.
If you set only one dimension, another dimension will be calculated using the icon's width to height ratio. For example, if the icon size is 16 x 24, you set the height to 48, the width will be set to 32. Calculations work not only with numbers, but also with string values.
#### Dimensions as numbers
You can use numbers for `width` and `height`.
```jsx
<Icon icon={homeIcon} height={24} />
```
```jsx
<Icon icon="mdi-light:home" width={16} height={16} />
```
Number values are treated as pixels. That means in examples above, values are identical to "24px" and "16px".
#### Dimensions as strings without units
If you use strings without units, they are treated the same as numbers in an example above.
```jsx
<Icon icon={homeIcon} height="24" />
```
```jsx
<Icon icon="mdi-light:home" width="16" height={'16'} />
```
#### Dimensions as strings with units
You can use units in width and height values:
```jsx
<Icon icon="mdi-light:home" height="2em" />
```
Be careful when using `calc`, view port based units or percentages. In SVG element they might not behave the way you expect them to behave and when using such units, you should consider settings both width and height.
#### Dimensions as 'auto'
Keyword "auto" sets dimensions to the icon's `viewBox` dimensions. For example, for 24 x 24 icon using `height="auto"` sets height to 24 pixels.
```jsx
<Icon icon="mdi-light:home" height="auto" />
```
### Icon colour
There are two types of icons: icons that do not have a palette and icons that do have a palette.
Icons that do have a palette, such as emojis, cannot be customised. Setting colour to such icons will not change anything.
Icons that do not have a palette can be customised. By default, colour is set to "currentColor", which means the icon's colour matches text colour. To change the colour you can:
- Set `color` style or use stylesheet to target icon. If you are using the stylesheet, target `svg` element.
- Add `color` property.
Examples:
Using `color` property:
```jsx
<Icon icon="eva:alert-triangle-fill" color="red" />
<Icon icon="eva:alert-triangle-fill" color="#f00" />
```
Using inline style:
```jsx
<Icon icon="eva:alert-triangle-fill" style={{color: 'red'}} />
<Icon icon="eva:alert-triangle-fill" style={{color: '#f00'}} />
```
Using stylesheet:
```jsx
<Icon icon="eva:alert-triangle-fill" className="red-icon" />
```
```css
.red-icon {
color: red;
}
```
### Transformations
You can rotate and flip the icon.
This might seem redundant because icon can also be rotated and flipped using CSS transformations. So why do transformation properties exist? Because it is a different type of transformation.
- CSS transformations transform the entire icon.
- Icon transformations transform the contents of the icon.
If you have a square icon, this makes no difference. However, if you have an icon that has different width and height values, it makes a huge difference.
Rotating 16x24 icon by 90 degrees results in:
- CSS transformation keeps 16x24 bounding box, which might cause the icon to overlap text around it.
- Icon transformation changes bounding box to 24x16, rotating content inside an icon.
See [icon transformations documentation](https://iconify.design/docs/icon-components/react/transform.html) for more details.
#### Flipping an icon
There are several properties available to flip an icon:
- `hFlip`: boolean property, flips icon horizontally.
- `vFlip`: boolean property, flips icon vertically.
- `flip`: shorthand string property, can flip icon horizontally and/or vertically.
Examples:
Flip an icon horizontally:
```jsx
<Icon icon="eva:alert-triangle-fill" hFlip={true} />
<Icon icon="eva:alert-triangle-fill" flip="horizontal" />
```
Flip an icon vertically:
```jsx
<Icon icon="eva:alert-triangle-fill" vFlip={true} />
<Icon icon="eva:alert-triangle-fill" flip="vertical" />
```
Flip an icon horizontally and vertically (the same as 180 degrees rotation):
```jsx
<Icon icon="eva:alert-triangle-fill" hFlip={true} vFlip={true} />
<Icon icon="eva:alert-triangle-fill" flip="horizontal,vertical" />
```
#### Rotating an icon
An icon can be rotated by 90, 180 and 270 degrees. Only contents of the icon are rotated.
To rotate an icon, use `rotate` property. Value can be a string (degrees or percentages) or a number.
Number values are 1 for 90 degrees, 2 for 180 degrees, 3 for 270 degrees.
Examples of 90 degrees rotation:
```jsx
<Icon icon="eva:alert-triangle-fill" rotate={1} />
<Icon icon="eva:alert-triangle-fill" rotate="90deg" />
<Icon icon="eva:alert-triangle-fill" rotate="25%" />
```
### onLoad
`onLoad` property is an optional callback function. It is called when icon data has been loaded.
It is not an event, such as `onClick` event for links, it is a simple callback function.
When `onLoad` is called:
- If value of icon property is an object, `onLoad` is not called.
- If value of icon property is a string and icon data is available, `onLoad` is called on first render.
- If value of icon property is a string and icon data is not available, `onLoad` is called on first re-render after icon data is retrieved from API.
What is the purpose of `onLoad`? To let you know when Icon component renders an icon and when it does not render anything. This allows you to do things like adding class name for parent element, such as "container--with-icon" that modify layout if icon is being displayed.
## Full documentation
For extended documentation visit [Iconify for React documentation](https://iconify.design/docs/icon-components/react/).
## License
React component is released with MIT license.
© 2019-PRESENT Vjacheslav Trushkin
See [Iconify icon sets page](https://icon-sets.iconify.design/) for list of collections and their licenses.

17
node_modules/@iconify/react/tsconfig.src.json generated vendored Normal file
View file

@ -0,0 +1,17 @@
{
"include": ["src/**/*"],
"exclude": ["tests/**/*"],
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"target": "ES2019",
"module": "ESNext",
"declaration": true,
"sourceMap": false,
"strict": false,
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
}
}

18
node_modules/@iconify/react/tsconfig.tests.json generated vendored Normal file
View file

@ -0,0 +1,18 @@
{
"include": ["tests/**/*", "tests/**/*.tsx"],
"exclude": ["src/*"],
"compilerOptions": {
"rootDir": "./tests",
"target": "ES2019",
"module": "ESNext",
"declaration": false,
"sourceMap": false,
"strict": false,
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"jsx": "react",
"noEmit": true
}
}

9
node_modules/@iconify/react/vitest.config.ts generated vendored Normal file
View file

@ -0,0 +1,9 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
watch: false,
},
});

8
node_modules/@iconify/types/.prettierrc generated vendored Normal file
View file

@ -0,0 +1,8 @@
{
"trailingComma": "es5",
"singleQuote": true,
"useTabs": true,
"semi": true,
"quoteProps": "consistent",
"endOfLine": "lf"
}

459
node_modules/@iconify/types/README.md generated vendored Normal file
View file

@ -0,0 +1,459 @@
# Iconify Types
Type definitions for using Iconify icon sets with TypeScript.
## Files structure
Iconify icon sets are available in several formats:
- Big JSON files that combine many icons in one file
- Node.js packages split into individual icons
### Icon format
Each icon is represented by the `IconifyIcon` type. It is a simple object with multiple string, number or boolean attributes.
The only required attribute is:
- `body`: string. Value contains inner HTML of an icon as a string, for example `<path d="..."/>`.
Optional attributes are represented by type `IconifyOptional`. They are split into several types: dimensions (`IconifyDimenisons` type) and transformations (`IconifyTransformations` type).
Dimensions attributes:
- `width`: number. viewBox width, number. If missing, value is set to 16.
- `height`: number. viewBox height, number. If missing, value is set to 16.
- `left`: number. viewBox left, number. If missing, the value is set to 0.
- `top`: number. viewBox top, number. If missing, the value is set to 0.
Transformations:
- `rotate`: number. Icon rotation. Iconify icons can be rotated in 90 degrees increments, allowing to reuse the same source icon for multiple icons, such as arrow-up being a copy of arrow-left rotated by 90 degrees. Values are 0 for 0 degrees, 1 for 90 degrees, 2 for 180 degrees, 3 for 270 degrees. The default value is 0.
- `hFlip`: boolean. Horizontal flip. Similar to the rotation transformation, an icon can be flipped horizontally and vertically. It can be used to quickly create aliases, such as arrow-left being an alias of arrow-right, but with hFlip set to true. The default value is false.
- `vFlip`: boolean. Vertical flip. The default value is false.
Example of icon object:
```js
const mdiHandIcon = {
body: '<path d="M6.58 19h8v3h-8v-3m13.16-7.4c-.19-.2-.45-.32-.74-.32l-.22.03l-3.2 1.69v-1.17l.51-8.93c.03-.55-.39-1.03-.94-1.06c-.55-.03-1.03.39-1.06.94l-.27 4.69h-.24l-1.04.11V2a1 1 0 0 0-1-1c-.54 0-1 .45-1 1v6.41l-.82.37l-.69-5.46c-.07-.55-.57-.94-1.12-.87c-.55.05-.94.55-.87 1.12l.77 6.06l-.38.17c-.13.05-.25.13-.36.2l-1.1-3.89c-.16-.57-.72-.91-1.26-.77c-.53.16-.83.74-.67 1.31l2.57 9.12c0 .03.02.07.03.1l.03.13h.01c.22.57.79 1 1.4 1h6.5c.39 0 .74-.16 1-.43l4.92-4.2l-.76-.77z" fill="currentColor"/>',
width: 24,
height: 24,
};
```
### Icon sets format
Iconify icon sets format is available from multiple sources:
- NPM package `@iconify/json` that includes all icon sets
- API responses used by SVG framework
Icon set format structure is available as the `IconifyJSON` type. It is an object with several fields:
- `prefix`: string. Icon set prefix.
- `icons`: object. Icons data. Value is an object that represents a set of icons, where the key is an icon name and value is `IconifyIcon` object (see "Icon format" above).
- `aliases`: object. Icon aliases, similar to the `icons` object (see "Aliases" section below).
Example:
```json
{
"prefix": "mdi",
"icons": {
"home": {
"body": "<path d=\"M10 20v-6h4v6h5v-8h3L12 3L2 12h3v8h5z\" fill=\"currentColor\"/>",
"width": 24,
"height": 24
},
"arrow-left": {
"body": "<path d=\"M20 11v2H8l5.5 5.5l-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5L8 11h12z\" fill=\"currentColor\"/>",
"width": 24,
"height": 24
}
}
}
```
All icon properties except for `body` are optional and are represented by type `IconifyOptional`. Type `IconifyJSON` also extends type `IconifyOptional`, allowing all optional properties to be placed in the root object.
If an icon is missing a property, look in the root object for the default value. If the root object does not have the default value, use Iconify default value for that property (see list of properties and default values in the "Icon format" section above).
Default values in the root object make it possible to reduce duplication.
Example:
```json
{
"prefix": "mdi",
"icons": {
"home": {
"body": "<path d=\"M10 20v-6h4v6h5v-8h3L12 3L2 12h3v8h5z\" fill=\"currentColor\"/>"
},
"arrow-left": {
"body": "<path d=\"M20 11v2H8l5.5 5.5l-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5L8 11h12z\" fill=\"currentColor\"/>"
}
},
"width": 24,
"height": 24
}
```
In this example, both icons are 24x24, so width and height have been moved to the root object.
Another example:
```json
{
"prefix": "fa-solid",
"icons": {
"arrow-left": {
"body": "<path d=\"M257.5 445.1l-22.2 22.2c-9.4 9.4-24.6 9.4-33.9 0L7 273c-9.4-9.4-9.4-24.6 0-33.9L201.4 44.7c9.4-9.4 24.6-9.4 33.9 0l22.2 22.2c9.5 9.5 9.3 25-.4 34.3L136.6 216H424c13.3 0 24 10.7 24 24v32c0 13.3-10.7 24-24 24H136.6l120.5 114.8c9.8 9.3 10 24.8.4 34.3z\" fill=\"currentColor\"/>",
"width": 448
},
"arrow-circle-left": {
"body": "<path d=\"M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248s-111 248-248 248zm28.9-143.6L209.4 288H392c13.3 0 24-10.7 24-24v-16c0-13.3-10.7-24-24-24H209.4l75.5-72.4c9.7-9.3 9.9-24.8.4-34.3l-11-10.9c-9.4-9.4-24.6-9.4-33.9 0L107.7 239c-9.4 9.4-9.4 24.6 0 33.9l132.7 132.7c9.4 9.4 24.6 9.4 33.9 0l11-10.9c9.5-9.5 9.3-25-.4-34.3z\" fill=\"currentColor\"/>"
},
"barcode": {
"body": "<path d=\"M0 448V64h18v384H0zm26.857-.273V64H36v383.727h-9.143zm27.143 0V64h8.857v383.727H54zm44.857 0V64h8.857v383.727h-8.857zm36 0V64h17.714v383.727h-17.714zm44.857 0V64h8.857v383.727h-8.857zm18 0V64h8.857v383.727h-8.857zm18 0V64h8.857v383.727h-8.857zm35.715 0V64h18v383.727h-18zm44.857 0V64h18v383.727h-18zm35.999 0V64h18.001v383.727h-18.001zm36.001 0V64h18.001v383.727h-18.001zm26.857 0V64h18v383.727h-18zm45.143 0V64h26.857v383.727h-26.857zm35.714 0V64h9.143v383.727H476zm18 .273V64h18v384h-18z\" fill=\"currentColor\"/>"
}
},
"width": 512,
"height": 512
}
```
In this example `arrow-circle-left` and `barcode` have width of 512, `arrow-left` has width of 448. All icons have a height of 512.
#### Aliases
In addition to `icons`, another important field in icon set object is `aliases`.
Aliases object is similar to icons object, except that instead of icon body icons reference another icon.
Each entry has the same attributes as an icon, except for `body` and has required attribute `parent` that contains the name of the parent icon. The parent icon must be present in the icon set file.
Example:
```json
{
"prefix": "fa",
"icons": {
"automobile": {
"body": "<path d=\"M480 960q0-66-47-113t-113-47t-113 47t-47 113t47 113t113 47t113-47t47-113zm36-320h1016l-89-357q-2-8-14-17.5t-21-9.5H640q-9 0-21 9.5T605 283zm1372 320q0-66-47-113t-113-47t-113 47t-47 113t47 113t113 47t113-47t47-113zm160-96v384q0 14-9 23t-23 9h-96v128q0 80-56 136t-136 56t-136-56t-56-136v-128H512v128q0 80-56 136t-136 56t-136-56t-56-136v-128H32q-14 0-23-9t-9-23V864q0-93 65.5-158.5T224 640h28l105-419q23-94 104-157.5T640 0h768q98 0 179 63.5T1691 221l105 419h28q93 0 158.5 65.5T2048 864z\" fill=\"currentColor\"/>",
"width": 2048,
"height": 1600
}
},
"aliases": {
"car": {
"parent": "automobile"
}
}
}
```
In this example `car` is an alias of `automobile`, allowing to use the same icon by multiple names.
Another example:
```json
{
"prefix": "fa",
"icons": {
"caret-left": {
"body": "<path d=\"M576 192v896q0 26-19 45t-45 19t-45-19L19 685Q0 666 0 640t19-45l448-448q19-19 45-19t45 19t19 45z\" fill=\"currentColor\"/>",
"width": 576,
"height": 1280
}
},
"aliases": {
"caret-right": {
"parent": "caret-left",
"hFlip": true
}
}
}
```
In this example `caret-right` is alias of `caret-left`, but with additional `hFlip` attribute. It is identical to this:
```json
{
"prefix": "fa",
"icons": {
"caret-left": {
"body": "<path d=\"M576 192v896q0 26-19 45t-45 19t-45-19L19 685Q0 666 0 640t19-45l448-448q19-19 45-19t45 19t19 45z\" fill=\"currentColor\"/>"
},
"caret-right": {
"body": "<path d=\"M576 192v896q0 26-19 45t-45 19t-45-19L19 685Q0 666 0 640t19-45l448-448q19-19 45-19t45 19t19 45z\" fill=\"currentColor\"/>",
"hFlip": true
}
},
"width": 576,
"height": 1280
}
```
##### Merging alias attributes
If both icon and alias have same attribute, following rules apply:
- `rotate`: attributes are combined. For example, icon has rotate = 1, alias has rotate = 1. Result will have rotate = 2. To prevent overflow, if rotate > 3, rotate = rotate - 4.
- `hFlip` and `vFlip`: attributes are combined. For example, icon has hFlip = true, alias also has hFlip = true (icon.hFlip !== alias.hFlip). Result is false. false + false = false, false + true = true, true + true = false.
- other attributes are overwritten.
Example:
```json
{
"prefix": "fa",
"icons": {
"caret-left": {
"body": "<path d=\"M576 192v896q0 26-19 45t-45 19t-45-19L19 685Q0 666 0 640t19-45l448-448q19-19 45-19t45 19t19 45z\" fill=\"currentColor\"/>",
"hFlip": true,
"width": 576,
"height": 1280
}
},
"aliases": {
"caret-left-compact": {
"parent": "caret-left",
"left": 64,
"width": 448
},
"caret-right": {
"parent": "caret-left",
"hFlip": true
}
}
}
```
is identical to:
```json
{
"prefix": "fa",
"icons": {
"caret-left": {
"body": "<path d=\"M576 192v896q0 26-19 45t-45 19t-45-19L19 685Q0 666 0 640t19-45l448-448q19-19 45-19t45 19t19 45z\" fill=\"currentColor\"/>",
"hFlip": true
},
"caret-left-compact": {
"body": "<path d=\"M576 192v896q0 26-19 45t-45 19t-45-19L19 685Q0 666 0 640t19-45l448-448q19-19 45-19t45 19t19 45z\" fill=\"currentColor\"/>",
"hFlip": true, // from caret-left
"left": 64, // overwritten
"width": 448 // overwritten
},
"caret-right": {
"body": "<path d=\"M576 192v896q0 26-19 45t-45 19t-45-19L19 685Q0 666 0 640t19-45l448-448q19-19 45-19t45 19t19 45z\" fill=\"currentColor\"/>"
// hFlip = false, which is default value, so it was removed
}
},
"width": 576,
"height": 1280
}
```
#### Metadata
Icon set files might also contain the metadata. That data is used for browsing icons, searching icons, exporting icon sets as fonts.
Metadata is a combination of several types, represented as type `IconifyMetaData`.
##### Icon set information
Icon set information is part of the metadata, it includes information about an author and license.
Example:
```json
{
"prefix": "dashicons",
"info": {
"name": "Dashicons",
"total": 304,
"author": {
"name": "WordPress",
"url": "https://github.com/WordPress/dashicons"
},
"license": {
"title": "GPL 2.0",
"spdx": "GPL-2.0-only",
"url": "http://www.gnu.org/licenses/gpl-2.0.html"
},
"version": "0.9.0",
"samples": ["shortcode", "businessperson", "editor-expand"],
"height": 20,
"category": "General",
"palette": false
},
"icons": {
// Icons here
}
}
```
##### Info
Information block is part of the metadata, it is used for browsing or searching icon sets. It also contains the license for icons in the icon set and information about the author.
Info block is represented by the type `IconifyInfo`. You can see an example above in "info" property.
IconifyInfo type has the following properties, most of them are optional:
- `name`: string. Icon set name. This field is always set.
- `total`: number. The total number of icons, optional.
- `version`: string. The current version, optional.
- `author`: object. Information about the author, always set. Author information has the following properties:
- `name`: string. Author name. This field is always set.
- `url`: string. Link to icon set, optional. Usually links to GitHub repository.
- `license`: object. Information about the license, always set. License information has the following properties:
- `title`: string. License title. This field is always set.
- `spdx`: string. SPDX license identifier, optional.
- `url`: string. Link to the license, optional.
- `samples`: string[]. Value is an array of icon names that should be used as samples when showing the icon set in an icon sets list.
- `height`: number | number[]. Value is a number or array of numbers, values are pixel grids used in the icon set. If any icons in an icon set do not match the grid, this attribute should not be set.
- `displayHeight`: number. The height value that should be used for displaying samples. Value is a number between 16 and 30 (inclusive).
##### Characters map
Characters map is part of the metadata, it is used for icon sets that are either imported from icon fonts or intended to be exported to icon font.
Characters map allows storing characters for export as well as searching icons by character used in an icon font.
It is a simple object, where the key is character code in hexadecimal form, value is an icon name.
Important: each icon can have multiple characters!
Example:
```json
{
"prefix": "fa",
"icons": {
// Icons here
},
"chars": {
"f000": "glass",
"f001": "music",
"f002": "search",
"f003": "envelope-o",
"f004": "heart",
"f005": "star"
// and so on...
}
}
```
##### Categories
Categories are part of the metadata, used to allow filtering icons when showing the entire icons set.
Categories list is a simple object, where the key is category name, value is the list of icons.
Important: each icon can belong to multiple categories!
```json
{
"prefix": "fa-solid",
"icons": {
// Icons here
},
"categories": {
"Accessibility": [
"american-sign-language-interpreting",
"assistive-listening-systems",
"audio-description",
"blind",
"braille",
"closed-captioning",
"deaf",
"low-vision",
"phone-volume",
"question-circle",
"sign-language",
"tty",
"universal-access",
"wheelchair"
],
"Alert": [
"bell",
"bell-slash",
"exclamation",
"exclamation-circle",
"exclamation-triangle",
"radiation",
"radiation-alt",
"skull-crossbones"
]
// and so on...
}
}
```
##### Themes
Themes are part of the metadata, similar to categories, but using prefixes or suffixes to identify icons that belong to a theme.
This is useful when icon set has variations of icons, such as "baseline-_", "outline-_".
Example:
```json
{
"prefix": "ic",
"icons": {
// Icons here
},
"themes": {
"baseline": {
"title": "Baseline",
"prefix": "baseline-"
},
"outline": {
"title": "Outline",
"prefix": "outline-"
},
"round": {
"title": "Round",
"prefix": "round-"
},
"sharp": {
"title": "Sharp",
"prefix": "sharp-"
},
"twotone": {
"title": "Two-Tone",
"prefix": "twotone-"
}
}
}
```
Each theme can have one of the attributes: `prefix` or `suffix`. The prefix must end with `-`, suffix must start with `-`.
In an example above, all icons that start with "baseline-", such as "baseline-home", are considered part of the "Baseline" theme.
#### All attributes
For an example of full icon set files that include metadata, look in icon set files in `@iconify/json` package or browse it at GitHub: [https://github.com/iconify/collections-json](https://github.com/iconify/collections-json)
For an example of individual icons, look in JavaScript files in NPM packages such as `@iconify/icons-mdi`.
## Usage
This repository is intended to be used with any Iconify packages.
At the moment of writing, multiple Iconify packages are written without TypeScript. At the beginning of the year 2020 plan is to rewrite all of them with TypeScript to make sure data is consistent and avoid duplication, this package will be used for sharing types between Iconify packages.
## License
This package is licensed under MIT license.
`SPDX-License-Identifier: MIT`
Previous versions of this package were dual-licensed under Apache 2.0 and GPL 2.0 licence, which was messy and confusing. This was later changed to MIT for simplicity.
© 2021 - 2022 Vjacheslav Trushkin / Iconify OÜ

21
node_modules/@iconify/types/license.txt generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 - 2022 Vjacheslav Trushkin / Iconify OÜ
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

23
node_modules/@iconify/types/package.json generated vendored Normal file
View file

@ -0,0 +1,23 @@
{
"name": "@iconify/types",
"type": "module",
"description": "Types for Iconify data",
"version": "2.0.0",
"author": "Vjacheslav Trushkin",
"license": "MIT",
"main": "./types.js",
"types": "./types.d.ts",
"bugs": "https://github.com/iconify/iconify/issues",
"homepage": "https://github.com/iconify/iconify",
"repository": {
"type": "git",
"url": "https://github.com/iconify/iconify.git",
"directory": "packages/types"
},
"devDependencies": {
"typescript": "^4.8.2"
},
"scripts": {
"test": "tsc --noEmit --strict --typeRoots '[]' types.d.ts"
}
}

15
node_modules/@iconify/types/pnpm-lock.yaml generated vendored Normal file
View file

@ -0,0 +1,15 @@
lockfileVersion: 5.4
specifiers:
typescript: ^4.6.2
devDependencies:
typescript: 4.7.4
packages:
/typescript/4.7.4:
resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true

44
node_modules/@iconify/types/provider.d.ts generated vendored Normal file
View file

@ -0,0 +1,44 @@
/**
* Raw data sent by API
*/
// Links
export interface APIProviderRawDataLinks {
// Collections list
home?: string;
// Collection. Available variables: {prefix}
collection?: string;
// Icon. Available variables: {prefix}, {name}
icon?: string;
}
// NPM
export interface APIProviderRawDataNPM {
// Package name for installation. Available variables: {prefix}
package?: string;
// Icon import source. Available variables: {prefix}, {name}
icon?: string;
}
// Main type
export interface APIProviderRawData {
// Provider name (as used in icon names)
provider: string;
// Provider name (human readable version)
title?: string;
// API link(s), though they are usually redundant because API end point is used to retrieve data
api?: string | string[];
// Links to website
links?: APIProviderRawDataLinks;
// NPM packages for icons, used when showing code samples
npm?: APIProviderRawDataNPM;
// SVG generator URL, including full host name, {prefix} and {name} variables
// Example: 'https://api.iconify.design/{prefix}/{name}.svg'
svg?: string;
}

3
node_modules/@iconify/types/provider.js generated vendored Normal file
View file

@ -0,0 +1,3 @@
/**
* Empty file. This repository contains only TypeScript types
*/

272
node_modules/@iconify/types/types.d.ts generated vendored Normal file
View file

@ -0,0 +1,272 @@
/**
* Icon dimensions.
*
* Used in:
* icon (as is)
* alias (overwrite icon's properties)
* root of JSON file (default values)
*/
export interface IconifyDimenisons {
// Left position of viewBox.
// Defaults to 0.
left?: number;
// Top position of viewBox.
// Defaults to 0.
top?: number;
// Width of viewBox.
// Defaults to 16.
width?: number;
// Height of viewBox.
// Defaults to 16.
height?: number;
}
/**
* Icon transformations.
*
* Used in:
* icon (as is)
* alias (merged with icon's properties)
*/
export interface IconifyTransformations {
// Number of 90 degrees rotations.
// 0 = 0, 1 = 90deg and so on.
// Defaults to 0.
// When merged (such as alias + icon), result is icon.rotation + alias.rotation.
rotate?: number;
// Horizontal flip.
// Defaults to false.
// When merged, result is icon.hFlip !== alias.hFlip
hFlip?: boolean;
// Vertical flip. (see hFlip comments)
vFlip?: boolean;
}
/**
* Combination of dimensions and transformations.
*/
export interface IconifyOptional
extends IconifyDimenisons,
IconifyTransformations {
//
}
/**
* Alias.
*/
export interface IconifyAlias extends IconifyOptional {
// Parent icon index without prefix, required.
parent: string;
// IconifyOptional properties.
// Alias should have only properties that it overrides.
// Transformations are merged, not overridden. See IconifyTransformations comments.
}
/**
* Icon.
*/
export interface IconifyIcon extends IconifyOptional {
// Icon body: <path d="..." />, required.
body: string;
// IconifyOptional properties.
// If property is missing in JSON file, look in root object for default value.
}
/**
* Icon with optional parameters that are provided by API and affect only search
*/
interface APIIconAttributes {
// True if icon is hidden.
// Used in icon sets to keep icons that no longer exist, but should still be accessible
// from API, preventing websites from breaking when icon is removed by developer.
hidden?: boolean;
}
export interface ExtendedIconifyIcon extends IconifyIcon, APIIconAttributes {}
export interface ExtendedIconifyAlias extends IconifyAlias, APIIconAttributes {}
/**
* "icons" field of JSON file.
*/
export interface IconifyIcons {
// Index is name of icon, without prefix. Value is ExtendedIconifyIcon object.
[index: string]: ExtendedIconifyIcon;
}
/**
* "aliases" field of JSON file.
*/
export interface IconifyAliases {
// Index is name of icon, without prefix. Value is ExtendedIconifyAlias object.
[index: string]: ExtendedIconifyAlias;
}
/**
* Icon set information block.
*/
export interface IconifyInfo {
// Icon set name.
name: string;
// Total number of icons.
total?: number;
// Version string.
version?: string;
// Author information.
author: {
// Author name.
name: string;
// Link to author's website or icon set website.
url?: string;
};
// License
license: {
// Human readable license.
title: string;
// SPDX license identifier.
spdx?: string;
// License URL.
url?: string;
};
// Array of icons that should be used for samples in icon sets list.
samples?: string[];
// Icon grid: number or array of numbers.
height?: number | number[];
// Display height for samples: 16 - 24
displayHeight?: number;
// Category on Iconify collections list.
category?: string;
// List of tags to group similar icon sets.
tags?: string[];
// Palette status. True if icons have predefined color scheme, false if icons use currentColor.
// Ideally, icon set should not mix icons with and without palette to simplify search.
palette?: boolean;
// If true, icon set should not appear in icon sets list.
hidden?: boolean;
}
/**
* Optional themes, old format.
*
* Deprecated because format is unnecessary complicated. Key is meaningless, suffixes and prefixes are mixed together.
*/
export interface LegacyIconifyThemes {
// Key is unique string.
[index: string]: {
// Theme title.
title: string;
// Icon prefix or suffix, including dash. All icons that start with prefix and end with suffix belong to theme.
prefix?: string; // Example: 'baseline-'
suffix?: string; // Example: '-filled'
};
}
/**
* Characters used in font.
*/
export interface IconifyChars {
// Index is character, such as "f000".
// Value is icon name.
[index: string]: string;
}
/**
* Icon categories
*/
export interface IconifyCategories {
// Index is category title, such as "Weather".
// Value is array of icons that belong to that category.
// Each icon can belong to multiple categories or no categories.
[index: string]: string[];
}
/**
* Meta data stored in JSON file, used for browsing icon set.
*/
export interface IconifyMetaData {
// Icon set information block. Used for public icon sets, can be skipped for private icon sets.
info?: IconifyInfo;
// Characters used in font. Used for searching by character for icon sets imported from font, exporting icon set to font.
chars?: IconifyChars;
// Categories. Used for filtering icons.
categories?: IconifyCategories;
// Optional themes (old format).
themes?: LegacyIconifyThemes;
// Optional themes (new format). Key is prefix or suffix, value is title.
prefixes?: Record<string, string>;
suffixes?: Record<string, string>;
}
/**
* JSON structure, contains only icon data
*/
export interface IconifyJSONIconsData extends IconifyDimenisons {
// Prefix for icons in JSON file, required.
prefix: string;
// API provider, optional.
provider?: string;
// List of icons, required.
icons: IconifyIcons;
// Optional aliases.
aliases?: IconifyAliases;
// IconifyDimenisons properties that are used as default viewbox for icons when icon is missing value.
// If viewbox exists in both icon and root, use value from icon.
// This is used to reduce duplication.
}
/**
* JSON structure.
*
* All optional values can exist in root of JSON file, used as defaults.
*/
export interface IconifyJSON extends IconifyJSONIconsData, IconifyMetaData {
// Last modification time of icons. Unix time stamp in seconds.
// Time is calculated only for icon data, ignoring metadata.
// Used to invalidate icons cache in components.
lastModified?: number;
// Optional list of missing icons. Returned by Iconify API when querying for icons that do not exist.
not_found?: string[];
}
/**
* Structure of exports '@iconify-json/*' packages.
*
* These are small packages, one per icon set, that split JSON structure into multiple files to reduce
* amount of data imported from package.
*/
export interface IconifyJSONPackageExports {
info: IconifyInfo;
icons: IconifyJSON;
metadata: IconifyMetaData;
chars: IconifyChars;
}

3
node_modules/@iconify/types/types.js generated vendored Normal file
View file

@ -0,0 +1,3 @@
/**
* Empty file. This repository contains only TypeScript types
*/

View file

@ -9,6 +9,7 @@
"start": "NODE_ENV=production bun src/index.tsx"
},
"dependencies": {
"@iconify/react": "^6.0.0",
"@mui/icons-material": "^7.3.1",
"i18next": "^25.3.2",
"i18next-browser-languagedetector": "^8.2.0",

View file

@ -2,6 +2,8 @@ import { APITester } from "../APITester";
import "./index.css";
import { useTranslation, withTranslation, Trans } from 'react-i18next';
import AppBar from './modules/MenuBar';
import logo from "./logo.svg";
import reactLogo from "./react.svg";
@ -9,28 +11,18 @@ import Button from '@mui/material/Button';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import VehicleCard from "./modules/VehicleCards";
import YourVehicleList from "./modules/YourVehicles";
import MenuLanguages from "./modules/MenuLanguages";
import StatisticsView from "./modules/StatisticsView"
export function App() {
const { t, i18n } = useTranslation();
return (
<div className="app">
<div className="logo-container">
<img src={logo} alt="Bun Logo" className="logo bun-logo" />
<img src={reactLogo} alt="React Logo" className="logo react-logo" />
</div>
<h1>Bun + React | GarageApp</h1>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
<h1>{t ('statistics')}</h1>
<AppBar position="static">
</AppBar>
<StatisticsView />
<YourVehicleList></YourVehicleList>
<h1>test</h1>
</div>
);
}

View file

@ -15,7 +15,7 @@ i18n
backend: {
loadPath: '/GarageApp/locales/{{lng}}/{{ns}}.json'
},
lng: 'da',
lng: 'en',
ns: ['translation']
});

View file

@ -8,7 +8,7 @@
body {
margin: 0;
display: grid;
place-items: center;
place-items: stretch;
min-width: 320px;
min-height: 100vh;
position: relative;
@ -34,9 +34,7 @@ body::before {
}
}
.app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
position: relative;
z-index: 1;
@ -48,8 +46,20 @@ body::before {
gap: 2rem;
margin-bottom: 2rem;
}
.menu-logo-container {
display: flex;
justify-content: left;
align-items: center;
gap: 0.4em;
}
.menu-logo {
height: 2em;
padding: 1em
will-change: filter;
transition: filter 0.3s;
}
.logo {
height: 6em;
height: 2em;
padding: 1.5em;
will-change: filter;
transition: filter 0.3s;

View file

@ -0,0 +1,217 @@
{
"quickentry": "Keine Schnelleinträge | Schnelleintrag | Schnelleinträge",
"statistics": "Statistiken",
"thisweek": "Diese Woche",
"thismonth": "Dieser Monat",
"pastxdays": "Letzter Tag | Letzte {count} Tage",
"pastxmonths": "Letzter Monat | Letzte {count} Monate",
"thisyear": "Dieses Jahr",
"alltime": "Gesamt",
"noattachments": "Keine Anhänge",
"attachments": "Anhänge",
"choosefile": "Datei auswählen",
"addattachment": "Anhang hinzufügen",
"sharedwith": "Geteilt mit",
"share": "Teile",
"you": "du",
"addfillup": "Tankfüllung erfassen",
"createfillup": "Erfasse Tankfüllung",
"deletefillup": "Lösche diese Tankfüllung",
"addexpense": "Ausgabe erfassen",
"createexpense": "Erfasse Ausgabe",
"deleteexpense": "Lösche diese Ausgabe",
"nofillups": "Keine Tankfüllungen",
"transfervehicle": "Fahrzeug übertragen",
"settingssaved": "Einstellungen erfolgreich gespeichert",
"yoursettings": "Deine Einstellungen",
"settings": "Einstellungen",
"changepassword": "Passwort ändern",
"oldpassword": "Bisheriges Passwort",
"newpassword": "Neues Passwort",
"repeatnewpassword": "Neues Passwort wiederholen",
"passworddontmatch": "Passwörter stimmen nicht überein",
"save": "Speichern",
"supportthedeveloper": "Unterstütze den Entwickler",
"buyhimabeer": "Kauf ihm ein Bier!",
"moreinfo": "Mehr Info",
"currency": "Währung",
"distanceunit": "Entfernungseinheit",
"dateformat": "Datumsformat",
"createnow": "Jetzt erstellen",
"yourvehicles": "Deine Fahrzeuge",
"menu": {
"quickentries": "Schnellinträge",
"logout": "Abmelden",
"import": "Import",
"home": "Start",
"settings": "Einstellungen",
"admin": "Verwalten",
"sitesettings": "Globale Einstellungen",
"users": "Benutzer",
"login": "Anmelden"
},
"enterusername": "E-Mail eingeben",
"enterpassword": "Passwort eingeben",
"email": "E-Mail",
"password": "Passwort",
"login": "Anmelden",
"totalexpenses": "Gesamtausgaben",
"fillupcost": "Tank-Ausgaben",
"otherexpenses": "Andere Ausgaben",
"addvehicle": "Fahrzeug hinzufügen",
"editvehicle": "Fahrzeug bearbeiten",
"deletevehicle": "Fahrzeug löschen",
"sharevehicle": "Fahrzeug teilen",
"makeowner": "zum Besitzer machen",
"lastfillup": "Letztes Tanken",
"quickentrydesc": "Mach ein Foto deiner Rechnung oder der Zapfsäule um den Eintrag später zu ergänzen.",
"quickentrycreatedsuccessfully": "Schnelleintrag erfolgreich erstellt",
"uploadfile": "Datei hochladen",
"uploadphoto": "Foto hochladen",
"details": "Details",
"odometer": "Kilometerzähler",
"language": "Sprache",
"date": "Datum",
"pastfillups": "Tankfüllungen",
"fuelsubtype": "Kraftstofftyp",
"fueltype": "Kraftstoff",
"quantity": "Menge",
"gasstation": "Tankstelle",
"fuel": {
"petrol": "Benzin",
"diesel": "Diesel",
"cng": "CNG",
"lpg": "LPG",
"electric": "Strom",
"ethanol": "Ethanol"
},
"unit": {
"long": {
"litre": "Liter",
"gallon": "Gallone",
"kilowatthour": "Kilowattstunde",
"kilogram": "Kilogramm",
"usgallon": "US-Gallone",
"minutes": "Minuten",
"kilometers": "Kilometer",
"miles": "Meilen"
},
"short": {
"litre": "L",
"gallon": "Gal",
"kilowatthour": "KwH",
"kilogram": "Kg",
"usgallon": "US-Gal",
"minutes": "Min",
"kilometers": "Km",
"miles": "Mi"
}
},
"avgfillupqty": "Ø Tankmenge",
"avgfillupexpense": "Ø Tankwert",
"avgfuelcost": "Ø Spritpreis",
"per": "{0} pro {1}",
"price": "Preis",
"total": "Gesamt",
"fulltank": "Voller Tank",
"getafulltank": "Hast du vollgetankt?",
"by": "Von",
"expenses": "Ausgaben",
"expensetype": "Ausgaben Typ",
"noexpenses": "Keine Ausgaben",
"download": "Herunterladen",
"title": "Titel",
"name": "Name",
"delete": "Löschen",
"importdata": "Importiere Daten in Hammond",
"importdatadesc": "Wähle eine der folgenden Optionen, um Daten in Hammond zu importieren",
"import": "Importieren",
"importcsv": "Wenn du {name} nutzt, um deine Fahrzeugdaten zu verwalten, exportiere die CSV Datei aus {name} und klicke hier, um zu importieren.",
"choosecsv": "CSV auswählen",
"choosephoto": "Foto auswählen",
"importsuccessfull": "Daten erfolgreich importiert",
"importerror": "Beim Importieren der Datei ist ein Fehler aufgetreten. Details findest du in der Fehlermeldung",
"importfrom": "Importiere von {name}",
"stepstoimport": "Schritte, um Daten aus {name} zu importieren",
"choosecsvimport": "Wähle die {name} CSV aus und klicke den Button, um zu importieren.",
"dontimportagain": "Achte darauf, dass du die Datei nicht erneut importierst, da dies zu mehrfachen Einträgen führen würde.",
"checkpointsimportcsv": "Wenn du alle diese Punkte überprüft hast kannst du unten die CSV importieren.",
"importhintunits": "Vergewissere dich ebenfalls, dass die <u>Kraftstoffeinheit</u> und der <u>Kraftstofftyp</u> im Fahrzeug richtig eingestellt sind.",
"importhintcurrdist": "Stelle sicher, dass die <u>Währung</u> und die <u>Entfernungseinheit</u> in Hammond korrekt eingestellt sind. Der Import erkennt die Währung nicht automatisch aus der datei, sondern verwendet die für den Benutzer eingestellte Währung.",
"importhintnickname": "Vergewissere dich, dass der Fahrzeugname in Hammond genau mit dem Namen in der Fuelly-CSV-Datei übereinstimmt, sonst funktioniert der Import nicht.",
"importhintvehiclecreated": "Vergewissere dich, dass du die Fahrzeuge bereits in Hammond erstellt hast.",
"importhintcreatecsv": "Exportiere deine Daten aus {name} im CSV-Format. Die Schritte dazu findest du",
"here": "hier",
"unprocessedquickentries": "Du hast einen Schnelleintrag zum bearbeiten. | Du hast {0} Schnelleinträge zum bearbeiten.",
"show": "Anzeigen",
"loginerror": "Bei der Anmeldung ist ein Fehler aufgetreten. {msg}",
"showunprocessed": "Zeige unbearbeitete",
"unprocessed": "unbearbeitet",
"sitesettingdesc": "Ändere die globalen Einstellungen. Diese werden als Standard für neue Benutzer verwendet.",
"settingdesc": "Diese Einstellungen werden als Standard verwendet wenn du eine neue Ausgabe oder eine Tankfüllung erfasst.",
"areyousure": "Bist du dir sicher?",
"adduser": "Benutzer hinzufügen",
"usercreatedsuccessfully": "Benutzer erfolgreich gespeichert",
"role": "Rolle",
"created": "Erstellt",
"createnewuser": "Erstelle neuen Benutzer",
"cancel": "Abbrechen",
"novehicles": "Du hast noch kein Fahrzeug erstellt. Lege jetzt einen Eintrag für das zu verwaltende Fahrzeug an.",
"processed": "Bearbeitet",
"notfound": "Nicht gefunden",
"timeout": "Das Laden der Seite hat eine Zeitüberschreitung verursacht. Bist du sicher, dass du noch mit dem Internet verbunden bist?",
"clicktoselect": "Klicke, um auszuwählen...",
"expenseby": "Ausgabe von",
"selectvehicle": "Wähle ein Fahrzeug aus",
"expensedate": "Datum der Ausgabe",
"totalamountpaid": "Gezahlter Gesamtbetrag",
"fillmoredetails": "Weitere Details ausfüllen",
"markquickentryprocessed": "Markiere gewählten Schnelleintrag als bearbeitet",
"referquickentry": "Wähle Schnelleintrag",
"deletequickentry": "Willst du diesen Schnelleintrag wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden!",
"fuelunit": "Kraftstoffeinheit",
"fillingstation": "Tankstelle",
"comments": "Kommentare",
"missfillupbefore": "Hast du vergessen, die vorherige Tankfüllung zu erfassen?",
"fillupdate": "Tankdatum",
"fillupsavedsuccessfully": "Tankfüllung erfolgreich gespeichert",
"expensesavedsuccessfully": "Ausgabe erfolgreich gespeichert",
"vehiclesavedsuccessfully": "Fahrzeug erfolgreich gespeichert",
"back": "Zurück",
"nickname": "Bezeichnung",
"registration": "Nummernschild",
"createvehicle": "Fahrzeug erstellen",
"make": "Marke",
"model": "Modell",
"yearmanufacture": "Jahr der Erstzulassung",
"enginesize": "Hubraum (in ccm)",
"testconn": "Teste Verbindung",
"migrate": "Migrieren",
"init": {
"migrateclarkson": "Migriere von Clarkson",
"migrateclarksondesc": "Wenn du bereits eine Instanz von Clarkson verwendest und die Daten migrieren möchtest, klicke hier.",
"freshinstall": "Frische Installation",
"freshinstalldesc": "Wenn du eine neue Installation von Hammond starten möchtest, klicke hier.",
"clarkson": {
"desc": "<p>Zuerst musst du sicherstellen, dass das Deployment von Hammond die von Clarkson verwendete MySQL Datenbank erreichen kann.</p><p>Wenn dies nicht möglich ist kannst du eine Kopie erstellen die für Hammond erreichbar ist.</p><p>Wenn das erledigt ist, füge hier den Connection String im folgenden Format ein.</p><p>Alle aus Clarkson importierten Nutzer bekommen ihren Benutzernamen als E-Mail und das Passwort wird geändert zu <span class='' style='font-weight:bold'>hammond</span></p><code>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
"success": "Deine Daten wurden erfolgreich von Clarkson migriert. Du wirst in kürze zur Anmeldung weitergeleitet wo du dich mit deiner E-Mail und dem passwort `hammond` anmelden kannst."
},
"fresh": {
"setupadminuser": "Erstelle einen Administrator",
"yourpassword": "Dein Passwort",
"youremail": "Deine E-Mail-Adresse",
"yourname": "Dein Name",
"success": "Du hast dich erfolgreich registriert. Du wirst in kürze zur Anmeldung weitergeleitet und kannst Anfangen Hammond zu verwenden."
}
},
"roles": {
"ADMIN": "Adminstrator",
"USER": "Benutzer"
},
"profile": "Profil",
"processedon": "Bearbeitet am",
"enable": "Entsperren",
"disable": "Sperren",
"confirm": "Bestätigen",
"labelforfile": "Bezeichnung für diese Datei"
}

View file

@ -0,0 +1,231 @@
{
"quickentry": "Pas d'entrée rapide | Entrée rapide | Entrées rapides",
"statistics": "Statistiques",
"thisweek": "Cette semaine",
"thismonth": "Ce mois",
"pastxdays": "Dernier jour | Derniers {count} jours",
"pastxmonths": "Dernier mois | Derniers {count} mois",
"thisyear": "Cette année",
"alltime": "Tout le temps",
"noattachments": "Pas de piece jointe",
"attachments": "Pièces jointes",
"choosefile": "Choose File",
"addattachment": "Ajouter une pièce jointe",
"sharedwith": "Partager avec",
"share": "Partager",
"you": "Vous",
"addfillup": "Ajouter un plein",
"createfillup": "Créer un plein",
"deletefillup": "Supprimer ce plein",
"addexpense": "Ajouter une dépense",
"createexpense": "Créer une dépense",
"deleteexpense": "Supprimer cette dépense",
"nofillups": "Pas de plein",
"transfervehicle": "Transferer le Véhicule",
"settingssaved": "Paramètres sauvegardés avec succès",
"yoursettings": "Vos paramètres",
"settings": "Paramètres",
"changepassword": "Changer votre mot de passe",
"oldpassword": "Ancien mot de passe",
"newpassword": "Nouveau mot de passe",
"repeatnewpassword": "Répéter votre nouveau mot de passe",
"passworddontmatch": "Les mots de passe ne correspondent pas",
"save": "Sauvegarder",
"supportthedeveloper": "Supporter le développeur",
"buyhimabeer": "Acheter lui un café!",
"featurerequest": "Demande de fonctionnalité",
"foundabug": "Trouvé un bug",
"currentversion": "Version actuelle",
"moreinfo": "Plus d'informations",
"currency": "Monnaie",
"distanceunit": "Unité de distance",
"dateformat": "Format de data",
"createnow": "Créer Maintenant",
"yourvehicles": "Vos Véhicules",
"menu": {
"quickentries": "Entrée rapide",
"logout": "Se déconnecter",
"import": "Importer",
"home": "Accueil",
"settings": "Paramètres",
"admin": "Admin",
"sitesettings": "Paramètres du site",
"users": "Utilisateurs",
"login": "Connexion"
},
"enterusername": "Entrez votre nom d'utilisateur",
"enterpassword": "Entrez votre mot de passe",
"email": "Email",
"password": "Mot de passe",
"login": "connexion",
"totalexpenses": "Dépenses totales",
"fillupcost": "Coût des pleins",
"otherexpenses": "Autres dépenses",
"addvehicle": "Ajouter un Véhicule",
"editvehicle": "Editer un Véhicule",
"deletevehicle": "Supprimer un Véhicule",
"sharevehicle": "Partager un Véhicule",
"makeowner": "Changer le propriétaire",
"lastfillup": "Dernier plein",
"quickentrydesc": "Prendre une photo de la facture ou de l'écran de la pompe à essence pour créer une entrée plus tard.",
"quickentrycreatedsuccessfully": "Entrée rapide créée avec succès",
"uploadfile": "Téléverser un fichier",
"uploadphoto": "Téléverser une photo",
"details": "Détails",
"odometer": "Odomètre",
"language": "Langue",
"date": "Date",
"pastfillups": "Derniers pleins",
"fuelsubtype": "Sous-type de combustible",
"fueltype": "Type de combustible",
"quantity": "Quantité",
"gasstation": "Station service",
"fuel": {
"petrol": "Pétrol",
"diesel": "Diesel",
"cng": "CNG",
"lpg": "LPG",
"electric": "Electrique",
"ethanol": "Éthanol"
},
"unit": {
"long": {
"litre": "Litre",
"gallon": "Gallon",
"kilowatthour": "Kilowatt Heure",
"kilogram": "Kilogram",
"usgallon": "US Gallon",
"minutes": "Minutes",
"kilometers": "Kilometres",
"miles": "Miles"
},
"short": {
"litre": "Lt",
"gallon": "Gal",
"kilowatthour": "KwH",
"kilogram": "Kg",
"usgallon": "US Gal",
"minutes": "Mins",
"kilometers": "Km",
"miles": "Mi"
}
},
"avgfillupqty": "Qté de plein moyen",
"avgfillupexpense": "Prix du plein moyen",
"avgfuelcost": "Prix de l'essence moyen",
"per": "{0} par {1}",
"price": "Prix",
"total": "Total",
"fulltank": "Reservoir complet",
"partialfillup": "Plein partiel",
"getafulltank": "Est-ce que vous avez rempli tout votre reservoir?",
"tankpartialfull": "Le quel traquez-vous?",
"by": "Par",
"expenses": "Dépenses",
"expensetype": "Type de dépense",
"noexpenses": "Pas de dépense",
"download": "Télécharger",
"title": "Titre",
"name": "Nom",
"delete": "Supprimer",
"importdata": "Importer des données dans Hammond",
"importdatadesc": "Choisissez une option pour importer des données dans Hammond",
"import": "Importer",
"importcsv": "Si vous utilisiez {name} pour stocker les données de vos véhicules, exportez les données en format CSV depuis {name} et cliquez ici pour importer.",
"importgeneric": "Importation de plein générique",
"importgenericdesc": "Importation de plein avec un SVC.",
"choosecsv": "Choisir un CSV",
"choosephoto": "Choisir une Photo",
"importsuccessfull": "Données importée avec succès",
"importerror": "Il y a eu un problème lors de l'importation. Veuillez regarder le message d'erreur",
"importfrom": "Importer depuis {0}",
"stepstoimport": "Étapes pour importer des données depuis {name}",
"choosecsvimport": "Choisissez le fichier CSV de {name} et appuyez sur le bouton pour importer.",
"choosedatafile": "Choisissez le fichier CSV et appuyez sur le bouton pour importer.",
"dontimportagain": "Faites attention à ne pas importer le fichier à nouveau car cela va créer des entrées dupliquées.",
"checkpointsimportcsv": "Dès que vous avez vérifié tous ces points, importez le CSV ci-dessous.",
"importhintunits": "De la même manière, make sure that the <u>Fuel Unit</u> and <u>Fuel Type</u> are correctly set in the Vehicle.",
"importhintcurrdist": "Soyez sûre que la <u>Monnaie</u> et l'<u>Unité de distance</u> sont mises correctement dans Hammond. L'importation ne detectera pas automatiquement la Monnaie du fichier mais utilisera les valeurs de l'utilisateur.",
"importhintnickname": "Soyez sûre que le nom du véhicule dans Hammon est exactement le même que le nom dans Fuelly, sinon, l'importation ne fonctionnera pas.",
"importhintvehiclecreated": "Soyez sûre d'avoir déjà créé le véhicule dans la plate-forme Hammond.",
"importhintcreatecsv": "Exportez vos données depuis {name} en format CSV. Les étapes pour faire ceci peuvent être trouvées",
"importgenerichintdata": "Les données doivent être au format CSV.",
"here": "ici",
"unprocessedquickentries": "Vous avez 1 entrée rapide en attente d'être traîtée. | Vous avez {0} entrée rapide en attente d'être traîtée.",
"show": "montrer",
"loginerror": "Il y a eu une erreur lors de la connexion a votre compte: {msg}",
"showunprocessed": "Montrer seulement les non-traîtées",
"unprocessed": "non-traîtée",
"sitesettingdesc": "Mettre à jour les paramètres du site. Ces valeurs seront utilisées par défaut pour les nouveaux utilisateurs.",
"settingdesc": "Ces valeurs seront utilisées par défaut lorsque vous créez un nouveau plein ou une nouvelle dépense.",
"areyousure": "Êtes-vous sûre de vouloir faire ceci?",
"adduser": "Ajouter un utilisateur",
"usercreatedsuccessfully": "Utilisateur créé avec succès",
"userdisabledsuccessfully": "Utilisateur désactivé avec succès",
"userenabledsuccessfully": "Utilisateur activé avec succès",
"role": "Rôle",
"created": "Créé",
"createnewuser": "Créer un nouvel utilisateur",
"cancel": "Annuler",
"novehicles": "Il semble que vous n'avez pas encore créé de véhicule dans le système pour le moment. Commencez par créer une entrée pour un des véhicule que vous voulez traquer.",
"processed": "Marquer en tant que traîté",
"notfound": "Non Trouvé",
"timeout": "La page a expiré lors du chargement. Êtes-vous sûre d'être toujours connecté à Internet?",
"clicktoselect": "Cliquer pour sélectionner...",
"expenseby": "Dépense par",
"selectvehicle": "Selectionner un véhicule",
"expensedate": "Date de la dépense",
"totalamountpaid": "Montant payé total",
"fillmoredetails": "Entrer plus de détails",
"markquickentryprocessed": "Marquer l'entrée rapide séléctionnée en tant que traîtée",
"referquickentry": "Faire référence à une entrée rapide",
"deletequickentry": "Ceci va supprimer l'entrée rapide. Cette action ne peut pas être annulée. Êtes-vous sûre?",
"fuelunit": "Unité de combustible",
"fillingstation": "Nom de la station service",
"comments": "Commentaires",
"missfillupbefore": "Est-ce que vous avez manqué un plein avant celui-ci?",
"missedfillup": "Plein manqué",
"fillupdate": "Date du plein",
"fillupsavedsuccessfully": "Plein sauvegardé avec succès",
"expensesavedsuccessfully": "Dépense sauvegardé avec succès",
"vehiclesavedsuccessfully": "Véhicule sauvegardé avec succès",
"settingssavedsuccessfully": "Paramètres sauvegardés avec succès",
"back": "Retour",
"nickname": "Surnom",
"registration": "Immatriculation",
"createvehicle": "Créer un Véhicule",
"make": "Marque",
"model": "Modèle",
"yearmanufacture": "Année de production",
"enginesize": "Taille du moteur (en chevaux)",
"mysqlconnstr": "Chaîne de caractère pour la connexion MySQL",
"testconn": "Tester la Connexion",
"migrate": "Migrer",
"init": {
"migrateclarkson": "Migrer depuis Clarkson",
"migrateclarksondesc": "Si vous avez un déploiement Clarkson existant et que vous souhaitez migrer vos données à partir de celui-ci, appuyez sur le bouton suivant.",
"freshinstall": "Nouvelle Installation",
"freshinstalldesc": "Si vous voulez une nouvelle installation de Hammond, appuyez sur le bouton suivant.",
"clarkson": {
"desc": "<p>Vous devez vous assurer que ce déploiement de Hammond peut accéder à la base de données MySQL utilisée par Clarkson.</p><p>Si ce n'est pas directement possible, vous pouvez faire une copie de cette base de données autre part qui est accessible à partir de cette instance.</p><p>Une fois cela fait, entrez la chaîne de connexion à l'instance MySQL au format suivant.</p><p>Tous les utilisateurs importés de Clarkson auront leur nom d'utilisateur comme e-mail dans la base de données Clarkson et le mot de passe défini sur <span class='' style='font-weight:bold'>hammond</span></p><code>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
"success": "Nous avons migré avec succès les données depuis Clarkson. Vous serez bientôt redirigé vers l'écran de connexion où vous pourrez vous connecter en utilisant votre adresse e-mail et votre mot de passe existants : hammond"
},
"fresh": {
"setupadminuser": "Configurer le compte administrateur",
"yourpassword": "Votre Mot de passe",
"youremail": "Votre Email",
"yourname": "Votre Nom",
"success": "Vous avez été inscrit avec succès. Vous allez être redirigé vers la page de connexion très bientôt, vous pourrez vous connecter et commencer à utiliser le système."
}
},
"roles": {
"ADMIN": "ADMIN",
"USER": "USER"
},
"profile": "Profile",
"processedon": "Traîté le",
"enable": "Activer",
"disable": "Désactiver",
"confirm": "Continuer",
"labelforfile": "Label pour ce fichier"
}

View file

@ -0,0 +1,231 @@
{
"quickentry": "Nincs gyors bejegyzés | Gyors bejegyzés | Gyors bejegyzések",
"statistics": "Statisztikák",
"thisweek": "Ez a hét",
"thismonth": "Ez a hónap",
"pastxdays": "Elmúlt 1 nap | Elmúlt {count} nap",
"pastxmonths": "Elmúlt 1 hónap | Past {count} hónap",
"thisyear": "Ez az év",
"alltime": "Összes",
"noattachments": "Nincs csatolmány eddig",
"attachments": "Csatolmányok",
"choosefile": "Válassz fájlt",
"addattachment": "Csatolmány hozzáadása",
"sharedwith": "Megosztva vele",
"share": "Megosztás",
"you": "Te",
"addfillup": "Tankolás hozzáadása",
"createfillup": "Tankolás létrehozása",
"deletefillup": "Tankolás törlése",
"addexpense": "Kiadás hozzáadása",
"createexpense": "Kiadás létrehozása",
"deleteexpense": "Kiads törlése",
"nofillups": "Nincs tankolás eddig",
"transfervehicle": "Jármű átruházása",
"settingssaved": "Beállítások sikeresen mentve",
"yoursettings": "Beállításaid",
"settings": "Beállítások",
"changepassword": "Jelszó megváltoztatása",
"oldpassword": "Régi jelszó",
"newpassword": "Új jelszó",
"repeatnewpassword": "Jelszó mégegyszer",
"passworddontmatch": "Jelszavak nem egyeznek",
"save": "Mentés",
"supportthedeveloper": "Támogsad a fejlesztőt",
"buyhimabeer": "Vegyél neki egy sört!",
"featurerequest": "Funkció kérése",
"foundabug": "Hibát találtam",
"currentversion": "Aktuális verzió",
"moreinfo": "Több információ",
"currency": "Pénznem",
"distanceunit": "Távolság mértékegysége",
"dateformat": "Dátum formátuma",
"createnow": "Létrehozás most",
"yourvehicles": "Járműveid",
"menu": {
"quickentries": "Gyors bejegyzések",
"logout": "Kijelentkezés",
"import": "Betöltés",
"home": "Kezdőlap",
"settings": "Beállítások",
"admin": "Adminisztrátor",
"sitesettings": "Oldal beállításai",
"users": "Felhasználók",
"login": "Bejelentkezés"
},
"enterusername": "Írd be a felhasználó neved",
"enterpassword": "Írd be a jelszavad",
"email": "Email",
"password": "Jelszó",
"login": "bejelentkezés",
"totalexpenses": "Összeskiadás",
"fillupcost": "Tankolás költsége",
"otherexpenses": "Egyéb kiadás",
"addvehicle": "Jármű hozzáadása",
"editvehicle": "Jármű szerkesztése",
"deletevehicle": "Jármű törlése",
"sharevehicle": "Jármű megosztása",
"makeowner": "Tulajdonosnak jelölés",
"lastfillup": "Utolsó tankolás",
"quickentrydesc": "Csinálj képet a blokkról/számláról vagy a tankoló mérőóráról hogy fel tudd vinni később az adatokat.",
"quickentrycreatedsuccessfully": "Gyors bejegyzés sikeresen létrehozva",
"uploadfile": "Fájl feltöltése",
"uploadphoto": "Fotó feltöltése",
"details": "Részletek",
"odometer": "Kilóméter óra",
"language": "Nyelv",
"date": "Dátum",
"pastfillups": "Előző tankolások",
"fuelsubtype": "Üzemanyag altípus",
"fueltype": "Üzemanyag típus",
"quantity": "Mennyiség",
"gasstation": "Benzinkút",
"fuel": {
"petrol": "Benzin",
"diesel": "Dízel",
"cng": "CNG",
"lpg": "LPG",
"electric": "Elektromos",
"ethanol": "Etanol"
},
"unit": {
"long": {
"litre": "Liter",
"gallon": "Gallon",
"kilowatthour": "Kilowattóra",
"kilogram": "Kilogram",
"usgallon": "US Gallon",
"minutes": "Perc",
"kilometers": "Kilóméter",
"miles": "Mérföld"
},
"short": {
"litre": "L",
"gallon": "Gal",
"kilowatthour": "KwH",
"kilogram": "Kg",
"usgallon": "US Gal",
"minutes": "P",
"kilometers": "Km",
"miles": "Mérf"
}
},
"avgfillupqty": "Átl. tankolási menny.",
"avgfillupexpense": "Átl. tankolási kiadás",
"avgfuelcost": "Átl. üzemanyag ár",
"per": "{0} per {1}",
"price": "Ár",
"total": "Összesen",
"fulltank": "Tele tank",
"partialfillup": "Részleges tankolás",
"getafulltank": "Teletankoltál?",
"tankpartialfull": "Which do you track?",
"by": "által",
"expenses": "Kiadások",
"expensetype": "Kiadás típusa",
"noexpenses": "Nincs kiadás eddig",
"download": "Letöltés",
"title": "Címe",
"name": "Neve",
"delete": "Törlés",
"importdata": "Adata betöltésa Hammondba",
"importdatadesc": "Válassz az alábbi lehetőségek közül, hogy betöltsd az adatokat",
"import": "Betöltés",
"importcsv": "Ha már használtad {name}-t hogy tárold a jármű adatait, exportáld CSV-be {name}-ból/ből majd kattints it a Betöltésre.",
"importgeneric": "Általános tanoklások betöltése",
"importgenericdesc": "Tankolás CSV betöltés.",
"choosecsv": "CSV választása",
"choosephoto": "Fotó választása",
"importsuccessfull": "Adat sikeresen betöltve",
"importerror": "Betöltés közben hiba lépett fel. Kérem ellenőrizze a hibaüzenetet.",
"importfrom": "Betöltés innen: {0}",
"stepstoimport": "Lépések az adat betöltéséhez {name}-ból/ből",
"choosecsvimport": "Válassza a/az {name} CSV-t és nyomja meg a betöltés gombot.",
"choosedatafile": "Válassza a CSV fájlt majd nyomja meg az importálás gombot.",
"dontimportagain": "Legyen biztos benne, hogy nem importálja újra ugyan azt a fájlt. Dublikált bejegyzéseket eredményez.",
"checkpointsimportcsv": "Amikor végzett az összes ponttal, töltse be a CSV-t lejjebb.",
"importhintunits": "Hasonlóan, legyen biztos benne, hogy az <u>Üzemanyag egysége</u> és az <u>Üzemanyag Típúsa</u> helyesek a Jármű beállításaiban.",
"importhintcurrdist": "Ellenőrizze, hogy a <u>Pénznem</u> és a <u>Távolság mértékegysége</u> be lettek állítva a Hammond-ban. A betöltés automatikusan nem ismeri fel a bejegyzések Pénznemét, helyette a felhaszáló alapértlemzett beállítása lesz alkalmazva.",
"importhintnickname": "Ellenőrizze, hogy a Jármű neve Hammond-ban megegyezik a Fuelly CSV-ben használttal vagy a betöltés nem fog működni.",
"importhintvehiclecreated": "Ellenőrizze, hogy a Járművek már léteznek a Hammond rendszerében.",
"importhintcreatecsv": "Mentse adatát {name}-ból/ből CSV formátumba. Steps to do that can be found",
"importgenerichintdata": "Az adatnak CSV formátumban kell lennie.",
"here": "itt",
"unprocessedquickentries": "Egy gyors bejegyzés feldolgozva. | {0} gyorsbejegyzés vár feldolgozásra.",
"show": "Mutasd",
"loginerror": "Hiba történt a bejelentkezés során. {msg}",
"showunprocessed": "Csak nem feldolgozottak",
"unprocessed": "feldolgozatlan",
"sitesettingdesc": "Oldal beállításainak módosítása. Ezek lesznek használva új felhazsnálók létrehozásakor.",
"settingdesc": "Ezek lesznak alkalmazva alapértelmezett értékként, tankolásnál vagy kiadásnál.",
"areyousure": "Biztos hogy ezt akarja?",
"adduser": "Felhasználó hozzáadása",
"usercreatedsuccessfully": "Felhasználó sikeresen létrehozva",
"userdisabledsuccessfully": "Felhasználó sikeresen letiltva",
"userenabledsuccessfully": "Felhasználó sikeresen engedélyezve",
"role": "Szerepkör",
"created": "Létrehozva",
"createnewuser": "Új felhasználó létrehozása",
"cancel": "Mégsem",
"novehicles": "Eddig nem hozott létre járművet a rendszerében. Hozzon létre egyet amelynek adatait követni szeretné.",
"processed": "Megjelölés feldolgozottnak",
"notfound": "Nem talált",
"timeout": "A lap túl sokáig nem töltött be. Biztos benne, hogy még mindig van \ninternet elérése?",
"clicktoselect": "Válasszon...",
"expenseby": "Kiadások ez szerint",
"selectvehicle": "Válassz járművet",
"expensedate": "Kiadás dátuma",
"totalamountpaid": "Összes kifizetés",
"fillmoredetails": "Több részlet kitöltése",
"markquickentryprocessed": "Kiválasztott gyorsbejegyzések megjelölése feldolgozottként",
"referquickentry": "Gzorsbejegzy;s referencia",
"deletequickentry": "Ez kitörli ezt a gyorsbejegyzést. Ez a lépés visszafordíthatatlan. Biztos benne?",
"fuelunit": "Üzemenyag egység",
"fillingstation": "Benzinkút neve",
"comments": "Komment",
"missfillupbefore": "Nem töltötte ki az előző tankolást?",
"missedfillup": "Kihagyott tankolás",
"fillupdate": "Tankolás dátuma",
"fillupsavedsuccessfully": "Tankolás sikeresen mentve",
"expensesavedsuccessfully": "Kiadás sikeresen mentve",
"vehiclesavedsuccessfully": "Jármű sikeresen mentve",
"settingssavedsuccessfully": "Beállítások sikeresen mentve",
"back": "Vissza",
"nickname": "Becenév",
"registration": "Rendszám",
"createvehicle": "Jármű létrehozása",
"make": "Gyártó",
"model": "Model",
"yearmanufacture": "Gyártás éve",
"enginesize": "Motorméret (cm3)",
"mysqlconnstr": "Mysql Connection String",
"testconn": "Kapcsolat tesztelése",
"migrate": "Migrálás",
"init": {
"migrateclarkson": "Migrálás Clarkson-ból",
"migrateclarksondesc": "Ha van egy meglévő Clarkson telepítése, és szeretné adatait átmozgatni onnan, nyomja meg a következő gombot.",
"freshinstall": "Tiszta telepítés",
"freshinstalldesc": "Ha szeretné a Hammond tiszta telepítését, nyomja meg a következő gombot.",
"clarkson": {
"desc": "<p>Biztosítania kell, hogy ez a Hammond telepítés el tudja érni a Clarkson által készített MySQL adatbázist.</p><p>Ha ez nem megoldható, készíthet egy másolatot az adatbázisról, és elhelyzheti olyan helyre amely elérhető innen.</p><p>Amikor ezzel kész van, Állítsa me a connection String-et a MySQL-hez a következő formátumban.</p><p>Az összes Clarkson-ból migrált felhasználónak az e-mail címük lesz a felhasználó nevük, és a jelszavuk <span class='' style='font-weight:bold'>hammond</span> lesz</p><code>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
"success": "Sikeresen migráltuk az adatot Clarkson-ból. Hamarosan át lesz irányítva a bejelentkezési oldalra, ahol használhatja a meglévő fiókját, és jelszavát: hammond"
},
"fresh": {
"setupadminuser": "Adminisztrátor felhasználó beállítása",
"yourpassword": "Ön jelszava",
"youremail": "Ön e-mailcíme",
"yourname": "Ön neve",
"success": "Ön sikeresen regisztrált. Át lesz irányítva a bejelentkezési képernyőre, ahol be tud jelentkezni és elkezdheti használni a rendszert."
}
},
"roles": {
"ADMIN": "ADMIN",
"USER": "FELHASZNÁLÓ"
},
"profile": "Profil",
"processedon": "Felfdolgozva ekkor",
"enable": "Engedélyezve",
"disable": "Letiltva",
"confirm": "Megerősítés",
"labelforfile": "Címke ehheza fájlhoz"
}

View file

@ -1,7 +1,10 @@
export const LANGUAGES = [
{ label: "Spanish", code: "es" },
{ label: "English", code: "en" },
{ label: "Italian", code: "it" },
{ label: "Danish", code: "da" },
{ label: "english | english", code: "en" },
{ label: "danish | dansk", code: "da" },
{ label: "german | deutch", code: "de" },
{ label: "frensh | français", code: "fr" },
{ label: "hungarian | magyar", code: "hu" },
{ label: "slovenian | slovenski", code: "sl" },
{ label: "Chinese (simplified) | 简体中文", code: "zh" },
];

View file

@ -0,0 +1,231 @@
{
"quickentry": "Ni hitrih vnosov | Hiter vnos | Hitri vnosi",
"statistics": "Statistika",
"thisweek": "Ta teden",
"thismonth": "Ta mesec",
"pastxdays": "Zadnji dan | Zadnjih {count} dni",
"pastxmonths": "Zadnji mesec | Zadnji {count} mesecev",
"thisyear": "To leto",
"alltime": "Celoten čas",
"noattachments": "Zaenkrat še ni priponk",
"attachments": "Priloge",
"choosefile": "Izberi datoteko",
"addattachment": "Dodaj prilogo",
"sharedwith": "V skupni rabi z",
"share": "Deli",
"you": "Ti",
"addfillup": "Dodaj polnjenje",
"createfillup": "Ustvarite polnjenje",
"deletefillup": "Izbriši to polnjenje",
"addexpense": "Dodaj strošek",
"createexpense": "Ustvari strošek",
"deleteexpense": "Izbriši ta strošek",
"nofillups": "Zaenkrat še brez polnjenja",
"transfervehicle": "Prevozno sredstvo",
"settingssaved": "Nastavitve so uspešno shranjene",
"yoursettings": "Vaše nastavitve",
"settings": "Nastavitve",
"changepassword": "Spremeni geslo",
"oldpassword": "Staro geslo",
"newpassword": "Novo geslo",
"repeatnewpassword": "Ponovite novo geslo",
"passworddontmatch": "Vrednosti gesel se ne ujemajo",
"save": "Shrani",
"supportthedeveloper": "Podprite razvijalca",
"buyhimabeer": "Kupi mu pivo!",
"featurerequest": "Nova funkcionalnost",
"foundabug": "Našel sem hrošča",
"currentversion": "Trenutna verzija",
"moreinfo": "Več informacij",
"currency": "Valuta",
"distanceunit": "Enota razdalje",
"dateformat": "Format datuma",
"createnow": "Ustvari zdaj",
"yourvehicles": "Vaša vozila",
"menu": {
"quickentries": "Hitri vnosi",
"logout": "Odjava",
"import": "Uvoz",
"home": "Domov",
"settings": "Nastavitve",
"admin": "Skrbnik",
"sitesettings": "Nastavitve spletnega mesta",
"users": "Uporabniki",
"login": "Vpiši se"
},
"enterusername": "Vnesite svoje uporabniško ime",
"enterpassword": "Vnesite vaše geslo",
"email": "E-naslov",
"password": "Geslo",
"login": "Vpiši se",
"totalexpenses": "Skupni stroški",
"fillupcost": "Stroški polnjenja",
"otherexpenses": "Drugi stroški",
"addvehicle": "Dodaj vozilo",
"editvehicle": "Uredi vozilo",
"deletevehicle": "Izbriši vozilo",
"sharevehicle": "Deli vozilo",
"makeowner": "Postani lastnik",
"lastfillup": "Zadnje polnjenje",
"quickentrydesc": "Posnemite sliko računa ali zaslona črpalke za gorivo, da ju lahko vnesete pozneje.",
"quickentrycreatedsuccessfully": "Hitri vnos je bil uspešno ustvarjen",
"uploadfile": "Naloži datoteko",
"uploadphoto": "Naloži fotografijo",
"details": "Podrobnosti",
"odometer": "Odometer",
"language": "Jezik",
"date": "Datum",
"pastfillups": "Prejšnja polnjenja",
"fuelsubtype": "Podvrsta goriva",
"fueltype": "Vrsta goriva",
"quantity": "Količina",
"gasstation": "Bencinska črpalka",
"fuel": {
"petrol": "Bencin",
"diesel": "Dizelsko gorivo",
"cng": "CNG",
"lpg": "LPG",
"electric": "Elektrika",
"ethanol": "Etanol"
},
"unit": {
"long": {
"litre": "Liter",
"gallon": "Galon",
"kilowatthour": "Kilovatna ura",
"kilogram": "Kilogram",
"usgallon": "Ameriška galona",
"minutes": "Minute",
"kilometers": "Kilometri",
"miles": "Milje"
},
"short": {
"litre": "Lit",
"gallon": "Gal",
"kilowatthour": "KwH",
"kilogram": "Kg",
"usgallon": "US Gal",
"minutes": "Min",
"kilometers": "Km",
"miles": "Mi"
}
},
"avgfillupqty": "Povprečna količina polnjenja",
"avgfillupexpense": "Povprečni stroški polnjenja",
"avgfuelcost": "Povprečni strošek goriva",
"per": "{0} na {1}",
"price": "Cena",
"total": "Skupaj",
"fulltank": "Rezervoar poln",
"partialfillup": "Delno polnjenje",
"getafulltank": "Ste dobili poln rezervoar?",
"tankpartialfull": "Kateremu sledite?",
"by": "Od",
"expenses": "Stroški",
"expensetype": "Vrsta stroška",
"noexpenses": "Zaenkrat ni bilo stroškov",
"download": "Prenesi",
"title": "Naslov",
"name": "Ime",
"delete": "Izbriši",
"importdata": "Uvozite podatke v Hammond",
"importdatadesc": "Za uvoz podatkov v Hammond izberite med naslednjimi možnostmi",
"import": "Uvozi",
"importcsv": "Če ste za shranjevanje podatkov o vozilu uporabljali {name}, izvozite datoteko CSV iz {name} in kliknite tukaj za uvoz.",
"importgeneric": "Generični uvoz polnjenja",
"importgenericdesc": "CSV uvoz poljenja.",
"choosecsv": "Izberite CSV",
"choosephoto": "Izberite fotografijo",
"importsuccessfull": "Podatki so bili uspešno uvoženi",
"importerror": "Pri uvozu datoteke je prišlo do težave. ",
"importfrom": "Uvoz iz {0}",
"stepstoimport": "Koraki za uvoz podatkov iz {name}",
"choosecsvimport": "Izberite {name} CSV in pritisnite gumb za uvoz.",
"choosedatafile": "Izberite datoteko CSV in pritisnite gumb za uvoz.",
"dontimportagain": "Prepričajte se, da datoteke ne uvozite znova, ker boste s tem ustvarili ponavljajoče se vnose.",
"checkpointsimportcsv": "Ko preverite vse te točke, preprosto uvozite spodnji CSV.",
"importhintunits": "Podobno se prepričajte, da sta <u>Enota za gorivo</u> in <u>Vrsta goriva</u> pravilno nameščeni pod Vozilo.",
"importhintcurrdist": "Prepričajte se, da sta <u>Valuta</u> in <u>Enota razdalje</u> pri Hammondu uporabniku pravilno nastavljeni.",
"importhintnickname": "Prepričajte se, da je vzdevek vozila v Hammondu popolnoma enak imenu v CSV datoteki polnjenj, sicer uvoz ne bo deloval.",
"importhintvehiclecreated": "Prepričajte se, da ste že ustvarili vozila na platformi Hammond.",
"importhintcreatecsv": "Izvozite svoje podatke iz {name} v formatu CSV. ",
"importgenerichintdata": "Podatki morajo biti v formatu CSV.",
"here": "tukaj",
"unprocessedquickentries": "Za obdelavo imate en hiter vnos. | Za obdelavo imate {0} hitrih vnosov.",
"show": "Prikaži",
"loginerror": "Pri prijavi v vaš račun je prišlo do napake. ",
"showunprocessed": "Pokaži samo neobdelano",
"unprocessed": "neobdelano",
"sitesettingdesc": "Posodobite nastavitve na ravni aplikacije. Te bodo uporabljene kot privzete vrednosti za nove uporabnike.",
"settingdesc": "Te bodo uporabljene kot privzete vrednosti vsakič, ko ustvarite novo polnjenje ali strošek.",
"areyousure": "Ste prepričani, da želite to narediti?",
"adduser": "Dodaj uporabnika",
"usercreatedsuccessfully": "Uporabnik je bil uspešno ustvarjen",
"userdisabledsuccessfully": "Uporabnik uspešno onemogočen",
"userenabledsuccessfully": "Uporabnik je uspešno omogočen",
"role": "Vloga",
"created": "Ustvarjeno",
"createnewuser": "Ustvari novega uporabnika",
"cancel": "Prekliči",
"novehicles": "Videti je, da še niste ustvarili vozila v sistemu. ",
"processed": "Označi obdelano",
"notfound": "Ni najdeno",
"timeout": "Med nalaganjem strani je potekla časovna omejitev. ",
"clicktoselect": "Kliknite za izbiro ...",
"expenseby": "Stroški po",
"selectvehicle": "Izberite vozilo",
"expensedate": "Datum izdatka",
"totalamountpaid": "Skupni plačani znesek",
"fillmoredetails": "Izpolnite več podrobnosti",
"markquickentryprocessed": "Označi izbrani hitri vnos kot obdelan",
"referquickentry": "Oglejte si hiter vnos",
"deletequickentry": "S tem boste izbrisali ta hitri vnos. ",
"fuelunit": "Enota za gorivo",
"fillingstation": "Ime bencinske postaje",
"comments": "Komentarji",
"missfillupbefore": "Ste pred tem zamudili vnos zapolnitve?",
"missedfillup": "Zamujeno polnjenje",
"fillupdate": "Datum polnjenja",
"fillupsavedsuccessfully": "Polnjenje je bil uspešno shranjeno",
"expensesavedsuccessfully": "Stroški so uspešno shranjeni",
"vehiclesavedsuccessfully": "Vozilo je uspešno shranjeno",
"settingssavedsuccessfully": "Nastavitve so uspešno shranjene",
"back": "Nazaj",
"nickname": "Vzdevek",
"registration": "Registracija",
"createvehicle": "Ustvarite vozilo",
"make": "Znamka / Podjetje",
"model": "Model",
"yearmanufacture": "Leto izdelave",
"enginesize": "Prostornina motorja (v cc)",
"mysqlconnstr": "Niz povezave Mysql",
"testconn": "Testna povezava",
"migrate": "Preseli",
"init": {
"migrateclarkson": "Selitev iz Clarksona",
"migrateclarksondesc": "Če imate obstoječo Clarkson namestitev in želite iz nje preseliti svoje podatke, pritisnite naslednji gumb.",
"freshinstall": "Sveža namestitev",
"freshinstalldesc": "Če želite novo namestitev Hammonda, pritisnite naslednji gumb.",
"clarkson": {
"desc": "<p>Zagotoviti morate, da lahko ta uvedba Hammonda dostopa do baze podatkov MySQL, ki jo uporablja Clarkson.</p><p>Če to ni neposredno mogoče, lahko naredite kopijo te zbirke podatkov nekje, kjer je dostopna iz tega primerka.</p><p>Ko je to storjeno, vnesite povezovalni niz v primerek MySQL v naslednji obliki.</p><p>Vsi uporabniki, uvoženi iz Clarksona, bodo imeli svoje uporabniško ime kot e-pošto v bazi podatkov Clarkson in geslo nastavljeno na<span class='' style='font-weight:bold'>hammond</span></p><code>uporabnik:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4</code><br/><br/>",
"success": "Uspešno smo prenesli podatke iz Clarksona. "
},
"fresh": {
"setupadminuser": "Nastavitev skrbniških uporabnikov",
"yourpassword": "Vaše geslo",
"youremail": "Vaš e-poštni naslov",
"yourname": "Vaše ime",
"success": "Uspešno ste se registrirali. "
}
},
"roles": {
"ADMIN": "SKRBNIK",
"USER": "UPORABNIK"
},
"profile": "Profil",
"processedon": "Obdelano dne",
"enable": "Omogoči",
"disable": "Onemogoči",
"confirm": "Kar daj",
"labelforfile": "Oznaka za to datoteko"
}

View file

@ -0,0 +1,231 @@
{
"quickentry": "没有速记 | 速记 | 速记",
"statistics": "统计数据",
"thisweek": "本周",
"thismonth": "本月",
"pastxdays": "过去一天 | 过去 {count} 天",
"pastxmonths": "过去一个月 | 过去 {count} 个月",
"thisyear": "今年",
"alltime": "所有时间",
"noattachments": "目前还没有附件",
"attachments": "附件",
"choosefile": "选择文件",
"addattachment": "添加附件",
"sharedwith": "共享给",
"share": "分享",
"you": "您",
"addfillup": "添加加注记录",
"createfillup": "创建加注记录",
"deletefillup": "删除此加注记录",
"addexpense": "添加支出",
"createexpense": "创建支出记录",
"deleteexpense": "删除此支出",
"nofillups": "目前还没有加注记录",
"transfervehicle": "转让车辆",
"settingssaved": "设置保存成功",
"yoursettings": "您的设置",
"settings": "设置",
"changepassword": "更改密码",
"oldpassword": "旧密码",
"newpassword": "新密码",
"repeatnewpassword": "重复新密码",
"passworddontmatch": "密码不匹配",
"save": "保存",
"supportthedeveloper": "支持开发者",
"buyhimabeer": "请他喝杯啤酒!",
"featurerequest": "功能请求",
"foundabug": "发现了错误",
"currentversion": "当前版本",
"moreinfo": "更多信息",
"currency": "货币",
"distanceunit": "长度单位",
"dateformat": "日期格式",
"createnow": "立即创建",
"yourvehicles": "您的车辆",
"menu": {
"quickentries": "速记",
"logout": "退出登录",
"import": "导入",
"home": "主页",
"settings": "设置",
"admin": "管理",
"sitesettings": "全局设置",
"users": "用户",
"login": "登录"
},
"enterusername": "输入您的用户名",
"enterpassword": "输入您的密码",
"email": "邮箱",
"password": "密码",
"login": "登录",
"totalexpenses": "总支出",
"fillupcost": "加注花费",
"otherexpenses": "其它支出",
"addvehicle": "添加车辆",
"editvehicle": "编辑车辆",
"deletevehicle": "删除车辆",
"sharevehicle": "共享车辆",
"makeowner": "设为车主",
"lastfillup": "上次加注记录",
"quickentrydesc": "拍摄发票或加油机显示屏的照片,以便稍后进行记录。",
"quickentrycreatedsuccessfully": "速记创建成功",
"uploadfile": "上传文件",
"uploadphoto": "上传照片",
"details": "详情",
"odometer": "里程表",
"language": "语言",
"date": "日期",
"pastfillups": "历史加注记录",
"fuelsubtype": "燃油型号",
"fueltype": "燃油类型",
"quantity": "加注量",
"gasstation": "加油站",
"fuel": {
"petrol": "汽油",
"diesel": "柴油",
"cng": "压缩天然气",
"lpg": "液化石油气",
"electric": "电力",
"ethanol": "乙醇"
},
"unit": {
"long": {
"litre": "升",
"gallon": "加仑",
"kilowatthour": "千瓦时",
"kilogram": "千克",
"usgallon": "美制加仑",
"minutes": "分钟",
"kilometers": "千米",
"miles": "英里"
},
"short": {
"litre": "升",
"gallon": "加仑",
"kilowatthour": "度",
"kilogram": "千克",
"usgallon": "美加仑",
"minutes": "分",
"kilometers": "千米",
"miles": "英里"
}
},
"avgfillupqty": "平均加注量",
"avgfillupexpense": "平均加注费用",
"avgfuelcost": "平均燃油成本",
"per": "每{1}的{0}",
"price": "价格",
"total": "总价",
"fulltank": "加满油箱",
"partialfillup": "部分加注",
"getafulltank": "您是否加满油箱?",
"tankpartialfull": "油箱状态如何标记?",
"by": "来自",
"expenses": "支出记录",
"expensetype": "支出类型",
"noexpenses": "目前还没有支出记录",
"download": "下载",
"title": "文件说明",
"name": "文件名",
"delete": "删除",
"importdata": "将数据导入 Hammond",
"importdatadesc": "从以下选项中进行选择以将数据导入 Hammond",
"import": "导入",
"importcsv": "如果您此前使用 {name} 存储车辆数据,请从 {name} 导出 CSV 文件,然后单击此处进行导入。",
"importgeneric": "通用导入",
"importgenericdesc": "导入加注信息的 CSV 文件。",
"choosecsv": "选择 CSV",
"choosephoto": "选择照片",
"importsuccessfull": "数据导入成功",
"importerror": "导入文件时出现问题,请检查错误信息。",
"importfrom": "从 {0} 导入",
"stepstoimport": "从 {name} 导入数据的步骤",
"choosecsvimport": "选择 {name} 的 CSV 文件,并单击导入按钮。",
"choosedatafile": "选择 CSV 文件,然后单击导入按钮。",
"dontimportagain": "确保不要再次导入文件,因为这样会产生重复数据。",
"checkpointsimportcsv": "检查完所有这些要点后,就在下面导入 CSV。",
"importhintunits": "同样,请确保车辆中的<u>燃油单位</u>和<u>燃油类型</u>设置正确。",
"importhintcurrdist": "确保在 Hammond 中正确设置了<u>货币</u>和<u>距离单位</u>。导入时不会从文件中自动检测货币,而是直接使用用户设置的货币。",
"importhintnickname": "确保 Hammond 中的车辆昵称与 CSV 中的名称完全相同,否则导入将不起作用。",
"importhintvehiclecreated": "确保已在 Hammond 中创建车辆。",
"importhintcreatecsv": "以 CSV 格式从 {name} 导出数据。可以在这里找到执行此操作的步骤:",
"importgenerichintdata": "数据必须为 CSV 格式。",
"here": "(文档)",
"unprocessedquickentries": "您有一条速记等待处理。 | 您有 {0} 条速记等待处理。",
"show": "显示",
"loginerror": "登录您的帐户时出错。{msg}",
"showunprocessed": "仅显示未处理的",
"unprocessed": "未处理的",
"sitesettingdesc": "更新全局设置,这些设置将作为新用户的默认值。",
"settingdesc": "当您创建新的加注或支出记录时,这些值将作为默认值使用。",
"areyousure": "您确定要这样做吗?",
"adduser": "添加用户",
"usercreatedsuccessfully": "用户创建成功",
"userdisabledsuccessfully": "用户禁用成功",
"userenabledsuccessfully": "用户启用成功",
"role": "角色",
"created": "创建",
"createnewuser": "创建新用户",
"cancel": "取消",
"novehicles": "您似乎尚未在系统中创建车辆,请先添加一辆。",
"processed": "标记为已处理",
"notfound": "未找到",
"timeout": "页面加载时超时,您确定仍连接到互联网吗?",
"clicktoselect": "单击以选择…",
"expenseby": "支出由",
"selectvehicle": "选择车辆",
"expensedate": "支出日期",
"totalamountpaid": "支付总额",
"fillmoredetails": "填写更多详细信息",
"markquickentryprocessed": "将选定的速记标记为已处理",
"referquickentry": "关联速记",
"deletequickentry": "此操作将删除这条速记。删除后无法恢复,您确定要继续吗?",
"fuelunit": "燃油单位",
"fillingstation": "加油站名称",
"comments": "注释",
"missfillupbefore": "您是否遗漏了之前的一次加注记录?",
"missedfillup": "遗漏的加注记录",
"fillupdate": "加注日期",
"fillupsavedsuccessfully": "加注记录保存成功",
"expensesavedsuccessfully": "支出记录保存成功",
"vehiclesavedsuccessfully": "车辆保存成功",
"settingssavedsuccessfully": "设置保存成功",
"back": "返回",
"nickname": "昵称",
"registration": "车牌号",
"createvehicle": "创建车辆",
"make": "品牌 / 制造商",
"model": "型号",
"yearmanufacture": "生产年份",
"enginesize": "发动机排量单位cc",
"mysqlconnstr": "MySQL 连接字符串",
"testconn": "测试连接",
"migrate": "迁移",
"init": {
"migrateclarkson": "从 Clarkson 迁移",
"migrateclarksondesc": "如果您已有 Clarkson 部署,并希望从中迁移数据,请单击以下按钮。",
"freshinstall": "全新安装",
"freshinstalldesc": "如果您想全新安装 Hammond请单击以下按钮。",
"clarkson": {
"desc": "<p>您需要此确保 Hammond 的部署可以访问 Clarkson 使用的 MySQL 数据库。</p><p>如果无法直接访问,可以在本实例可访问的地方复制该数据库。</p><p><完成后,按以下格式输入与 MySQL 实例的连接字符串。/p><p>所有从 Clarkson 导入的用户将使用原邮箱作为用户名,密码设置为<span class='' style='font-weight:bold'>hammond</span></p><code>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
"success": "我们已成功从 Clarkson 迁移数据。您将很快被重定向到登录界面在那里您可以使用现有的邮箱和密码hammond登录。"
},
"fresh": {
"setupadminuser": "设置管理员用户",
"yourpassword": "您的密码",
"youremail": "您的邮箱",
"yourname": "您的姓名",
"success": "您已注册成功。您将很快被重定向到登录界面,登录后即可开始使用。"
}
},
"roles": {
"ADMIN": "管理员",
"USER": "普通用户"
},
"profile": "配置文件",
"processedon": "处理于",
"enable": "启用",
"disable": "禁用",
"confirm": "继续",
"labelforfile": "文件说明"
}

View file

@ -0,0 +1,176 @@
import * as React from 'react';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Toolbar from '@mui/material/Toolbar';
import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import Menu from '@mui/material/Menu';
import MenuIcon from '@mui/icons-material/Menu';
import Container from '@mui/material/Container';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import Tooltip from '@mui/material/Tooltip';
import MenuItem from '@mui/material/MenuItem';
import AdbIcon from '@mui/icons-material/Adb';
import MenuLanguages from './MenuLanguages';
import logo from '../logo.svg'
import reactLogo from '../react.svg'
//translation
import { useTranslation } from 'react-i18next';
import { LANGUAGES } from '../locales'
// a test to see if this will work in menu
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
function GarageAppLogo() {
return (
<div className="menu-logo-container">
<div className="menu-logo-image">
<img src={logo} alt="Bun Logo" className="menu-logo bun-logo" />
<img src={reactLogo} alt="React Logo" className="menu-logo react-logo" />
</div>
<div className="menu-logo-text">
<h2>
GarageApp
</h2>
</div>
</div>
)
}
const pages = ['Home', 'Quick Entries', 'Import'];
const settings = ['Profile', 'Admin', 'Logout'];
function ResponsiveAppBar() {
//translation
const { t, i18n } = useTranslation();
//MaterialUI stuff
const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>(null);
const [anchorElUser, setAnchorElUser] = React.useState<null | HTMLElement>(null);
const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
setAnchorElNav(event.currentTarget);
};
const handleOpenUserMenu = (event: React.MouseEvent<HTMLElement>) => {
setAnchorElUser(event.currentTarget);
};
const handleCloseNavMenu = () => {
setAnchorElNav(null);
};
const handleCloseUserMenu = () => {
setAnchorElUser(null);
};
return (
<AppBar position="static">
<Container>
<Toolbar disableGutters>
<GarageAppLogo sx={{ display: { xs: 'none', md: 'flex' }, mr: 1 }} />
<Box sx={{ flexGrow: 1, display: { xs: 'end', md: 'none' } }}>
<IconButton
size="large"
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleOpenNavMenu}
color="inherit"
>
<MenuIcon />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorElNav}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
open={Boolean(anchorElNav)}
onClose={handleCloseNavMenu}
sx={{ display: { xs: 'block', md: 'none' } }}
>
{pages.map((page) => (
<MenuItem key={page} onClick={handleCloseNavMenu}>
<Typography sx={{ textAlign: 'right' }}>{page}</Typography>
</MenuItem>
))}
</Menu>
</Box>
<AdbIcon sx={{ display: { xs: 'flex', md: 'none' }, mr: 1 }} />
<Typography
variant="h5"
noWrap
component="a"
href="#app-bar-with-responsive-menu"
sx={{
mr: 2,
display: { xs: 'flex', md: 'none' },
flexGrow: 1,
fontFamily: 'monospace',
fontWeight: 700,
letterSpacing: '.3rem',
color: 'inherit',
textDecoration: 'none',
}}
>
LOGO
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}>
{pages.map((page) => (
<Button
key={page}
onClick={handleCloseNavMenu}
sx={{ my: 2, color: 'white', display: 'block' }}
>
{page}
</Button>
))}
</Box>
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Open settings">
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar alt="Remy Sharp" src="/static/images/avatar/2.jpg" />
</IconButton>
</Tooltip>
<Menu
sx={{ mt: '45px' }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
{settings.map((setting) => (
<MenuItem key={setting} onClick={handleCloseUserMenu}>
<Typography sx={{ textAlign: 'center' }}>{setting}</Typography>
</MenuItem>
))}
<MenuItem>
<MenuLanguages onClose={handleCloseUserMenu} />
</MenuItem>
</Menu>
</Box>
</Toolbar>
</Container>
</AppBar>
);
}
export default ResponsiveAppBar;

View file

@ -0,0 +1,89 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import MenuList from '@mui/material/MenuList';
import MenuItem from '@mui/material/MenuItem';
import ListItemText from '@mui/material/ListItemText';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemButton from '@mui/material/ListItemButton';
import { LANGUAGES } from '../locales'
import { Icon } from "@iconify/react";
import { useTranslation } from 'react-i18next';
import Menu from '@mui/material/Menu';
export default function LanguageMenu( {closeAction} ) {
const { t, i18n } = useTranslation();
const handleLanguageChange = (lang: any) => {
try {
i18n.changeLanguage(lang.code);
} catch (error) {
console.error(`Error changing language to ${lang.code}:`, error);
}
};
const [anchorElUser, setAnchorElUser] = React.useState<null | HTMLElement>(null);
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const [selectedIndex, setSelectedIndex] = React.useState(1);
const open = Boolean(anchorEl);
const handleClickListItem = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleLanguageSelect = (
event: React.MouseEvent<HTMLElement>,
index: number,
) => {
setSelectedIndex(index);
handleLanguageChange(LANGUAGES[index]);
closeAction;
setAnchorEl(null);
setAnchorElUser(null);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<Paper sx={{ minWidth: 320, maxWidth: '100%' }}>
<ListItemButton
id="language-button"
aria-haspopup="listbox"
aria-controls="language-menu"
aria-label="Language"
aria-expanded={open ? 'true' : undefined}
onClick={handleClickListItem}
>
<ListItemText
primary={t ('language')}
secondary={i18n.resolvedLanguage}
/>
</ListItemButton>
<Menu
id="language-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
slotProps={{
list: {
'aria-labelledby': 'language-button',
role: 'listbox',
},
}}
>
{LANGUAGES.map((lang, index) =>
<MenuItem key={index} onClick={() => handleLanguageSelect(event, index)}>
<ListItemIcon>
<Icon icon={"circle-flags:" + lang.code} />
</ListItemIcon>
<ListItemText>{lang.label}</ListItemText>
</MenuItem>
)}
</Menu>
</Paper>
)
}

View file

@ -0,0 +1,13 @@
import { useTranslation, withTranslation, Trans } from 'react-i18next';
export default function StatisticsView() {
const { t, i18n } = useTranslation();
return (
<h1>{t ('statistics')}</h1>
)
}

View file

@ -13,8 +13,6 @@ import IconButton, { IconButtonProps } from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import { red } from '@mui/material/colors';
import FavoriteIcon from '@mui/icons-material/Favorite';
import ShareIcon from '@mui/icons-material/Share';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import GasStation from './icons/gasFillup'

View file

@ -7,9 +7,9 @@ import { useTranslation, withTranslation, Trans } from 'react-i18next';
const response = await fetch("/GarageApp/api/vehicles");
console.log(response)
// console.log(response)
const vehicles = await response.json();
console.log(vehicles)
// console.log(vehicles)
export default function YourVehicleList() {
const { t, i18n } = useTranslation();
// const response = await fetch("/GarageApp/api/vehicles");