mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-04-14 16:40:58 -04:00
Merge remote-tracking branch 'origin/master' into aakansha-create-text-containers-programmatically
This commit is contained in:
commit
dcf9e27e51
135 changed files with 5873 additions and 57355 deletions
1
.npmrc
1
.npmrc
|
@ -1 +1,2 @@
|
|||
save-exact=true
|
||||
legacy-peer-deps=true
|
||||
|
|
|
@ -16,7 +16,6 @@ function App() {
|
|||
className="custom-footer"
|
||||
onClick={() => alert("This is dummy footer")}
|
||||
>
|
||||
{" "}
|
||||
custom footer
|
||||
</button>
|
||||
</Footer>
|
||||
|
|
|
@ -14,8 +14,7 @@ function App() {
|
|||
Item1
|
||||
</MainMenu.Item>
|
||||
<MainMenu.Item onSelect={() => window.alert("Item2")}>
|
||||
{" "}
|
||||
Item 2{" "}
|
||||
Item 2
|
||||
</MainMenu.Item>
|
||||
</MainMenu>
|
||||
</Excalidraw>
|
||||
|
@ -93,7 +92,6 @@ function App() {
|
|||
style={{ height: "2rem" }}
|
||||
onClick={() => window.alert("custom menu item")}
|
||||
>
|
||||
{" "}
|
||||
custom item
|
||||
</button>
|
||||
</MainMenu.ItemCustom>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
## renderTopRightUI
|
||||
|
||||
<pre>
|
||||
(isMobile: boolean, appState:{" "}
|
||||
(isMobile: boolean, appState:
|
||||
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">
|
||||
AppState
|
||||
</a>
|
||||
|
@ -29,8 +29,7 @@ function App() {
|
|||
}}
|
||||
onClick={() => window.alert("This is dummy top right UI")}
|
||||
>
|
||||
{" "}
|
||||
Click me{" "}
|
||||
Click me
|
||||
</button>
|
||||
);
|
||||
}}
|
||||
|
@ -55,8 +54,7 @@ function App() {
|
|||
<Excalidraw
|
||||
renderCustomStats={() => (
|
||||
<p style={{ color: "#70b1ec", fontWeight: "bold" }}>
|
||||
{" "}
|
||||
Dummy stats will be shown here{" "}
|
||||
Dummy stats will be shown here
|
||||
</p>
|
||||
)}
|
||||
/>
|
||||
|
@ -105,8 +103,7 @@ function App() {
|
|||
return (
|
||||
<div style={{ height: "500px" }}>
|
||||
<button className="custom-button" onClick={() => excalidrawAPI.toggleMenu("customSidebar")}>
|
||||
{" "}
|
||||
Toggle Custom Sidebar{" "}
|
||||
Toggle Custom Sidebar
|
||||
</button>
|
||||
<Excalidraw
|
||||
UIOptions={{ dockedSidebarBreakpoint: 100 }}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-popover": "1.0.3",
|
||||
"@radix-ui/react-tabs": "1.0.2",
|
||||
"@sentry/browser": "6.2.5",
|
||||
"@sentry/integrations": "6.2.5",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ColorPicker } from "../components/ColorPicker";
|
||||
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
|
||||
import { ZoomInIcon, ZoomOutIcon } from "../components/icons";
|
||||
import { ToolButton } from "../components/ToolButton";
|
||||
import { CURSOR_TYPE, MIN_ZOOM, THEME, ZOOM_STEP } from "../constants";
|
||||
|
@ -19,6 +19,7 @@ import {
|
|||
isEraserActive,
|
||||
isHandToolActive,
|
||||
} from "../appState";
|
||||
import { DEFAULT_CANVAS_BACKGROUND_PICKS } from "../colors";
|
||||
|
||||
export const actionChangeViewBackgroundColor = register({
|
||||
name: "changeViewBackgroundColor",
|
||||
|
@ -35,24 +36,21 @@ export const actionChangeViewBackgroundColor = register({
|
|||
commitToHistory: !!value.viewBackgroundColor,
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData }) => {
|
||||
PanelComponent: ({ elements, appState, updateData, appProps }) => {
|
||||
// FIXME move me to src/components/mainMenu/DefaultItems.tsx
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
<ColorPicker
|
||||
label={t("labels.canvasBackground")}
|
||||
type="canvasBackground"
|
||||
color={appState.viewBackgroundColor}
|
||||
onChange={(color) => updateData({ viewBackgroundColor: color })}
|
||||
isActive={appState.openPopup === "canvasColorPicker"}
|
||||
setActive={(active) =>
|
||||
updateData({ openPopup: active ? "canvasColorPicker" : null })
|
||||
}
|
||||
data-testid="canvas-background-picker"
|
||||
elements={elements}
|
||||
appState={appState}
|
||||
/>
|
||||
</div>
|
||||
<ColorPicker
|
||||
palette={null}
|
||||
topPicks={DEFAULT_CANVAS_BACKGROUND_PICKS}
|
||||
label={t("labels.canvasBackground")}
|
||||
type="canvasBackground"
|
||||
color={appState.viewBackgroundColor}
|
||||
onChange={(color) => updateData({ viewBackgroundColor: color })}
|
||||
data-testid="canvas-background-picker"
|
||||
elements={elements}
|
||||
appState={appState}
|
||||
updateData={updateData}
|
||||
/>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
68
src/actions/actionElementLock.test.tsx
Normal file
68
src/actions/actionElementLock.test.tsx
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { Excalidraw } from "../packages/excalidraw/index";
|
||||
import { queryByTestId, fireEvent } from "@testing-library/react";
|
||||
import { render } from "../tests/test-utils";
|
||||
import { Pointer, UI } from "../tests/helpers/ui";
|
||||
import { API } from "../tests/helpers/api";
|
||||
|
||||
const { h } = window;
|
||||
const mouse = new Pointer("mouse");
|
||||
|
||||
describe("element locking", () => {
|
||||
it("should not show unlockAllElements action in contextMenu if no elements locked", async () => {
|
||||
await render(<Excalidraw />);
|
||||
|
||||
mouse.rightClickAt(0, 0);
|
||||
|
||||
const item = queryByTestId(UI.queryContextMenu()!, "unlockAllElements");
|
||||
expect(item).toBe(null);
|
||||
});
|
||||
|
||||
it("should unlock all elements and select them when using unlockAllElements action in contextMenu", async () => {
|
||||
await render(
|
||||
<Excalidraw
|
||||
initialData={{
|
||||
elements: [
|
||||
API.createElement({
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 100,
|
||||
locked: true,
|
||||
}),
|
||||
API.createElement({
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 100,
|
||||
locked: true,
|
||||
}),
|
||||
API.createElement({
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 100,
|
||||
locked: false,
|
||||
}),
|
||||
],
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
mouse.rightClickAt(0, 0);
|
||||
|
||||
expect(Object.keys(h.state.selectedElementIds).length).toBe(0);
|
||||
expect(h.elements.map((el) => el.locked)).toEqual([true, true, false]);
|
||||
|
||||
const item = queryByTestId(UI.queryContextMenu()!, "unlockAllElements");
|
||||
expect(item).not.toBe(null);
|
||||
|
||||
fireEvent.click(item!.querySelector("button")!);
|
||||
|
||||
expect(h.elements.map((el) => el.locked)).toEqual([false, false, false]);
|
||||
// should select the unlocked elements
|
||||
expect(h.state.selectedElementIds).toEqual({
|
||||
[h.elements[0].id]: true,
|
||||
[h.elements[1].id]: true,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,8 +5,11 @@ import { getSelectedElements } from "../scene";
|
|||
import { arrayToMap } from "../utils";
|
||||
import { register } from "./register";
|
||||
|
||||
export const actionToggleLock = register({
|
||||
name: "toggleLock",
|
||||
const shouldLock = (elements: readonly ExcalidrawElement[]) =>
|
||||
elements.every((el) => !el.locked);
|
||||
|
||||
export const actionToggleElementLock = register({
|
||||
name: "toggleElementLock",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
const selectedElements = getSelectedElements(elements, appState, true);
|
||||
|
@ -15,20 +18,21 @@ export const actionToggleLock = register({
|
|||
return false;
|
||||
}
|
||||
|
||||
const operation = getOperation(selectedElements);
|
||||
const nextLockState = shouldLock(selectedElements);
|
||||
const selectedElementsMap = arrayToMap(selectedElements);
|
||||
const lock = operation === "lock";
|
||||
return {
|
||||
elements: elements.map((element) => {
|
||||
if (!selectedElementsMap.has(element.id)) {
|
||||
return element;
|
||||
}
|
||||
|
||||
return newElementWith(element, { locked: lock });
|
||||
return newElementWith(element, { locked: nextLockState });
|
||||
}),
|
||||
appState: {
|
||||
...appState,
|
||||
selectedLinearElement: lock ? null : appState.selectedLinearElement,
|
||||
selectedLinearElement: nextLockState
|
||||
? null
|
||||
: appState.selectedLinearElement,
|
||||
},
|
||||
commitToHistory: true,
|
||||
};
|
||||
|
@ -41,7 +45,7 @@ export const actionToggleLock = register({
|
|||
: "labels.elementLock.lock";
|
||||
}
|
||||
|
||||
return getOperation(selected) === "lock"
|
||||
return shouldLock(selected)
|
||||
? "labels.elementLock.lockAll"
|
||||
: "labels.elementLock.unlockAll";
|
||||
},
|
||||
|
@ -55,6 +59,31 @@ export const actionToggleLock = register({
|
|||
},
|
||||
});
|
||||
|
||||
const getOperation = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
): "lock" | "unlock" => (elements.some((el) => !el.locked) ? "lock" : "unlock");
|
||||
export const actionUnlockAllElements = register({
|
||||
name: "unlockAllElements",
|
||||
trackEvent: { category: "canvas" },
|
||||
viewMode: false,
|
||||
predicate: (elements) => {
|
||||
return elements.some((element) => element.locked);
|
||||
},
|
||||
perform: (elements, appState) => {
|
||||
const lockedElements = elements.filter((el) => el.locked);
|
||||
|
||||
return {
|
||||
elements: elements.map((element) => {
|
||||
if (element.locked) {
|
||||
return newElementWith(element, { locked: false });
|
||||
}
|
||||
return element;
|
||||
}),
|
||||
appState: {
|
||||
...appState,
|
||||
selectedElementIds: Object.fromEntries(
|
||||
lockedElements.map((el) => [el.id, true]),
|
||||
),
|
||||
},
|
||||
commitToHistory: true,
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.elementLock.unlockAll",
|
||||
});
|
|
@ -14,7 +14,7 @@ import {
|
|||
} from "../element/bounds";
|
||||
import { isLinearElement } from "../element/typeChecks";
|
||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||
import { KEYS } from "../keys";
|
||||
import { CODES, KEYS } from "../keys";
|
||||
|
||||
const enableActionFlipHorizontal = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
|
@ -48,7 +48,7 @@ export const actionFlipHorizontal = register({
|
|||
commitToHistory: true,
|
||||
};
|
||||
},
|
||||
keyTest: (event) => event.shiftKey && event.code === "KeyH",
|
||||
keyTest: (event) => event.shiftKey && event.code === CODES.H,
|
||||
contextItemLabel: "labels.flipHorizontal",
|
||||
predicate: (elements, appState) =>
|
||||
enableActionFlipHorizontal(elements, appState),
|
||||
|
@ -65,7 +65,7 @@ export const actionFlipVertical = register({
|
|||
};
|
||||
},
|
||||
keyTest: (event) =>
|
||||
event.shiftKey && event.code === "KeyV" && !event[KEYS.CTRL_OR_CMD],
|
||||
event.shiftKey && event.code === CODES.V && !event[KEYS.CTRL_OR_CMD],
|
||||
contextItemLabel: "labels.flipVertical",
|
||||
predicate: (elements, appState) =>
|
||||
enableActionFlipVertical(elements, appState),
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
import { AppState } from "../../src/types";
|
||||
import {
|
||||
DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE,
|
||||
DEFAULT_ELEMENT_BACKGROUND_PICKS,
|
||||
DEFAULT_ELEMENT_STROKE_COLOR_PALETTE,
|
||||
DEFAULT_ELEMENT_STROKE_PICKS,
|
||||
} from "../colors";
|
||||
import { trackEvent } from "../analytics";
|
||||
import { ButtonIconSelect } from "../components/ButtonIconSelect";
|
||||
import { ColorPicker } from "../components/ColorPicker";
|
||||
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
|
||||
import { IconPicker } from "../components/IconPicker";
|
||||
// TODO barnabasmolnar/editor-redesign
|
||||
// TextAlignTopIcon, TextAlignBottomIcon,TextAlignMiddleIcon,
|
||||
|
@ -226,10 +232,12 @@ export const actionChangeStrokeColor = register({
|
|||
commitToHistory: !!value.currentItemStrokeColor,
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData }) => (
|
||||
PanelComponent: ({ elements, appState, updateData, appProps }) => (
|
||||
<>
|
||||
<h3 aria-hidden="true">{t("labels.stroke")}</h3>
|
||||
<ColorPicker
|
||||
topPicks={DEFAULT_ELEMENT_STROKE_PICKS}
|
||||
palette={DEFAULT_ELEMENT_STROKE_COLOR_PALETTE}
|
||||
type="elementStroke"
|
||||
label={t("labels.stroke")}
|
||||
color={getFormValue(
|
||||
|
@ -239,12 +247,9 @@ export const actionChangeStrokeColor = register({
|
|||
appState.currentItemStrokeColor,
|
||||
)}
|
||||
onChange={(color) => updateData({ currentItemStrokeColor: color })}
|
||||
isActive={appState.openPopup === "strokeColorPicker"}
|
||||
setActive={(active) =>
|
||||
updateData({ openPopup: active ? "strokeColorPicker" : null })
|
||||
}
|
||||
elements={elements}
|
||||
appState={appState}
|
||||
updateData={updateData}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
|
@ -269,10 +274,12 @@ export const actionChangeBackgroundColor = register({
|
|||
commitToHistory: !!value.currentItemBackgroundColor,
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData }) => (
|
||||
PanelComponent: ({ elements, appState, updateData, appProps }) => (
|
||||
<>
|
||||
<h3 aria-hidden="true">{t("labels.background")}</h3>
|
||||
<ColorPicker
|
||||
topPicks={DEFAULT_ELEMENT_BACKGROUND_PICKS}
|
||||
palette={DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE}
|
||||
type="elementBackground"
|
||||
label={t("labels.background")}
|
||||
color={getFormValue(
|
||||
|
@ -282,12 +289,9 @@ export const actionChangeBackgroundColor = register({
|
|||
appState.currentItemBackgroundColor,
|
||||
)}
|
||||
onChange={(color) => updateData({ currentItemBackgroundColor: color })}
|
||||
isActive={appState.openPopup === "backgroundColorPicker"}
|
||||
setActive={(active) =>
|
||||
updateData({ openPopup: active ? "backgroundColorPicker" : null })
|
||||
}
|
||||
elements={elements}
|
||||
appState={appState}
|
||||
updateData={updateData}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import ExcalidrawApp from "../excalidraw-app";
|
||||
import { t } from "../i18n";
|
||||
import { CODES } from "../keys";
|
||||
import { API } from "../tests/helpers/api";
|
||||
import { Keyboard, Pointer, UI } from "../tests/helpers/ui";
|
||||
import { fireEvent, render, screen } from "../tests/test-utils";
|
||||
import {
|
||||
act,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
togglePopover,
|
||||
} from "../tests/test-utils";
|
||||
import { copiedStyles } from "./actionStyles";
|
||||
|
||||
const { h } = window;
|
||||
|
@ -14,7 +19,14 @@ describe("actionStyles", () => {
|
|||
beforeEach(async () => {
|
||||
await render(<ExcalidrawApp />);
|
||||
});
|
||||
it("should copy & paste styles via keyboard", () => {
|
||||
|
||||
afterEach(async () => {
|
||||
// https://github.com/floating-ui/floating-ui/issues/1908#issuecomment-1301553793
|
||||
// affects node v16+
|
||||
await act(async () => {});
|
||||
});
|
||||
|
||||
it("should copy & paste styles via keyboard", async () => {
|
||||
UI.clickTool("rectangle");
|
||||
mouse.down(10, 10);
|
||||
mouse.up(20, 20);
|
||||
|
@ -24,10 +36,10 @@ describe("actionStyles", () => {
|
|||
mouse.up(20, 20);
|
||||
|
||||
// Change some styles of second rectangle
|
||||
UI.clickLabeledElement("Stroke");
|
||||
UI.clickLabeledElement(t("colors.c92a2a"));
|
||||
UI.clickLabeledElement("Background");
|
||||
UI.clickLabeledElement(t("colors.e64980"));
|
||||
togglePopover("Stroke");
|
||||
UI.clickOnTestId("color-red");
|
||||
togglePopover("Background");
|
||||
UI.clickOnTestId("color-blue");
|
||||
// Fill style
|
||||
fireEvent.click(screen.getByTitle("Cross-hatch"));
|
||||
// Stroke width
|
||||
|
@ -60,8 +72,8 @@ describe("actionStyles", () => {
|
|||
|
||||
const firstRect = API.getSelectedElement();
|
||||
expect(firstRect.id).toBe(h.elements[0].id);
|
||||
expect(firstRect.strokeColor).toBe("#c92a2a");
|
||||
expect(firstRect.backgroundColor).toBe("#e64980");
|
||||
expect(firstRect.strokeColor).toBe("#e03131");
|
||||
expect(firstRect.backgroundColor).toBe("#a5d8ff");
|
||||
expect(firstRect.fillStyle).toBe("cross-hatch");
|
||||
expect(firstRect.strokeWidth).toBe(2); // Bold: 2
|
||||
expect(firstRect.strokeStyle).toBe("dotted");
|
||||
|
|
|
@ -84,5 +84,5 @@ export { actionToggleZenMode } from "./actionToggleZenMode";
|
|||
export { actionToggleStats } from "./actionToggleStats";
|
||||
export { actionUnbindText, actionBindText } from "./actionBoundText";
|
||||
export { actionLink } from "../element/Hyperlink";
|
||||
export { actionToggleLock } from "./actionToggleLock";
|
||||
export { actionToggleElementLock } from "./actionElementLock";
|
||||
export { actionToggleLinearEditor } from "./actionLinearEditor";
|
||||
|
|
|
@ -34,7 +34,7 @@ export type ShortcutName =
|
|||
| "flipHorizontal"
|
||||
| "flipVertical"
|
||||
| "hyperlink"
|
||||
| "toggleLock"
|
||||
| "toggleElementLock"
|
||||
>
|
||||
| "saveScene"
|
||||
| "imageExport";
|
||||
|
@ -80,7 +80,7 @@ const shortcutMap: Record<ShortcutName, string[]> = {
|
|||
flipVertical: [getShortcutKey("Shift+V")],
|
||||
viewMode: [getShortcutKey("Alt+R")],
|
||||
hyperlink: [getShortcutKey("CtrlOrCmd+K")],
|
||||
toggleLock: [getShortcutKey("CtrlOrCmd+Shift+L")],
|
||||
toggleElementLock: [getShortcutKey("CtrlOrCmd+Shift+L")],
|
||||
};
|
||||
|
||||
export const getShortcutFromShortcutName = (name: ShortcutName) => {
|
||||
|
|
|
@ -111,7 +111,8 @@ export type ActionName =
|
|||
| "unbindText"
|
||||
| "hyperlink"
|
||||
| "bindText"
|
||||
| "toggleLock"
|
||||
| "unlockAllElements"
|
||||
| "toggleElementLock"
|
||||
| "toggleLinearEditor"
|
||||
| "toggleEraserTool"
|
||||
| "toggleHandTool"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import oc from "open-color";
|
||||
import { COLOR_PALETTE } from "./colors";
|
||||
import {
|
||||
DEFAULT_ELEMENT_PROPS,
|
||||
DEFAULT_FONT_FAMILY,
|
||||
|
@ -84,7 +84,7 @@ export const getDefaultAppState = (): Omit<
|
|||
startBoundElement: null,
|
||||
suggestedBindings: [],
|
||||
toast: null,
|
||||
viewBackgroundColor: oc.white,
|
||||
viewBackgroundColor: COLOR_PALETTE.white,
|
||||
zenModeEnabled: false,
|
||||
zoom: {
|
||||
value: 1 as NormalizedZoomValue,
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
import colors from "./colors";
|
||||
import { DEFAULT_FONT_SIZE, ENV } from "./constants";
|
||||
import {
|
||||
COLOR_PALETTE,
|
||||
DEFAULT_CHART_COLOR_INDEX,
|
||||
getAllColorsSpecificShade,
|
||||
} from "./colors";
|
||||
import {
|
||||
DEFAULT_FONT_FAMILY,
|
||||
DEFAULT_FONT_SIZE,
|
||||
ENV,
|
||||
VERTICAL_ALIGN,
|
||||
} from "./constants";
|
||||
import { newElement, newLinearElement, newTextElement } from "./element";
|
||||
import { NonDeletedExcalidrawElement } from "./element/types";
|
||||
import { randomId } from "./random";
|
||||
|
@ -153,15 +162,22 @@ export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => {
|
|||
return result;
|
||||
};
|
||||
|
||||
const bgColors = colors.elementBackground.slice(
|
||||
2,
|
||||
colors.elementBackground.length,
|
||||
);
|
||||
const bgColors = getAllColorsSpecificShade(DEFAULT_CHART_COLOR_INDEX);
|
||||
|
||||
// Put all the common properties here so when the whole chart is selected
|
||||
// the properties dialog shows the correct selected values
|
||||
const commonProps = {
|
||||
strokeColor: colors.elementStroke[0],
|
||||
fillStyle: "hachure",
|
||||
fontFamily: DEFAULT_FONT_FAMILY,
|
||||
fontSize: DEFAULT_FONT_SIZE,
|
||||
opacity: 100,
|
||||
roughness: 1,
|
||||
strokeColor: COLOR_PALETTE.black,
|
||||
roundness: null,
|
||||
strokeStyle: "solid",
|
||||
strokeWidth: 1,
|
||||
verticalAlign: VERTICAL_ALIGN.MIDDLE,
|
||||
locked: false,
|
||||
} as const;
|
||||
|
||||
const getChartDimentions = (spreadsheet: Spreadsheet) => {
|
||||
|
@ -322,7 +338,7 @@ const chartBaseElements = (
|
|||
y: y - chartHeight,
|
||||
width: chartWidth,
|
||||
height: chartHeight,
|
||||
strokeColor: colors.elementStroke[0],
|
||||
strokeColor: COLOR_PALETTE.black,
|
||||
fillStyle: "solid",
|
||||
opacity: 6,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
import colors from "./colors";
|
||||
import {
|
||||
DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX,
|
||||
DEFAULT_ELEMENT_STROKE_COLOR_INDEX,
|
||||
getAllColorsSpecificShade,
|
||||
} from "./colors";
|
||||
import { AppState } from "./types";
|
||||
|
||||
const BG_COLORS = getAllColorsSpecificShade(
|
||||
DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX,
|
||||
);
|
||||
const STROKE_COLORS = getAllColorsSpecificShade(
|
||||
DEFAULT_ELEMENT_STROKE_COLOR_INDEX,
|
||||
);
|
||||
|
||||
export const getClientColors = (clientId: string, appState: AppState) => {
|
||||
if (appState?.collaborators) {
|
||||
const currentUser = appState.collaborators.get(clientId);
|
||||
|
@ -11,18 +22,19 @@ export const getClientColors = (clientId: string, appState: AppState) => {
|
|||
// Naive way of getting an integer out of the clientId
|
||||
const sum = clientId.split("").reduce((a, str) => a + str.charCodeAt(0), 0);
|
||||
|
||||
// Skip transparent & gray colors
|
||||
const backgrounds = colors.elementBackground.slice(3);
|
||||
const strokes = colors.elementStroke.slice(3);
|
||||
return {
|
||||
background: backgrounds[sum % backgrounds.length],
|
||||
stroke: strokes[sum % strokes.length],
|
||||
background: BG_COLORS[sum % BG_COLORS.length],
|
||||
stroke: STROKE_COLORS[sum % STROKE_COLORS.length],
|
||||
};
|
||||
};
|
||||
|
||||
export const getClientInitials = (userName?: string | null) => {
|
||||
if (!userName?.trim()) {
|
||||
return "?";
|
||||
}
|
||||
return userName.trim()[0].toUpperCase();
|
||||
/**
|
||||
* returns first char, capitalized
|
||||
*/
|
||||
export const getNameInitial = (name?: string | null) => {
|
||||
// first char can be a surrogate pair, hence using codePointAt
|
||||
const firstCodePoint = name?.trim()?.codePointAt(0);
|
||||
return (
|
||||
firstCodePoint ? String.fromCodePoint(firstCodePoint) : "?"
|
||||
).toUpperCase();
|
||||
};
|
||||
|
|
183
src/colors.ts
183
src/colors.ts
|
@ -1,22 +1,167 @@
|
|||
import oc from "open-color";
|
||||
import { Merge } from "./utility-types";
|
||||
|
||||
const shades = (index: number) => [
|
||||
oc.red[index],
|
||||
oc.pink[index],
|
||||
oc.grape[index],
|
||||
oc.violet[index],
|
||||
oc.indigo[index],
|
||||
oc.blue[index],
|
||||
oc.cyan[index],
|
||||
oc.teal[index],
|
||||
oc.green[index],
|
||||
oc.lime[index],
|
||||
oc.yellow[index],
|
||||
oc.orange[index],
|
||||
];
|
||||
|
||||
export default {
|
||||
canvasBackground: [oc.white, oc.gray[0], oc.gray[1], ...shades(0)],
|
||||
elementBackground: ["transparent", oc.gray[4], oc.gray[6], ...shades(6)],
|
||||
elementStroke: [oc.black, oc.gray[8], oc.gray[7], ...shades(9)],
|
||||
// FIXME can't put to utils.ts rn because of circular dependency
|
||||
const pick = <R extends Record<string, any>, K extends readonly (keyof R)[]>(
|
||||
source: R,
|
||||
keys: K,
|
||||
) => {
|
||||
return keys.reduce((acc, key: K[number]) => {
|
||||
if (key in source) {
|
||||
acc[key] = source[key];
|
||||
}
|
||||
return acc;
|
||||
}, {} as Pick<R, K[number]>) as Pick<R, K[number]>;
|
||||
};
|
||||
|
||||
export type ColorPickerColor =
|
||||
| Exclude<keyof oc, "indigo" | "lime">
|
||||
| "transparent"
|
||||
| "bronze";
|
||||
export type ColorTuple = readonly [string, string, string, string, string];
|
||||
export type ColorPalette = Merge<
|
||||
Record<ColorPickerColor, ColorTuple>,
|
||||
{ black: string; white: string; transparent: string }
|
||||
>;
|
||||
|
||||
// used general type instead of specific type (ColorPalette) to support custom colors
|
||||
export type ColorPaletteCustom = { [key: string]: ColorTuple | string };
|
||||
export type ColorShadesIndexes = [number, number, number, number, number];
|
||||
|
||||
export const MAX_CUSTOM_COLORS_USED_IN_CANVAS = 5;
|
||||
export const COLORS_PER_ROW = 5;
|
||||
|
||||
export const DEFAULT_CHART_COLOR_INDEX = 4;
|
||||
|
||||
export const DEFAULT_ELEMENT_STROKE_COLOR_INDEX = 4;
|
||||
export const DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX = 1;
|
||||
export const ELEMENTS_PALETTE_SHADE_INDEXES = [0, 2, 4, 6, 8] as const;
|
||||
export const CANVAS_PALETTE_SHADE_INDEXES = [0, 1, 2, 3, 4] as const;
|
||||
|
||||
export const getSpecificColorShades = (
|
||||
color: Exclude<
|
||||
ColorPickerColor,
|
||||
"transparent" | "white" | "black" | "bronze"
|
||||
>,
|
||||
indexArr: Readonly<ColorShadesIndexes>,
|
||||
) => {
|
||||
return indexArr.map((index) => oc[color][index]) as any as ColorTuple;
|
||||
};
|
||||
|
||||
export const COLOR_PALETTE = {
|
||||
transparent: "transparent",
|
||||
black: "#1e1e1e",
|
||||
white: "#ffffff",
|
||||
// open-colors
|
||||
gray: getSpecificColorShades("gray", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
red: getSpecificColorShades("red", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
pink: getSpecificColorShades("pink", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
grape: getSpecificColorShades("grape", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
violet: getSpecificColorShades("violet", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
blue: getSpecificColorShades("blue", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
cyan: getSpecificColorShades("cyan", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
teal: getSpecificColorShades("teal", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
green: getSpecificColorShades("green", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
yellow: getSpecificColorShades("yellow", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
orange: getSpecificColorShades("orange", ELEMENTS_PALETTE_SHADE_INDEXES),
|
||||
// radix bronze shades 3,5,7,9,11
|
||||
bronze: ["#f8f1ee", "#eaddd7", "#d2bab0", "#a18072", "#846358"],
|
||||
} as ColorPalette;
|
||||
|
||||
const COMMON_ELEMENT_SHADES = pick(COLOR_PALETTE, [
|
||||
"cyan",
|
||||
"blue",
|
||||
"violet",
|
||||
"grape",
|
||||
"pink",
|
||||
"green",
|
||||
"teal",
|
||||
"yellow",
|
||||
"orange",
|
||||
"red",
|
||||
]);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// quick picks defaults
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ORDER matters for positioning in quick picker
|
||||
export const DEFAULT_ELEMENT_STROKE_PICKS = [
|
||||
COLOR_PALETTE.black,
|
||||
COLOR_PALETTE.red[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
|
||||
COLOR_PALETTE.green[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
|
||||
COLOR_PALETTE.blue[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
|
||||
COLOR_PALETTE.yellow[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
|
||||
] as ColorTuple;
|
||||
|
||||
// ORDER matters for positioning in quick picker
|
||||
export const DEFAULT_ELEMENT_BACKGROUND_PICKS = [
|
||||
COLOR_PALETTE.transparent,
|
||||
COLOR_PALETTE.red[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
|
||||
COLOR_PALETTE.green[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
|
||||
COLOR_PALETTE.blue[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
|
||||
COLOR_PALETTE.yellow[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
|
||||
] as ColorTuple;
|
||||
|
||||
// ORDER matters for positioning in quick picker
|
||||
export const DEFAULT_CANVAS_BACKGROUND_PICKS = [
|
||||
COLOR_PALETTE.white,
|
||||
// radix slate2
|
||||
"#f8f9fa",
|
||||
// radix blue2
|
||||
"#f5faff",
|
||||
// radix yellow2
|
||||
"#fffce8",
|
||||
// radix bronze2
|
||||
"#fdf8f6",
|
||||
] as ColorTuple;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// palette defaults
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
export const DEFAULT_ELEMENT_STROKE_COLOR_PALETTE = {
|
||||
// 1st row
|
||||
transparent: COLOR_PALETTE.transparent,
|
||||
white: COLOR_PALETTE.white,
|
||||
gray: COLOR_PALETTE.gray,
|
||||
black: COLOR_PALETTE.black,
|
||||
bronze: COLOR_PALETTE.bronze,
|
||||
// rest
|
||||
...COMMON_ELEMENT_SHADES,
|
||||
} as const;
|
||||
|
||||
// ORDER matters for positioning in pallete (5x3 grid)s
|
||||
export const DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE = {
|
||||
transparent: COLOR_PALETTE.transparent,
|
||||
white: COLOR_PALETTE.white,
|
||||
gray: COLOR_PALETTE.gray,
|
||||
black: COLOR_PALETTE.black,
|
||||
bronze: COLOR_PALETTE.bronze,
|
||||
|
||||
...COMMON_ELEMENT_SHADES,
|
||||
} as const;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// !!!MUST BE WITHOUT GRAY, TRANSPARENT AND BLACK!!!
|
||||
export const getAllColorsSpecificShade = (index: 0 | 1 | 2 | 3 | 4) =>
|
||||
[
|
||||
// 2nd row
|
||||
COLOR_PALETTE.cyan[index],
|
||||
COLOR_PALETTE.blue[index],
|
||||
COLOR_PALETTE.violet[index],
|
||||
COLOR_PALETTE.grape[index],
|
||||
COLOR_PALETTE.pink[index],
|
||||
|
||||
// 3rd row
|
||||
COLOR_PALETTE.green[index],
|
||||
COLOR_PALETTE.teal[index],
|
||||
COLOR_PALETTE.yellow[index],
|
||||
COLOR_PALETTE.orange[index],
|
||||
COLOR_PALETTE.red[index],
|
||||
] as const;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -33,7 +33,7 @@ import {
|
|||
actionBindText,
|
||||
actionUngroup,
|
||||
actionLink,
|
||||
actionToggleLock,
|
||||
actionToggleElementLock,
|
||||
actionToggleLinearEditor,
|
||||
} from "../actions";
|
||||
import { createRedoAction, createUndoAction } from "../actions/actionHistory";
|
||||
|
@ -59,6 +59,7 @@ import {
|
|||
ELEMENT_TRANSLATE_AMOUNT,
|
||||
ENV,
|
||||
EVENT,
|
||||
EXPORT_IMAGE_TYPES,
|
||||
GRID_SIZE,
|
||||
IMAGE_MIME_TYPES,
|
||||
IMAGE_RENDER_TIMEOUT,
|
||||
|
@ -82,7 +83,7 @@ import {
|
|||
VERTICAL_ALIGN,
|
||||
ZOOM_STEP,
|
||||
} from "../constants";
|
||||
import { loadFromBlob } from "../data";
|
||||
import { exportCanvas, loadFromBlob } from "../data";
|
||||
import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
|
||||
import { restore, restoreElements } from "../data/restore";
|
||||
import {
|
||||
|
@ -238,6 +239,7 @@ import {
|
|||
getShortcutKey,
|
||||
isTransparent,
|
||||
easeToValuesRAF,
|
||||
muteFSAbortError,
|
||||
} from "../utils";
|
||||
import {
|
||||
ContextMenu,
|
||||
|
@ -252,6 +254,7 @@ import {
|
|||
generateIdFromFile,
|
||||
getDataURL,
|
||||
getFileFromEvent,
|
||||
isImageFileHandle,
|
||||
isSupportedImageFile,
|
||||
loadSceneOrLibraryFromBlob,
|
||||
normalizeFile,
|
||||
|
@ -291,6 +294,7 @@ import {
|
|||
isLocalLink,
|
||||
} from "../element/Hyperlink";
|
||||
import { shouldShowBoundingBox } from "../element/transformHandles";
|
||||
import { actionUnlockAllElements } from "../actions/actionElementLock";
|
||||
import { Fonts } from "../scene/Fonts";
|
||||
import { actionPaste } from "../actions/actionClipboard";
|
||||
import {
|
||||
|
@ -310,6 +314,7 @@ const deviceContextInitialValue = {
|
|||
isMobile: false,
|
||||
isTouchScreen: false,
|
||||
canDeviceFitSidebar: false,
|
||||
isLandscape: false,
|
||||
};
|
||||
const DeviceContext = React.createContext<Device>(deviceContextInitialValue);
|
||||
DeviceContext.displayName = "DeviceContext";
|
||||
|
@ -618,6 +623,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
}
|
||||
UIOptions={this.props.UIOptions}
|
||||
onImageAction={this.onImageAction}
|
||||
onExportImage={this.onExportImage}
|
||||
renderWelcomeScreen={
|
||||
!this.state.isLoading &&
|
||||
this.state.showWelcomeScreen &&
|
||||
|
@ -657,7 +663,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
)}
|
||||
<main>{this.renderCanvas()}</main>
|
||||
</ExcalidrawActionManagerContext.Provider>
|
||||
</ExcalidrawElementsContext.Provider>{" "}
|
||||
</ExcalidrawElementsContext.Provider>
|
||||
</ExcalidrawAppStateContext.Provider>
|
||||
</ExcalidrawSetAppStateContext.Provider>
|
||||
</DeviceContext.Provider>
|
||||
|
@ -688,6 +694,37 @@ class App extends React.Component<AppProps, AppState> {
|
|||
});
|
||||
};
|
||||
|
||||
public onExportImage = async (
|
||||
type: keyof typeof EXPORT_IMAGE_TYPES,
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
) => {
|
||||
trackEvent("export", type, "ui");
|
||||
const fileHandle = await exportCanvas(
|
||||
type,
|
||||
elements,
|
||||
this.state,
|
||||
this.files,
|
||||
{
|
||||
exportBackground: this.state.exportBackground,
|
||||
name: this.state.name,
|
||||
viewBackgroundColor: this.state.viewBackgroundColor,
|
||||
},
|
||||
)
|
||||
.catch(muteFSAbortError)
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
this.setState({ errorMessage: error.message });
|
||||
});
|
||||
|
||||
if (
|
||||
this.state.exportEmbedScene &&
|
||||
fileHandle &&
|
||||
isImageFileHandle(fileHandle)
|
||||
) {
|
||||
this.setState({ fileHandle });
|
||||
}
|
||||
};
|
||||
|
||||
private syncActionResult = withBatchedUpdates(
|
||||
(actionResult: ActionResult) => {
|
||||
if (this.unmounted || actionResult === false) {
|
||||
|
@ -912,6 +949,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
? this.props.UIOptions.dockedSidebarBreakpoint
|
||||
: MQ_RIGHT_SIDEBAR_MIN_WIDTH;
|
||||
this.device = updateObject(this.device, {
|
||||
isLandscape: width > height,
|
||||
isSmScreen: width < MQ_SM_MAX_WIDTH,
|
||||
isMobile:
|
||||
width < MQ_MAX_WIDTH_PORTRAIT ||
|
||||
|
@ -2289,11 +2327,11 @@ class App extends React.Component<AppProps, AppState> {
|
|||
(hasBackground(this.state.activeTool.type) ||
|
||||
selectedElements.some((element) => hasBackground(element.type)))
|
||||
) {
|
||||
this.setState({ openPopup: "backgroundColorPicker" });
|
||||
this.setState({ openPopup: "elementBackground" });
|
||||
event.stopPropagation();
|
||||
}
|
||||
if (event.key === KEYS.S) {
|
||||
this.setState({ openPopup: "strokeColorPicker" });
|
||||
this.setState({ openPopup: "elementStroke" });
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
@ -6349,6 +6387,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
copyText,
|
||||
CONTEXT_MENU_SEPARATOR,
|
||||
actionSelectAll,
|
||||
actionUnlockAllElements,
|
||||
CONTEXT_MENU_SEPARATOR,
|
||||
actionToggleGridMode,
|
||||
actionToggleZenMode,
|
||||
|
@ -6395,7 +6434,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||
actionToggleLinearEditor,
|
||||
actionLink,
|
||||
actionDuplicateSelection,
|
||||
actionToggleLock,
|
||||
actionToggleElementLock,
|
||||
CONTEXT_MENU_SEPARATOR,
|
||||
actionDeleteSelected,
|
||||
];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import "./Avatar.scss";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { getClientInitials } from "../clients";
|
||||
import { getNameInitial } from "../clients";
|
||||
|
||||
type AvatarProps = {
|
||||
onClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
|
@ -12,7 +12,7 @@ type AvatarProps = {
|
|||
};
|
||||
|
||||
export const Avatar = ({ color, onClick, name, src }: AvatarProps) => {
|
||||
const shortName = getClientInitials(name);
|
||||
const shortName = getNameInitial(name);
|
||||
const [error, setError] = useState(false);
|
||||
const loadImg = !error && src;
|
||||
const style = loadImg ? undefined : { background: color };
|
||||
|
|
|
@ -1,430 +0,0 @@
|
|||
import React from "react";
|
||||
import { Popover } from "./Popover";
|
||||
import { isTransparent } from "../utils";
|
||||
|
||||
import "./ColorPicker.scss";
|
||||
import { isArrowKey, KEYS } from "../keys";
|
||||
import { t, getLanguage } from "../i18n";
|
||||
import { isWritableElement } from "../utils";
|
||||
import colors from "../colors";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState } from "../types";
|
||||
|
||||
const MAX_CUSTOM_COLORS = 5;
|
||||
const MAX_DEFAULT_COLORS = 15;
|
||||
|
||||
export const getCustomColors = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
type: "elementBackground" | "elementStroke",
|
||||
) => {
|
||||
const customColors: string[] = [];
|
||||
const updatedElements = elements
|
||||
.filter((element) => !element.isDeleted)
|
||||
.sort((ele1, ele2) => ele2.updated - ele1.updated);
|
||||
|
||||
let index = 0;
|
||||
const elementColorTypeMap = {
|
||||
elementBackground: "backgroundColor",
|
||||
elementStroke: "strokeColor",
|
||||
};
|
||||
const colorType = elementColorTypeMap[type] as
|
||||
| "backgroundColor"
|
||||
| "strokeColor";
|
||||
while (
|
||||
index < updatedElements.length &&
|
||||
customColors.length < MAX_CUSTOM_COLORS
|
||||
) {
|
||||
const element = updatedElements[index];
|
||||
|
||||
if (
|
||||
customColors.length < MAX_CUSTOM_COLORS &&
|
||||
isCustomColor(element[colorType], type) &&
|
||||
!customColors.includes(element[colorType])
|
||||
) {
|
||||
customColors.push(element[colorType]);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return customColors;
|
||||
};
|
||||
|
||||
const isCustomColor = (
|
||||
color: string,
|
||||
type: "elementBackground" | "elementStroke",
|
||||
) => {
|
||||
return !colors[type].includes(color);
|
||||
};
|
||||
|
||||
const isValidColor = (color: string) => {
|
||||
const style = new Option().style;
|
||||
style.color = color;
|
||||
return !!style.color;
|
||||
};
|
||||
|
||||
const getColor = (color: string): string | null => {
|
||||
if (isTransparent(color)) {
|
||||
return color;
|
||||
}
|
||||
|
||||
// testing for `#` first fixes a bug on Electron (more specfically, an
|
||||
// Obsidian popout window), where a hex color without `#` is (incorrectly)
|
||||
// considered valid
|
||||
return isValidColor(`#${color}`)
|
||||
? `#${color}`
|
||||
: isValidColor(color)
|
||||
? color
|
||||
: null;
|
||||
};
|
||||
|
||||
// This is a narrow reimplementation of the awesome react-color Twitter component
|
||||
// https://github.com/casesandberg/react-color/blob/master/src/components/twitter/Twitter.js
|
||||
|
||||
// Unfortunately, we can't detect keyboard layout in the browser. So this will
|
||||
// only work well for QWERTY but not AZERTY or others...
|
||||
const keyBindings = [
|
||||
["1", "2", "3", "4", "5"],
|
||||
["q", "w", "e", "r", "t"],
|
||||
["a", "s", "d", "f", "g"],
|
||||
["z", "x", "c", "v", "b"],
|
||||
].flat();
|
||||
|
||||
const Picker = ({
|
||||
colors,
|
||||
color,
|
||||
onChange,
|
||||
onClose,
|
||||
label,
|
||||
showInput = true,
|
||||
type,
|
||||
elements,
|
||||
}: {
|
||||
colors: string[];
|
||||
color: string | null;
|
||||
onChange: (color: string) => void;
|
||||
onClose: () => void;
|
||||
label: string;
|
||||
showInput: boolean;
|
||||
type: "canvasBackground" | "elementBackground" | "elementStroke";
|
||||
elements: readonly ExcalidrawElement[];
|
||||
}) => {
|
||||
const firstItem = React.useRef<HTMLButtonElement>();
|
||||
const activeItem = React.useRef<HTMLButtonElement>();
|
||||
const gallery = React.useRef<HTMLDivElement>();
|
||||
const colorInput = React.useRef<HTMLInputElement>();
|
||||
|
||||
const [customColors] = React.useState(() => {
|
||||
if (type === "canvasBackground") {
|
||||
return [];
|
||||
}
|
||||
return getCustomColors(elements, type);
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
// After the component is first mounted focus on first input
|
||||
if (activeItem.current) {
|
||||
activeItem.current.focus();
|
||||
} else if (colorInput.current) {
|
||||
colorInput.current.focus();
|
||||
} else if (gallery.current) {
|
||||
gallery.current.focus();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent) => {
|
||||
let handled = false;
|
||||
if (isArrowKey(event.key)) {
|
||||
handled = true;
|
||||
const { activeElement } = document;
|
||||
const isRTL = getLanguage().rtl;
|
||||
let isCustom = false;
|
||||
let index = Array.prototype.indexOf.call(
|
||||
gallery.current!.querySelector(".color-picker-content--default")
|
||||
?.children,
|
||||
activeElement,
|
||||
);
|
||||
if (index === -1) {
|
||||
index = Array.prototype.indexOf.call(
|
||||
gallery.current!.querySelector(".color-picker-content--canvas-colors")
|
||||
?.children,
|
||||
activeElement,
|
||||
);
|
||||
if (index !== -1) {
|
||||
isCustom = true;
|
||||
}
|
||||
}
|
||||
const parentElement = isCustom
|
||||
? gallery.current?.querySelector(".color-picker-content--canvas-colors")
|
||||
: gallery.current?.querySelector(".color-picker-content--default");
|
||||
|
||||
if (parentElement && index !== -1) {
|
||||
const length = parentElement.children.length - (showInput ? 1 : 0);
|
||||
const nextIndex =
|
||||
event.key === (isRTL ? KEYS.ARROW_LEFT : KEYS.ARROW_RIGHT)
|
||||
? (index + 1) % length
|
||||
: event.key === (isRTL ? KEYS.ARROW_RIGHT : KEYS.ARROW_LEFT)
|
||||
? (length + index - 1) % length
|
||||
: !isCustom && event.key === KEYS.ARROW_DOWN
|
||||
? (index + 5) % length
|
||||
: !isCustom && event.key === KEYS.ARROW_UP
|
||||
? (length + index - 5) % length
|
||||
: index;
|
||||
(parentElement.children[nextIndex] as HTMLElement | undefined)?.focus();
|
||||
}
|
||||
event.preventDefault();
|
||||
} else if (
|
||||
keyBindings.includes(event.key.toLowerCase()) &&
|
||||
!event[KEYS.CTRL_OR_CMD] &&
|
||||
!event.altKey &&
|
||||
!isWritableElement(event.target)
|
||||
) {
|
||||
handled = true;
|
||||
const index = keyBindings.indexOf(event.key.toLowerCase());
|
||||
const isCustom = index >= MAX_DEFAULT_COLORS;
|
||||
const parentElement = isCustom
|
||||
? gallery?.current?.querySelector(
|
||||
".color-picker-content--canvas-colors",
|
||||
)
|
||||
: gallery?.current?.querySelector(".color-picker-content--default");
|
||||
const actualIndex = isCustom ? index - MAX_DEFAULT_COLORS : index;
|
||||
(
|
||||
parentElement?.children[actualIndex] as HTMLElement | undefined
|
||||
)?.focus();
|
||||
|
||||
event.preventDefault();
|
||||
} else if (event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) {
|
||||
handled = true;
|
||||
event.preventDefault();
|
||||
onClose();
|
||||
}
|
||||
if (handled) {
|
||||
event.nativeEvent.stopImmediatePropagation();
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
const renderColors = (colors: Array<string>, custom: boolean = false) => {
|
||||
return colors.map((_color, i) => {
|
||||
const _colorWithoutHash = _color.replace("#", "");
|
||||
const keyBinding = custom
|
||||
? keyBindings[i + MAX_DEFAULT_COLORS]
|
||||
: keyBindings[i];
|
||||
const label = custom
|
||||
? _colorWithoutHash
|
||||
: t(`colors.${_colorWithoutHash}`);
|
||||
return (
|
||||
<button
|
||||
className="color-picker-swatch"
|
||||
onClick={(event) => {
|
||||
(event.currentTarget as HTMLButtonElement).focus();
|
||||
onChange(_color);
|
||||
}}
|
||||
title={`${label}${
|
||||
!isTransparent(_color) ? ` (${_color})` : ""
|
||||
} — ${keyBinding.toUpperCase()}`}
|
||||
aria-label={label}
|
||||
aria-keyshortcuts={keyBindings[i]}
|
||||
style={{ color: _color }}
|
||||
key={_color}
|
||||
ref={(el) => {
|
||||
if (!custom && el && i === 0) {
|
||||
firstItem.current = el;
|
||||
}
|
||||
if (el && _color === color) {
|
||||
activeItem.current = el;
|
||||
}
|
||||
}}
|
||||
onFocus={() => {
|
||||
onChange(_color);
|
||||
}}
|
||||
>
|
||||
{isTransparent(_color) ? (
|
||||
<div className="color-picker-transparent"></div>
|
||||
) : undefined}
|
||||
<span className="color-picker-keybinding">{keyBinding}</span>
|
||||
</button>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`color-picker color-picker-type-${type}`}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label={t("labels.colorPicker")}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<div className="color-picker-triangle color-picker-triangle-shadow"></div>
|
||||
<div className="color-picker-triangle"></div>
|
||||
<div
|
||||
className="color-picker-content"
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
gallery.current = el;
|
||||
}
|
||||
}}
|
||||
// to allow focusing by clicking but not by tabbing
|
||||
tabIndex={-1}
|
||||
>
|
||||
<div className="color-picker-content--default">
|
||||
{renderColors(colors)}
|
||||
</div>
|
||||
{!!customColors.length && (
|
||||
<div className="color-picker-content--canvas">
|
||||
<span className="color-picker-content--canvas-title">
|
||||
{t("labels.canvasColors")}
|
||||
</span>
|
||||
<div className="color-picker-content--canvas-colors">
|
||||
{renderColors(customColors, true)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showInput && (
|
||||
<ColorInput
|
||||
color={color}
|
||||
label={label}
|
||||
onChange={(color) => {
|
||||
onChange(color);
|
||||
}}
|
||||
ref={colorInput}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ColorInput = React.forwardRef(
|
||||
(
|
||||
{
|
||||
color,
|
||||
onChange,
|
||||
label,
|
||||
}: {
|
||||
color: string | null;
|
||||
onChange: (color: string) => void;
|
||||
label: string;
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const [innerValue, setInnerValue] = React.useState(color);
|
||||
const inputRef = React.useRef(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
setInnerValue(color);
|
||||
}, [color]);
|
||||
|
||||
React.useImperativeHandle(ref, () => inputRef.current);
|
||||
|
||||
const changeColor = React.useCallback(
|
||||
(inputValue: string) => {
|
||||
const value = inputValue.toLowerCase();
|
||||
const color = getColor(value);
|
||||
if (color) {
|
||||
onChange(color);
|
||||
}
|
||||
setInnerValue(value);
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<label className="color-input-container">
|
||||
<div className="color-picker-hash">#</div>
|
||||
<input
|
||||
spellCheck={false}
|
||||
className="color-picker-input"
|
||||
aria-label={label}
|
||||
onChange={(event) => changeColor(event.target.value)}
|
||||
value={(innerValue || "").replace(/^#/, "")}
|
||||
onBlur={() => setInnerValue(color)}
|
||||
ref={inputRef}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
ColorInput.displayName = "ColorInput";
|
||||
|
||||
export const ColorPicker = ({
|
||||
type,
|
||||
color,
|
||||
onChange,
|
||||
label,
|
||||
isActive,
|
||||
setActive,
|
||||
elements,
|
||||
appState,
|
||||
}: {
|
||||
type: "canvasBackground" | "elementBackground" | "elementStroke";
|
||||
color: string | null;
|
||||
onChange: (color: string) => void;
|
||||
label: string;
|
||||
isActive: boolean;
|
||||
setActive: (active: boolean) => void;
|
||||
elements: readonly ExcalidrawElement[];
|
||||
appState: AppState;
|
||||
}) => {
|
||||
const pickerButton = React.useRef<HTMLButtonElement>(null);
|
||||
const coords = pickerButton.current?.getBoundingClientRect();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="color-picker-control-container">
|
||||
<div className="color-picker-label-swatch-container">
|
||||
<button
|
||||
className="color-picker-label-swatch"
|
||||
aria-label={label}
|
||||
style={color ? { "--swatch-color": color } : undefined}
|
||||
onClick={() => setActive(!isActive)}
|
||||
ref={pickerButton}
|
||||
/>
|
||||
</div>
|
||||
<ColorInput
|
||||
color={color}
|
||||
label={label}
|
||||
onChange={(color) => {
|
||||
onChange(color);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<React.Suspense fallback="">
|
||||
{isActive ? (
|
||||
<div
|
||||
className="color-picker-popover-container"
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: coords?.top,
|
||||
left: coords?.right,
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<Popover
|
||||
onCloseRequest={(event) =>
|
||||
event.target !== pickerButton.current && setActive(false)
|
||||
}
|
||||
>
|
||||
<Picker
|
||||
colors={colors[type]}
|
||||
color={color || null}
|
||||
onChange={(changedColor) => {
|
||||
onChange(changedColor);
|
||||
}}
|
||||
onClose={() => {
|
||||
setActive(false);
|
||||
pickerButton.current?.focus();
|
||||
}}
|
||||
label={label}
|
||||
showInput={false}
|
||||
type={type}
|
||||
elements={elements}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
) : null}
|
||||
</React.Suspense>
|
||||
</div>
|
||||
);
|
||||
};
|
75
src/components/ColorPicker/ColorInput.tsx
Normal file
75
src/components/ColorPicker/ColorInput.tsx
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { getColor } from "./ColorPicker";
|
||||
import { useAtom } from "jotai";
|
||||
import { activeColorPickerSectionAtom } from "./colorPickerUtils";
|
||||
import { KEYS } from "../../keys";
|
||||
|
||||
interface ColorInputProps {
|
||||
color: string | null;
|
||||
onChange: (color: string) => void;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const ColorInput = ({ color, onChange, label }: ColorInputProps) => {
|
||||
const [innerValue, setInnerValue] = useState(color);
|
||||
const [activeSection, setActiveColorPickerSection] = useAtom(
|
||||
activeColorPickerSectionAtom,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setInnerValue(color);
|
||||
}, [color]);
|
||||
|
||||
const changeColor = useCallback(
|
||||
(inputValue: string) => {
|
||||
const value = inputValue.toLowerCase();
|
||||
const color = getColor(value);
|
||||
|
||||
if (color) {
|
||||
onChange(color);
|
||||
}
|
||||
setInnerValue(value);
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const divRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}, [activeSection]);
|
||||
|
||||
return (
|
||||
<label className="color-picker__input-label">
|
||||
<div className="color-picker__input-hash">#</div>
|
||||
<input
|
||||
ref={activeSection === "hex" ? inputRef : undefined}
|
||||
style={{ border: 0, padding: 0 }}
|
||||
spellCheck={false}
|
||||
className="color-picker-input"
|
||||
aria-label={label}
|
||||
onChange={(event) => {
|
||||
changeColor(event.target.value);
|
||||
}}
|
||||
value={(innerValue || "").replace(/^#/, "")}
|
||||
onBlur={() => {
|
||||
setInnerValue(color);
|
||||
}}
|
||||
tabIndex={-1}
|
||||
onFocus={() => setActiveColorPickerSection("hex")}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === KEYS.TAB) {
|
||||
return;
|
||||
}
|
||||
if (e.key === KEYS.ESCAPE) {
|
||||
divRef.current?.focus();
|
||||
}
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
};
|
|
@ -1,6 +1,134 @@
|
|||
@import "../css/variables.module";
|
||||
@import "../../css/variables.module";
|
||||
|
||||
.excalidraw {
|
||||
.focus-visible-none {
|
||||
&:focus-visible {
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.color-picker__heading {
|
||||
padding: 0 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.color-picker-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 20px 1.625rem;
|
||||
padding: 0.25rem 0px;
|
||||
align-items: center;
|
||||
|
||||
@include isMobile {
|
||||
max-width: 175px;
|
||||
}
|
||||
}
|
||||
|
||||
.color-picker__top-picks {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.color-picker__button {
|
||||
--radius: 0.25rem;
|
||||
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 1.35rem;
|
||||
height: 1.35rem;
|
||||
border: 1px solid var(--color-gray-30);
|
||||
border-radius: var(--radius);
|
||||
filter: var(--theme-filter);
|
||||
background-color: var(--swatch-color);
|
||||
background-position: left center;
|
||||
position: relative;
|
||||
font-family: inherit;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
box-shadow: 0 0 0 1px var(--color-gray-30);
|
||||
border-radius: calc(var(--radius) + 1px);
|
||||
filter: var(--theme-filter);
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
.color-picker__button-outline {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
box-shadow: 0 0 0 1px var(--color-primary-darkest);
|
||||
z-index: 1; // due hover state so this has preference
|
||||
border-radius: calc(var(--radius) + 1px);
|
||||
filter: var(--theme-filter);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -4px;
|
||||
bottom: -4px;
|
||||
left: -4px;
|
||||
border: 3px solid var(--focus-highlight-color);
|
||||
border-radius: calc(var(--radius) + 1px);
|
||||
}
|
||||
|
||||
&.active {
|
||||
.color-picker__button-outline {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--large {
|
||||
--radius: 0.5rem;
|
||||
width: 1.875rem;
|
||||
height: 1.875rem;
|
||||
}
|
||||
|
||||
&.is-transparent {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==");
|
||||
}
|
||||
|
||||
&--no-focus-visible {
|
||||
border: 0;
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.active-color {
|
||||
border-radius: calc(var(--radius) + 1px);
|
||||
width: 1.625rem;
|
||||
height: 1.625rem;
|
||||
}
|
||||
}
|
||||
|
||||
.color-picker__button__hotkey-label {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
bottom: 4px;
|
||||
filter: none;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.color-picker {
|
||||
background: var(--popup-bg-color);
|
||||
border: 0 solid transparentize($oc-white, 0.75);
|
||||
|
@ -72,11 +200,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
.color-picker-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.color-picker-content--default {
|
||||
padding: 0.5rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, auto);
|
||||
grid-gap: 0.5rem;
|
||||
grid-template-columns: repeat(5, 1.875rem);
|
||||
grid-gap: 0.25rem;
|
||||
border-radius: 4px;
|
||||
|
||||
&:focus {
|
||||
|
@ -178,6 +312,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
.color-picker__input-label {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto auto;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
border: 1px solid var(--default-border-color);
|
||||
border-radius: 8px;
|
||||
padding: 0 12px;
|
||||
margin: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:focus-within {
|
||||
box-shadow: 0 0 0 1px var(--color-primary-darkest);
|
||||
border-radius: var(--border-radius-lg);
|
||||
}
|
||||
}
|
||||
|
||||
.color-picker__input-hash {
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.color-picker-input {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
235
src/components/ColorPicker/ColorPicker.tsx
Normal file
235
src/components/ColorPicker/ColorPicker.tsx
Normal file
|
@ -0,0 +1,235 @@
|
|||
import { isTransparent } from "../../utils";
|
||||
import { ExcalidrawElement } from "../../element/types";
|
||||
import { AppState } from "../../types";
|
||||
import { TopPicks } from "./TopPicks";
|
||||
import { Picker } from "./Picker";
|
||||
import * as Popover from "@radix-ui/react-popover";
|
||||
import { useAtom } from "jotai";
|
||||
import {
|
||||
activeColorPickerSectionAtom,
|
||||
ColorPickerType,
|
||||
} from "./colorPickerUtils";
|
||||
import { useDevice, useExcalidrawContainer } from "../App";
|
||||
import { ColorTuple, COLOR_PALETTE, ColorPaletteCustom } from "../../colors";
|
||||
import PickerHeading from "./PickerHeading";
|
||||
import { ColorInput } from "./ColorInput";
|
||||
import { t } from "../../i18n";
|
||||
import clsx from "clsx";
|
||||
|
||||
import "./ColorPicker.scss";
|
||||
import React from "react";
|
||||
|
||||
const isValidColor = (color: string) => {
|
||||
const style = new Option().style;
|
||||
style.color = color;
|
||||
return !!style.color;
|
||||
};
|
||||
|
||||
export const getColor = (color: string): string | null => {
|
||||
if (isTransparent(color)) {
|
||||
return color;
|
||||
}
|
||||
|
||||
// testing for `#` first fixes a bug on Electron (more specfically, an
|
||||
// Obsidian popout window), where a hex color without `#` is (incorrectly)
|
||||
// considered valid
|
||||
return isValidColor(`#${color}`)
|
||||
? `#${color}`
|
||||
: isValidColor(color)
|
||||
? color
|
||||
: null;
|
||||
};
|
||||
|
||||
export interface ColorPickerProps {
|
||||
type: ColorPickerType;
|
||||
color: string | null;
|
||||
onChange: (color: string) => void;
|
||||
label: string;
|
||||
elements: readonly ExcalidrawElement[];
|
||||
appState: AppState;
|
||||
palette?: ColorPaletteCustom | null;
|
||||
topPicks?: ColorTuple;
|
||||
updateData: (formData?: any) => void;
|
||||
}
|
||||
|
||||
const ColorPickerPopupContent = ({
|
||||
type,
|
||||
color,
|
||||
onChange,
|
||||
label,
|
||||
elements,
|
||||
palette = COLOR_PALETTE,
|
||||
updateData,
|
||||
}: Pick<
|
||||
ColorPickerProps,
|
||||
| "type"
|
||||
| "color"
|
||||
| "onChange"
|
||||
| "label"
|
||||
| "label"
|
||||
| "elements"
|
||||
| "palette"
|
||||
| "updateData"
|
||||
>) => {
|
||||
const [, setActiveColorPickerSection] = useAtom(activeColorPickerSectionAtom);
|
||||
|
||||
const { container } = useExcalidrawContainer();
|
||||
const { isMobile, isLandscape } = useDevice();
|
||||
|
||||
const colorInputJSX = (
|
||||
<div>
|
||||
<PickerHeading>{t("colorPicker.hexCode")}</PickerHeading>
|
||||
<ColorInput
|
||||
color={color}
|
||||
label={label}
|
||||
onChange={(color) => {
|
||||
onChange(color);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover.Portal container={container}>
|
||||
<Popover.Content
|
||||
className="focus-visible-none"
|
||||
data-prevent-outside-click
|
||||
onCloseAutoFocus={(e) => {
|
||||
// return focus to excalidraw container
|
||||
if (container) {
|
||||
container.focus();
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
setActiveColorPickerSection(null);
|
||||
}}
|
||||
side={isMobile && !isLandscape ? "bottom" : "right"}
|
||||
align={isMobile && !isLandscape ? "center" : "start"}
|
||||
alignOffset={-16}
|
||||
sideOffset={20}
|
||||
style={{
|
||||
zIndex: 9999,
|
||||
backgroundColor: "var(--popup-bg-color)",
|
||||
maxWidth: "208px",
|
||||
maxHeight: window.innerHeight,
|
||||
padding: "12px",
|
||||
borderRadius: "8px",
|
||||
boxSizing: "border-box",
|
||||
overflowY: "auto",
|
||||
boxShadow:
|
||||
"0px 7px 14px rgba(0, 0, 0, 0.05), 0px 0px 3.12708px rgba(0, 0, 0, 0.0798), 0px 0px 0.931014px rgba(0, 0, 0, 0.1702)",
|
||||
}}
|
||||
>
|
||||
{palette ? (
|
||||
<Picker
|
||||
palette={palette}
|
||||
color={color || null}
|
||||
onChange={(changedColor) => {
|
||||
onChange(changedColor);
|
||||
}}
|
||||
label={label}
|
||||
type={type}
|
||||
elements={elements}
|
||||
updateData={updateData}
|
||||
>
|
||||
{colorInputJSX}
|
||||
</Picker>
|
||||
) : (
|
||||
colorInputJSX
|
||||
)}
|
||||
<Popover.Arrow
|
||||
width={20}
|
||||
height={10}
|
||||
style={{
|
||||
fill: "var(--popup-bg-color)",
|
||||
filter: "drop-shadow(rgba(0, 0, 0, 0.05) 0px 3px 2px)",
|
||||
}}
|
||||
/>
|
||||
</Popover.Content>
|
||||
</Popover.Portal>
|
||||
);
|
||||
};
|
||||
|
||||
const ColorPickerTrigger = ({
|
||||
label,
|
||||
color,
|
||||
type,
|
||||
}: {
|
||||
color: string | null;
|
||||
label: string;
|
||||
type: ColorPickerType;
|
||||
}) => {
|
||||
return (
|
||||
<Popover.Trigger
|
||||
type="button"
|
||||
className={clsx("color-picker__button active-color", {
|
||||
"is-transparent": color === "transparent" || !color,
|
||||
})}
|
||||
aria-label={label}
|
||||
style={color ? { "--swatch-color": color } : undefined}
|
||||
title={
|
||||
type === "elementStroke"
|
||||
? t("labels.showStroke")
|
||||
: t("labels.showBackground")
|
||||
}
|
||||
>
|
||||
<div className="color-picker__button-outline" />
|
||||
</Popover.Trigger>
|
||||
);
|
||||
};
|
||||
|
||||
export const ColorPicker = ({
|
||||
type,
|
||||
color,
|
||||
onChange,
|
||||
label,
|
||||
elements,
|
||||
palette = COLOR_PALETTE,
|
||||
topPicks,
|
||||
updateData,
|
||||
appState,
|
||||
}: ColorPickerProps) => {
|
||||
return (
|
||||
<div>
|
||||
<div role="dialog" aria-modal="true" className="color-picker-container">
|
||||
<TopPicks
|
||||
activeColor={color}
|
||||
onChange={onChange}
|
||||
type={type}
|
||||
topPicks={topPicks}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: 1,
|
||||
height: "100%",
|
||||
backgroundColor: "var(--default-border-color)",
|
||||
margin: "0 auto",
|
||||
}}
|
||||
/>
|
||||
<Popover.Root
|
||||
open={appState.openPopup === type}
|
||||
onOpenChange={(open) => {
|
||||
updateData({ openPopup: open ? type : null });
|
||||
}}
|
||||
>
|
||||
{/* serves as an active color indicator as well */}
|
||||
<ColorPickerTrigger color={color} label={label} type={type} />
|
||||
{/* popup content */}
|
||||
{appState.openPopup === type && (
|
||||
<ColorPickerPopupContent
|
||||
type={type}
|
||||
color={color}
|
||||
onChange={onChange}
|
||||
label={label}
|
||||
elements={elements}
|
||||
palette={palette}
|
||||
updateData={updateData}
|
||||
/>
|
||||
)}
|
||||
</Popover.Root>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
63
src/components/ColorPicker/CustomColorList.tsx
Normal file
63
src/components/ColorPicker/CustomColorList.tsx
Normal file
|
@ -0,0 +1,63 @@
|
|||
import clsx from "clsx";
|
||||
import { useAtom } from "jotai";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { activeColorPickerSectionAtom } from "./colorPickerUtils";
|
||||
import HotkeyLabel from "./HotkeyLabel";
|
||||
|
||||
interface CustomColorListProps {
|
||||
colors: string[];
|
||||
color: string | null;
|
||||
onChange: (color: string) => void;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const CustomColorList = ({
|
||||
colors,
|
||||
color,
|
||||
onChange,
|
||||
label,
|
||||
}: CustomColorListProps) => {
|
||||
const [activeColorPickerSection, setActiveColorPickerSection] = useAtom(
|
||||
activeColorPickerSectionAtom,
|
||||
);
|
||||
|
||||
const btnRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (btnRef.current) {
|
||||
btnRef.current.focus();
|
||||
}
|
||||
}, [color, activeColorPickerSection]);
|
||||
|
||||
return (
|
||||
<div className="color-picker-content--default">
|
||||
{colors.map((c, i) => {
|
||||
return (
|
||||
<button
|
||||
ref={color === c ? btnRef : undefined}
|
||||
tabIndex={-1}
|
||||
type="button"
|
||||
className={clsx(
|
||||
"color-picker__button color-picker__button--large",
|
||||
{
|
||||
active: color === c,
|
||||
"is-transparent": c === "transparent" || !c,
|
||||
},
|
||||
)}
|
||||
onClick={() => {
|
||||
onChange(c);
|
||||
setActiveColorPickerSection("custom");
|
||||
}}
|
||||
title={c}
|
||||
aria-label={label}
|
||||
style={{ "--swatch-color": c }}
|
||||
key={i}
|
||||
>
|
||||
<div className="color-picker__button-outline" />
|
||||
<HotkeyLabel color={c} keyLabel={i + 1} isCustomColor />
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
29
src/components/ColorPicker/HotkeyLabel.tsx
Normal file
29
src/components/ColorPicker/HotkeyLabel.tsx
Normal file
|
@ -0,0 +1,29 @@
|
|||
import React from "react";
|
||||
import { getContrastYIQ } from "./colorPickerUtils";
|
||||
|
||||
interface HotkeyLabelProps {
|
||||
color: string;
|
||||
keyLabel: string | number;
|
||||
isCustomColor?: boolean;
|
||||
isShade?: boolean;
|
||||
}
|
||||
const HotkeyLabel = ({
|
||||
color,
|
||||
keyLabel,
|
||||
isCustomColor = false,
|
||||
isShade = false,
|
||||
}: HotkeyLabelProps) => {
|
||||
return (
|
||||
<div
|
||||
className="color-picker__button__hotkey-label"
|
||||
style={{
|
||||
color: getContrastYIQ(color, isCustomColor),
|
||||
}}
|
||||
>
|
||||
{isShade && "⇧"}
|
||||
{keyLabel}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HotkeyLabel;
|
156
src/components/ColorPicker/Picker.tsx
Normal file
156
src/components/ColorPicker/Picker.tsx
Normal file
|
@ -0,0 +1,156 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { t } from "../../i18n";
|
||||
|
||||
import { ExcalidrawElement } from "../../element/types";
|
||||
import { ShadeList } from "./ShadeList";
|
||||
|
||||
import PickerColorList from "./PickerColorList";
|
||||
import { useAtom } from "jotai";
|
||||
import { CustomColorList } from "./CustomColorList";
|
||||
import { colorPickerKeyNavHandler } from "./keyboardNavHandlers";
|
||||
import PickerHeading from "./PickerHeading";
|
||||
import {
|
||||
ColorPickerType,
|
||||
activeColorPickerSectionAtom,
|
||||
getColorNameAndShadeFromHex,
|
||||
getMostUsedCustomColors,
|
||||
isCustomColor,
|
||||
} from "./colorPickerUtils";
|
||||
import {
|
||||
ColorPaletteCustom,
|
||||
DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX,
|
||||
DEFAULT_ELEMENT_STROKE_COLOR_INDEX,
|
||||
} from "../../colors";
|
||||
|
||||
interface PickerProps {
|
||||
color: string | null;
|
||||
onChange: (color: string) => void;
|
||||
label: string;
|
||||
type: ColorPickerType;
|
||||
elements: readonly ExcalidrawElement[];
|
||||
palette: ColorPaletteCustom;
|
||||
updateData: (formData?: any) => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Picker = ({
|
||||
color,
|
||||
onChange,
|
||||
label,
|
||||
type,
|
||||
elements,
|
||||
palette,
|
||||
updateData,
|
||||
children,
|
||||
}: PickerProps) => {
|
||||
const [customColors] = React.useState(() => {
|
||||
if (type === "canvasBackground") {
|
||||
return [];
|
||||
}
|
||||
return getMostUsedCustomColors(elements, type, palette);
|
||||
});
|
||||
|
||||
const [activeColorPickerSection, setActiveColorPickerSection] = useAtom(
|
||||
activeColorPickerSectionAtom,
|
||||
);
|
||||
|
||||
const colorObj = getColorNameAndShadeFromHex({
|
||||
hex: color || "transparent",
|
||||
palette,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeColorPickerSection) {
|
||||
const isCustom = isCustomColor({ color, palette });
|
||||
const isCustomButNotInList =
|
||||
isCustom && !customColors.includes(color || "");
|
||||
|
||||
setActiveColorPickerSection(
|
||||
isCustomButNotInList
|
||||
? "hex"
|
||||
: isCustom
|
||||
? "custom"
|
||||
: colorObj?.shade != null
|
||||
? "shades"
|
||||
: "baseColors",
|
||||
);
|
||||
}
|
||||
}, [
|
||||
activeColorPickerSection,
|
||||
color,
|
||||
palette,
|
||||
setActiveColorPickerSection,
|
||||
colorObj,
|
||||
customColors,
|
||||
]);
|
||||
|
||||
const [activeShade, setActiveShade] = useState(
|
||||
colorObj?.shade ??
|
||||
(type === "elementBackground"
|
||||
? DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX
|
||||
: DEFAULT_ELEMENT_STROKE_COLOR_INDEX),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (colorObj?.shade != null) {
|
||||
setActiveShade(colorObj.shade);
|
||||
}
|
||||
}, [colorObj]);
|
||||
|
||||
return (
|
||||
<div role="dialog" aria-modal="true" aria-label={t("labels.colorPicker")}>
|
||||
<div
|
||||
onKeyDown={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
colorPickerKeyNavHandler({
|
||||
e,
|
||||
activeColorPickerSection,
|
||||
palette,
|
||||
hex: color,
|
||||
onChange,
|
||||
customColors,
|
||||
setActiveColorPickerSection,
|
||||
updateData,
|
||||
activeShade,
|
||||
});
|
||||
}}
|
||||
className="color-picker-content"
|
||||
// to allow focusing by clicking but not by tabbing
|
||||
tabIndex={-1}
|
||||
>
|
||||
{!!customColors.length && (
|
||||
<div>
|
||||
<PickerHeading>
|
||||
{t("colorPicker.mostUsedCustomColors")}
|
||||
</PickerHeading>
|
||||
<CustomColorList
|
||||
colors={customColors}
|
||||
color={color}
|
||||
label={t("colorPicker.mostUsedCustomColors")}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<PickerHeading>{t("colorPicker.colors")}</PickerHeading>
|
||||
<PickerColorList
|
||||
color={color}
|
||||
label={label}
|
||||
palette={palette}
|
||||
onChange={onChange}
|
||||
activeShade={activeShade}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<PickerHeading>{t("colorPicker.shades")}</PickerHeading>
|
||||
<ShadeList hex={color} onChange={onChange} palette={palette} />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
86
src/components/ColorPicker/PickerColorList.tsx
Normal file
86
src/components/ColorPicker/PickerColorList.tsx
Normal file
|
@ -0,0 +1,86 @@
|
|||
import clsx from "clsx";
|
||||
import { useAtom } from "jotai";
|
||||
import { useEffect, useRef } from "react";
|
||||
import {
|
||||
activeColorPickerSectionAtom,
|
||||
colorPickerHotkeyBindings,
|
||||
getColorNameAndShadeFromHex,
|
||||
} from "./colorPickerUtils";
|
||||
import HotkeyLabel from "./HotkeyLabel";
|
||||
import { ColorPaletteCustom } from "../../colors";
|
||||
import { t } from "../../i18n";
|
||||
|
||||
interface PickerColorListProps {
|
||||
palette: ColorPaletteCustom;
|
||||
color: string | null;
|
||||
onChange: (color: string) => void;
|
||||
label: string;
|
||||
activeShade: number;
|
||||
}
|
||||
|
||||
const PickerColorList = ({
|
||||
palette,
|
||||
color,
|
||||
onChange,
|
||||
label,
|
||||
activeShade,
|
||||
}: PickerColorListProps) => {
|
||||
const colorObj = getColorNameAndShadeFromHex({
|
||||
hex: color || "transparent",
|
||||
palette,
|
||||
});
|
||||
const [activeColorPickerSection, setActiveColorPickerSection] = useAtom(
|
||||
activeColorPickerSectionAtom,
|
||||
);
|
||||
|
||||
const btnRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (btnRef.current && activeColorPickerSection === "baseColors") {
|
||||
btnRef.current.focus();
|
||||
}
|
||||
}, [colorObj?.colorName, activeColorPickerSection]);
|
||||
|
||||
return (
|
||||
<div className="color-picker-content--default">
|
||||
{Object.entries(palette).map(([key, value], index) => {
|
||||
const color =
|
||||
(Array.isArray(value) ? value[activeShade] : value) || "transparent";
|
||||
|
||||
const keybinding = colorPickerHotkeyBindings[index];
|
||||
const label = t(`colors.${key.replace(/\d+/, "")}`, null, "");
|
||||
|
||||
return (
|
||||
<button
|
||||
ref={colorObj?.colorName === key ? btnRef : undefined}
|
||||
tabIndex={-1}
|
||||
type="button"
|
||||
className={clsx(
|
||||
"color-picker__button color-picker__button--large",
|
||||
{
|
||||
active: colorObj?.colorName === key,
|
||||
"is-transparent": color === "transparent" || !color,
|
||||
},
|
||||
)}
|
||||
onClick={() => {
|
||||
onChange(color);
|
||||
setActiveColorPickerSection("baseColors");
|
||||
}}
|
||||
title={`${label}${
|
||||
color.startsWith("#") ? ` ${color}` : ""
|
||||
} — ${keybinding}`}
|
||||
aria-label={`${label} — ${keybinding}`}
|
||||
style={color ? { "--swatch-color": color } : undefined}
|
||||
data-testid={`color-${key}`}
|
||||
key={key}
|
||||
>
|
||||
<div className="color-picker__button-outline" />
|
||||
<HotkeyLabel color={color} keyLabel={keybinding} />
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PickerColorList;
|
7
src/components/ColorPicker/PickerHeading.tsx
Normal file
7
src/components/ColorPicker/PickerHeading.tsx
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { ReactNode } from "react";
|
||||
|
||||
const PickerHeading = ({ children }: { children: ReactNode }) => (
|
||||
<div className="color-picker__heading">{children}</div>
|
||||
);
|
||||
|
||||
export default PickerHeading;
|
105
src/components/ColorPicker/ShadeList.tsx
Normal file
105
src/components/ColorPicker/ShadeList.tsx
Normal file
|
@ -0,0 +1,105 @@
|
|||
import clsx from "clsx";
|
||||
import { useAtom } from "jotai";
|
||||
import { useEffect, useRef } from "react";
|
||||
import {
|
||||
activeColorPickerSectionAtom,
|
||||
getColorNameAndShadeFromHex,
|
||||
} from "./colorPickerUtils";
|
||||
import HotkeyLabel from "./HotkeyLabel";
|
||||
import { t } from "../../i18n";
|
||||
import { ColorPaletteCustom } from "../../colors";
|
||||
|
||||
interface ShadeListProps {
|
||||
hex: string | null;
|
||||
onChange: (color: string) => void;
|
||||
palette: ColorPaletteCustom;
|
||||
}
|
||||
|
||||
export const ShadeList = ({ hex, onChange, palette }: ShadeListProps) => {
|
||||
const colorObj = getColorNameAndShadeFromHex({
|
||||
hex: hex || "transparent",
|
||||
palette,
|
||||
});
|
||||
|
||||
const [activeColorPickerSection, setActiveColorPickerSection] = useAtom(
|
||||
activeColorPickerSectionAtom,
|
||||
);
|
||||
|
||||
const btnRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (btnRef.current && activeColorPickerSection === "shades") {
|
||||
btnRef.current.focus();
|
||||
}
|
||||
}, [colorObj, activeColorPickerSection]);
|
||||
|
||||
if (colorObj) {
|
||||
const { colorName, shade } = colorObj;
|
||||
|
||||
const shades = palette[colorName];
|
||||
|
||||
if (Array.isArray(shades)) {
|
||||
return (
|
||||
<div className="color-picker-content--default shades">
|
||||
{shades.map((color, i) => (
|
||||
<button
|
||||
ref={
|
||||
i === shade && activeColorPickerSection === "shades"
|
||||
? btnRef
|
||||
: undefined
|
||||
}
|
||||
tabIndex={-1}
|
||||
key={i}
|
||||
type="button"
|
||||
className={clsx(
|
||||
"color-picker__button color-picker__button--large",
|
||||
{ active: i === shade },
|
||||
)}
|
||||
aria-label="Shade"
|
||||
title={`${colorName} - ${i + 1}`}
|
||||
style={color ? { "--swatch-color": color } : undefined}
|
||||
onClick={() => {
|
||||
onChange(color);
|
||||
setActiveColorPickerSection("shades");
|
||||
}}
|
||||
>
|
||||
<div className="color-picker__button-outline" />
|
||||
<HotkeyLabel color={color} keyLabel={i + 1} isShade />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="color-picker-content--default"
|
||||
style={{ position: "relative" }}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={-1}
|
||||
className="color-picker__button color-picker__button--large color-picker__button--no-focus-visible"
|
||||
/>
|
||||
<div
|
||||
tabIndex={-1}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
textAlign: "center",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{t("colorPicker.noShades")}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
64
src/components/ColorPicker/TopPicks.tsx
Normal file
64
src/components/ColorPicker/TopPicks.tsx
Normal file
|
@ -0,0 +1,64 @@
|
|||
import clsx from "clsx";
|
||||
import { ColorPickerType } from "./colorPickerUtils";
|
||||
import {
|
||||
DEFAULT_CANVAS_BACKGROUND_PICKS,
|
||||
DEFAULT_ELEMENT_BACKGROUND_PICKS,
|
||||
DEFAULT_ELEMENT_STROKE_PICKS,
|
||||
} from "../../colors";
|
||||
|
||||
interface TopPicksProps {
|
||||
onChange: (color: string) => void;
|
||||
type: ColorPickerType;
|
||||
activeColor: string | null;
|
||||
topPicks?: readonly string[];
|
||||
}
|
||||
|
||||
export const TopPicks = ({
|
||||
onChange,
|
||||
type,
|
||||
activeColor,
|
||||
topPicks,
|
||||
}: TopPicksProps) => {
|
||||
let colors;
|
||||
if (type === "elementStroke") {
|
||||
colors = DEFAULT_ELEMENT_STROKE_PICKS;
|
||||
}
|
||||
|
||||
if (type === "elementBackground") {
|
||||
colors = DEFAULT_ELEMENT_BACKGROUND_PICKS;
|
||||
}
|
||||
|
||||
if (type === "canvasBackground") {
|
||||
colors = DEFAULT_CANVAS_BACKGROUND_PICKS;
|
||||
}
|
||||
|
||||
// this one can overwrite defaults
|
||||
if (topPicks) {
|
||||
colors = topPicks;
|
||||
}
|
||||
|
||||
if (!colors) {
|
||||
console.error("Invalid type for TopPicks");
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="color-picker__top-picks">
|
||||
{colors.map((color: string) => (
|
||||
<button
|
||||
className={clsx("color-picker__button", {
|
||||
active: color === activeColor,
|
||||
"is-transparent": color === "transparent" || !color,
|
||||
})}
|
||||
style={{ "--swatch-color": color }}
|
||||
key={color}
|
||||
type="button"
|
||||
title={color}
|
||||
onClick={() => onChange(color)}
|
||||
>
|
||||
<div className="color-picker__button-outline" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
139
src/components/ColorPicker/colorPickerUtils.ts
Normal file
139
src/components/ColorPicker/colorPickerUtils.ts
Normal file
|
@ -0,0 +1,139 @@
|
|||
import { ExcalidrawElement } from "../../element/types";
|
||||
import { atom } from "jotai";
|
||||
import {
|
||||
ColorPickerColor,
|
||||
ColorPaletteCustom,
|
||||
MAX_CUSTOM_COLORS_USED_IN_CANVAS,
|
||||
} from "../../colors";
|
||||
|
||||
export const getColorNameAndShadeFromHex = ({
|
||||
palette,
|
||||
hex,
|
||||
}: {
|
||||
palette: ColorPaletteCustom;
|
||||
hex: string;
|
||||
}): {
|
||||
colorName: ColorPickerColor;
|
||||
shade: number | null;
|
||||
} | null => {
|
||||
for (const [colorName, colorVal] of Object.entries(palette)) {
|
||||
if (Array.isArray(colorVal)) {
|
||||
const shade = colorVal.indexOf(hex);
|
||||
if (shade > -1) {
|
||||
return { colorName: colorName as ColorPickerColor, shade };
|
||||
}
|
||||
} else if (colorVal === hex) {
|
||||
return { colorName: colorName as ColorPickerColor, shade: null };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const colorPickerHotkeyBindings = [
|
||||
["q", "w", "e", "r", "t"],
|
||||
["a", "s", "d", "f", "g"],
|
||||
["z", "x", "c", "v", "b"],
|
||||
].flat();
|
||||
|
||||
export const isCustomColor = ({
|
||||
color,
|
||||
palette,
|
||||
}: {
|
||||
color: string | null;
|
||||
palette: ColorPaletteCustom;
|
||||
}) => {
|
||||
if (!color) {
|
||||
return false;
|
||||
}
|
||||
const paletteValues = Object.values(palette).flat();
|
||||
return !paletteValues.includes(color);
|
||||
};
|
||||
|
||||
export const getMostUsedCustomColors = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
type: "elementBackground" | "elementStroke",
|
||||
palette: ColorPaletteCustom,
|
||||
) => {
|
||||
const elementColorTypeMap = {
|
||||
elementBackground: "backgroundColor",
|
||||
elementStroke: "strokeColor",
|
||||
};
|
||||
|
||||
const colors = elements.filter((element) => {
|
||||
if (element.isDeleted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const color =
|
||||
element[elementColorTypeMap[type] as "backgroundColor" | "strokeColor"];
|
||||
|
||||
return isCustomColor({ color, palette });
|
||||
});
|
||||
|
||||
const colorCountMap = new Map<string, number>();
|
||||
colors.forEach((element) => {
|
||||
const color =
|
||||
element[elementColorTypeMap[type] as "backgroundColor" | "strokeColor"];
|
||||
if (colorCountMap.has(color)) {
|
||||
colorCountMap.set(color, colorCountMap.get(color)! + 1);
|
||||
} else {
|
||||
colorCountMap.set(color, 1);
|
||||
}
|
||||
});
|
||||
|
||||
return [...colorCountMap.entries()]
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map((c) => c[0])
|
||||
.slice(0, MAX_CUSTOM_COLORS_USED_IN_CANVAS);
|
||||
};
|
||||
|
||||
export type ActiveColorPickerSectionAtomType =
|
||||
| "custom"
|
||||
| "baseColors"
|
||||
| "shades"
|
||||
| "hex"
|
||||
| null;
|
||||
export const activeColorPickerSectionAtom =
|
||||
atom<ActiveColorPickerSectionAtomType>(null);
|
||||
|
||||
const calculateContrast = (r: number, g: number, b: number) => {
|
||||
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
|
||||
return yiq >= 160 ? "black" : "white";
|
||||
};
|
||||
|
||||
// inspiration from https://stackoverflow.com/a/11868398
|
||||
export const getContrastYIQ = (bgHex: string, isCustomColor: boolean) => {
|
||||
if (isCustomColor) {
|
||||
const style = new Option().style;
|
||||
style.color = bgHex;
|
||||
|
||||
if (style.color) {
|
||||
const rgb = style.color
|
||||
.replace(/^(rgb|rgba)\(/, "")
|
||||
.replace(/\)$/, "")
|
||||
.replace(/\s/g, "")
|
||||
.split(",");
|
||||
const r = parseInt(rgb[0]);
|
||||
const g = parseInt(rgb[1]);
|
||||
const b = parseInt(rgb[2]);
|
||||
|
||||
return calculateContrast(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ? is this wanted?
|
||||
if (bgHex === "transparent") {
|
||||
return "black";
|
||||
}
|
||||
|
||||
const r = parseInt(bgHex.substring(1, 3), 16);
|
||||
const g = parseInt(bgHex.substring(3, 5), 16);
|
||||
const b = parseInt(bgHex.substring(5, 7), 16);
|
||||
|
||||
return calculateContrast(r, g, b);
|
||||
};
|
||||
|
||||
export type ColorPickerType =
|
||||
| "canvasBackground"
|
||||
| "elementBackground"
|
||||
| "elementStroke";
|
249
src/components/ColorPicker/keyboardNavHandlers.ts
Normal file
249
src/components/ColorPicker/keyboardNavHandlers.ts
Normal file
|
@ -0,0 +1,249 @@
|
|||
import {
|
||||
ColorPickerColor,
|
||||
ColorPalette,
|
||||
ColorPaletteCustom,
|
||||
COLORS_PER_ROW,
|
||||
COLOR_PALETTE,
|
||||
} from "../../colors";
|
||||
import { KEYS } from "../../keys";
|
||||
import { ValueOf } from "../../utility-types";
|
||||
import {
|
||||
ActiveColorPickerSectionAtomType,
|
||||
colorPickerHotkeyBindings,
|
||||
getColorNameAndShadeFromHex,
|
||||
} from "./colorPickerUtils";
|
||||
|
||||
const arrowHandler = (
|
||||
eventKey: string,
|
||||
currentIndex: number | null,
|
||||
length: number,
|
||||
) => {
|
||||
const rows = Math.ceil(length / COLORS_PER_ROW);
|
||||
|
||||
currentIndex = currentIndex ?? -1;
|
||||
|
||||
switch (eventKey) {
|
||||
case "ArrowLeft": {
|
||||
const prevIndex = currentIndex - 1;
|
||||
return prevIndex < 0 ? length - 1 : prevIndex;
|
||||
}
|
||||
case "ArrowRight": {
|
||||
return (currentIndex + 1) % length;
|
||||
}
|
||||
case "ArrowDown": {
|
||||
const nextIndex = currentIndex + COLORS_PER_ROW;
|
||||
return nextIndex >= length ? currentIndex % COLORS_PER_ROW : nextIndex;
|
||||
}
|
||||
case "ArrowUp": {
|
||||
const prevIndex = currentIndex - COLORS_PER_ROW;
|
||||
const newIndex =
|
||||
prevIndex < 0 ? COLORS_PER_ROW * rows + prevIndex : prevIndex;
|
||||
return newIndex >= length ? undefined : newIndex;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
interface HotkeyHandlerProps {
|
||||
e: React.KeyboardEvent;
|
||||
colorObj: { colorName: ColorPickerColor; shade: number | null } | null;
|
||||
onChange: (color: string) => void;
|
||||
palette: ColorPaletteCustom;
|
||||
customColors: string[];
|
||||
setActiveColorPickerSection: (
|
||||
update: React.SetStateAction<ActiveColorPickerSectionAtomType>,
|
||||
) => void;
|
||||
activeShade: number;
|
||||
}
|
||||
|
||||
const hotkeyHandler = ({
|
||||
e,
|
||||
colorObj,
|
||||
onChange,
|
||||
palette,
|
||||
customColors,
|
||||
setActiveColorPickerSection,
|
||||
activeShade,
|
||||
}: HotkeyHandlerProps) => {
|
||||
if (colorObj?.shade != null) {
|
||||
// shift + numpad is extremely messed up on windows apparently
|
||||
if (
|
||||
["Digit1", "Digit2", "Digit3", "Digit4", "Digit5"].includes(e.code) &&
|
||||
e.shiftKey
|
||||
) {
|
||||
const newShade = Number(e.code.slice(-1)) - 1;
|
||||
onChange(palette[colorObj.colorName][newShade]);
|
||||
setActiveColorPickerSection("shades");
|
||||
}
|
||||
}
|
||||
|
||||
if (["1", "2", "3", "4", "5"].includes(e.key)) {
|
||||
const c = customColors[Number(e.key) - 1];
|
||||
if (c) {
|
||||
onChange(customColors[Number(e.key) - 1]);
|
||||
setActiveColorPickerSection("custom");
|
||||
}
|
||||
}
|
||||
|
||||
if (colorPickerHotkeyBindings.includes(e.key)) {
|
||||
const index = colorPickerHotkeyBindings.indexOf(e.key);
|
||||
const paletteKey = Object.keys(palette)[index] as keyof ColorPalette;
|
||||
const paletteValue = palette[paletteKey];
|
||||
const r = Array.isArray(paletteValue)
|
||||
? paletteValue[activeShade]
|
||||
: paletteValue;
|
||||
onChange(r);
|
||||
setActiveColorPickerSection("baseColors");
|
||||
}
|
||||
};
|
||||
|
||||
interface ColorPickerKeyNavHandlerProps {
|
||||
e: React.KeyboardEvent;
|
||||
activeColorPickerSection: ActiveColorPickerSectionAtomType;
|
||||
palette: ColorPaletteCustom;
|
||||
hex: string | null;
|
||||
onChange: (color: string) => void;
|
||||
customColors: string[];
|
||||
setActiveColorPickerSection: (
|
||||
update: React.SetStateAction<ActiveColorPickerSectionAtomType>,
|
||||
) => void;
|
||||
updateData: (formData?: any) => void;
|
||||
activeShade: number;
|
||||
}
|
||||
|
||||
export const colorPickerKeyNavHandler = ({
|
||||
e,
|
||||
activeColorPickerSection,
|
||||
palette,
|
||||
hex,
|
||||
onChange,
|
||||
customColors,
|
||||
setActiveColorPickerSection,
|
||||
updateData,
|
||||
activeShade,
|
||||
}: ColorPickerKeyNavHandlerProps) => {
|
||||
if (e.key === KEYS.ESCAPE || !hex) {
|
||||
updateData({ openPopup: null });
|
||||
return;
|
||||
}
|
||||
|
||||
const colorObj = getColorNameAndShadeFromHex({ hex, palette });
|
||||
|
||||
if (e.key === KEYS.TAB) {
|
||||
const sectionsMap: Record<
|
||||
NonNullable<ActiveColorPickerSectionAtomType>,
|
||||
boolean
|
||||
> = {
|
||||
custom: !!customColors.length,
|
||||
baseColors: true,
|
||||
shades: colorObj?.shade != null,
|
||||
hex: true,
|
||||
};
|
||||
|
||||
const sections = Object.entries(sectionsMap).reduce((acc, [key, value]) => {
|
||||
if (value) {
|
||||
acc.push(key as ActiveColorPickerSectionAtomType);
|
||||
}
|
||||
return acc;
|
||||
}, [] as ActiveColorPickerSectionAtomType[]);
|
||||
|
||||
const activeSectionIndex = sections.indexOf(activeColorPickerSection);
|
||||
const indexOffset = e.shiftKey ? -1 : 1;
|
||||
const nextSectionIndex =
|
||||
activeSectionIndex + indexOffset > sections.length - 1
|
||||
? 0
|
||||
: activeSectionIndex + indexOffset < 0
|
||||
? sections.length - 1
|
||||
: activeSectionIndex + indexOffset;
|
||||
|
||||
const nextSection = sections[nextSectionIndex];
|
||||
|
||||
if (nextSection) {
|
||||
setActiveColorPickerSection(nextSection);
|
||||
}
|
||||
|
||||
if (nextSection === "custom") {
|
||||
onChange(customColors[0]);
|
||||
} else if (nextSection === "baseColors") {
|
||||
const baseColorName = (
|
||||
Object.entries(palette) as [string, ValueOf<ColorPalette>][]
|
||||
).find(([name, shades]) => {
|
||||
if (Array.isArray(shades)) {
|
||||
return shades.includes(hex);
|
||||
} else if (shades === hex) {
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
if (!baseColorName) {
|
||||
onChange(COLOR_PALETTE.black);
|
||||
}
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
hotkeyHandler({
|
||||
e,
|
||||
colorObj,
|
||||
onChange,
|
||||
palette,
|
||||
customColors,
|
||||
setActiveColorPickerSection,
|
||||
activeShade,
|
||||
});
|
||||
|
||||
if (activeColorPickerSection === "shades") {
|
||||
if (colorObj) {
|
||||
const { shade } = colorObj;
|
||||
const newShade = arrowHandler(e.key, shade, COLORS_PER_ROW);
|
||||
|
||||
if (newShade !== undefined) {
|
||||
onChange(palette[colorObj.colorName][newShade]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activeColorPickerSection === "baseColors") {
|
||||
if (colorObj) {
|
||||
const { colorName } = colorObj;
|
||||
const colorNames = Object.keys(palette) as (keyof ColorPalette)[];
|
||||
const indexOfColorName = colorNames.indexOf(colorName);
|
||||
|
||||
const newColorIndex = arrowHandler(
|
||||
e.key,
|
||||
indexOfColorName,
|
||||
colorNames.length,
|
||||
);
|
||||
|
||||
if (newColorIndex !== undefined) {
|
||||
const newColorName = colorNames[newColorIndex];
|
||||
const newColorNameValue = palette[newColorName];
|
||||
|
||||
onChange(
|
||||
Array.isArray(newColorNameValue)
|
||||
? newColorNameValue[activeShade]
|
||||
: newColorNameValue,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activeColorPickerSection === "custom") {
|
||||
const indexOfColor = customColors.indexOf(hex);
|
||||
|
||||
const newColorIndex = arrowHandler(
|
||||
e.key,
|
||||
indexOfColor,
|
||||
customColors.length,
|
||||
);
|
||||
|
||||
if (newColorIndex !== undefined) {
|
||||
const newColor = customColors[newColorIndex];
|
||||
onChange(newColor);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -4,13 +4,17 @@ import { canvasToBlob } from "../data/blob";
|
|||
import { NonDeletedExcalidrawElement } from "../element/types";
|
||||
import { t } from "../i18n";
|
||||
import { getSelectedElements, isSomeElementSelected } from "../scene";
|
||||
import { BinaryFiles, UIAppState } from "../types";
|
||||
import { AppClassProperties, BinaryFiles, UIAppState } from "../types";
|
||||
import { Dialog } from "./Dialog";
|
||||
import { clipboard } from "./icons";
|
||||
import Stack from "./Stack";
|
||||
import OpenColor from "open-color";
|
||||
import { CheckboxItem } from "./CheckboxItem";
|
||||
import { DEFAULT_EXPORT_PADDING, isFirefox } from "../constants";
|
||||
import {
|
||||
DEFAULT_EXPORT_PADDING,
|
||||
EXPORT_IMAGE_TYPES,
|
||||
isFirefox,
|
||||
} from "../constants";
|
||||
import { nativeFileSystemSupported } from "../data/filesystem";
|
||||
import { ActionManager } from "../actions/manager";
|
||||
import { exportToCanvas } from "../packages/utils";
|
||||
|
@ -65,21 +69,14 @@ const ImageExportModal = ({
|
|||
elements,
|
||||
appState,
|
||||
files,
|
||||
exportPadding = DEFAULT_EXPORT_PADDING,
|
||||
actionManager,
|
||||
onExportToPng,
|
||||
onExportToSvg,
|
||||
onExportToClipboard,
|
||||
onExportImage,
|
||||
}: {
|
||||
appState: UIAppState;
|
||||
elements: readonly NonDeletedExcalidrawElement[];
|
||||
files: BinaryFiles;
|
||||
exportPadding?: number;
|
||||
actionManager: ActionManager;
|
||||
onExportToPng: ExportCB;
|
||||
onExportToSvg: ExportCB;
|
||||
onExportToClipboard: ExportCB;
|
||||
onCloseRequest: () => void;
|
||||
onExportImage: AppClassProperties["onExportImage"];
|
||||
}) => {
|
||||
const someElementIsSelected = isSomeElementSelected(elements, appState);
|
||||
const [exportSelected, setExportSelected] = useState(someElementIsSelected);
|
||||
|
@ -90,10 +87,6 @@ const ImageExportModal = ({
|
|||
? getSelectedElements(elements, appState, true)
|
||||
: elements;
|
||||
|
||||
useEffect(() => {
|
||||
setExportSelected(someElementIsSelected);
|
||||
}, [someElementIsSelected]);
|
||||
|
||||
useEffect(() => {
|
||||
const previewNode = previewRef.current;
|
||||
if (!previewNode) {
|
||||
|
@ -107,7 +100,7 @@ const ImageExportModal = ({
|
|||
elements: exportedElements,
|
||||
appState,
|
||||
files,
|
||||
exportPadding,
|
||||
exportPadding: DEFAULT_EXPORT_PADDING,
|
||||
maxWidthOrHeight: maxWidth,
|
||||
})
|
||||
.then((canvas) => {
|
||||
|
@ -122,7 +115,7 @@ const ImageExportModal = ({
|
|||
console.error(error);
|
||||
setRenderError(error);
|
||||
});
|
||||
}, [appState, files, exportedElements, exportPadding]);
|
||||
}, [appState, files, exportedElements]);
|
||||
|
||||
return (
|
||||
<div className="ExportDialog">
|
||||
|
@ -177,7 +170,9 @@ const ImageExportModal = ({
|
|||
color="indigo"
|
||||
title={t("buttons.exportToPng")}
|
||||
aria-label={t("buttons.exportToPng")}
|
||||
onClick={() => onExportToPng(exportedElements)}
|
||||
onClick={() =>
|
||||
onExportImage(EXPORT_IMAGE_TYPES.png, exportedElements)
|
||||
}
|
||||
>
|
||||
PNG
|
||||
</ExportButton>
|
||||
|
@ -185,7 +180,9 @@ const ImageExportModal = ({
|
|||
color="red"
|
||||
title={t("buttons.exportToSvg")}
|
||||
aria-label={t("buttons.exportToSvg")}
|
||||
onClick={() => onExportToSvg(exportedElements)}
|
||||
onClick={() =>
|
||||
onExportImage(EXPORT_IMAGE_TYPES.svg, exportedElements)
|
||||
}
|
||||
>
|
||||
SVG
|
||||
</ExportButton>
|
||||
|
@ -194,7 +191,9 @@ const ImageExportModal = ({
|
|||
{(probablySupportsClipboardBlob || isFirefox) && (
|
||||
<ExportButton
|
||||
title={t("buttons.copyPngToClipboard")}
|
||||
onClick={() => onExportToClipboard(exportedElements)}
|
||||
onClick={() =>
|
||||
onExportImage(EXPORT_IMAGE_TYPES.clipboard, exportedElements)
|
||||
}
|
||||
color="gray"
|
||||
shade={7}
|
||||
>
|
||||
|
@ -209,45 +208,31 @@ const ImageExportModal = ({
|
|||
export const ImageExportDialog = ({
|
||||
elements,
|
||||
appState,
|
||||
setAppState,
|
||||
files,
|
||||
exportPadding = DEFAULT_EXPORT_PADDING,
|
||||
actionManager,
|
||||
onExportToPng,
|
||||
onExportToSvg,
|
||||
onExportToClipboard,
|
||||
onExportImage,
|
||||
onCloseRequest,
|
||||
}: {
|
||||
appState: UIAppState;
|
||||
setAppState: React.Component<any, UIAppState>["setState"];
|
||||
elements: readonly NonDeletedExcalidrawElement[];
|
||||
files: BinaryFiles;
|
||||
exportPadding?: number;
|
||||
actionManager: ActionManager;
|
||||
onExportToPng: ExportCB;
|
||||
onExportToSvg: ExportCB;
|
||||
onExportToClipboard: ExportCB;
|
||||
onExportImage: AppClassProperties["onExportImage"];
|
||||
onCloseRequest: () => void;
|
||||
}) => {
|
||||
const handleClose = React.useCallback(() => {
|
||||
setAppState({ openDialog: null });
|
||||
}, [setAppState]);
|
||||
if (appState.openDialog !== "imageExport") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{appState.openDialog === "imageExport" && (
|
||||
<Dialog onCloseRequest={handleClose} title={t("buttons.exportImage")}>
|
||||
<ImageExportModal
|
||||
elements={elements}
|
||||
appState={appState}
|
||||
files={files}
|
||||
exportPadding={exportPadding}
|
||||
actionManager={actionManager}
|
||||
onExportToPng={onExportToPng}
|
||||
onExportToSvg={onExportToSvg}
|
||||
onExportToClipboard={onExportToClipboard}
|
||||
onCloseRequest={handleClose}
|
||||
/>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
<Dialog onCloseRequest={onCloseRequest} title={t("buttons.exportImage")}>
|
||||
<ImageExportModal
|
||||
elements={elements}
|
||||
appState={appState}
|
||||
files={files}
|
||||
actionManager={actionManager}
|
||||
onExportImage={onExportImage}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,23 +2,22 @@ import clsx from "clsx";
|
|||
import React from "react";
|
||||
import { ActionManager } from "../actions/manager";
|
||||
import { CLASSES, DEFAULT_SIDEBAR, LIBRARY_SIDEBAR_WIDTH } from "../constants";
|
||||
import { exportCanvas } from "../data";
|
||||
import { isTextElement, showSelectedShapeActions } from "../element";
|
||||
import { NonDeletedExcalidrawElement } from "../element/types";
|
||||
import { Language, t } from "../i18n";
|
||||
import { calculateScrollCenter } from "../scene";
|
||||
import { ExportType } from "../scene/types";
|
||||
import {
|
||||
AppProps,
|
||||
AppState,
|
||||
ExcalidrawProps,
|
||||
BinaryFiles,
|
||||
UIAppState,
|
||||
AppClassProperties,
|
||||
} from "../types";
|
||||
import { capitalizeString, isShallowEqual, muteFSAbortError } from "../utils";
|
||||
import { capitalizeString, isShallowEqual } from "../utils";
|
||||
import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
|
||||
import { ErrorDialog } from "./ErrorDialog";
|
||||
import { ExportCB, ImageExportDialog } from "./ImageExportDialog";
|
||||
import { ImageExportDialog } from "./ImageExportDialog";
|
||||
import { FixedSideContainer } from "./FixedSideContainer";
|
||||
import { HintViewer } from "./HintViewer";
|
||||
import { Island } from "./Island";
|
||||
|
@ -31,7 +30,6 @@ import { HelpDialog } from "./HelpDialog";
|
|||
import Stack from "./Stack";
|
||||
import { UserList } from "./UserList";
|
||||
import { JSONExportDialog } from "./JSONExportDialog";
|
||||
import { isImageFileHandle } from "../data/blob";
|
||||
import { PenModeButton } from "./PenModeButton";
|
||||
import { trackEvent } from "../analytics";
|
||||
import { useDevice } from "../components/App";
|
||||
|
@ -69,6 +67,7 @@ interface LayerUIProps {
|
|||
renderCustomStats?: ExcalidrawProps["renderCustomStats"];
|
||||
UIOptions: AppProps["UIOptions"];
|
||||
onImageAction: (data: { insertOnCanvasDirectly: boolean }) => void;
|
||||
onExportImage: AppClassProperties["onExportImage"];
|
||||
renderWelcomeScreen: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
@ -114,6 +113,7 @@ const LayerUI = ({
|
|||
renderCustomStats,
|
||||
UIOptions,
|
||||
onImageAction,
|
||||
onExportImage,
|
||||
renderWelcomeScreen,
|
||||
children,
|
||||
}: LayerUIProps) => {
|
||||
|
@ -143,47 +143,14 @@ const LayerUI = ({
|
|||
return null;
|
||||
}
|
||||
|
||||
const createExporter =
|
||||
(type: ExportType): ExportCB =>
|
||||
async (exportedElements) => {
|
||||
trackEvent("export", type, "ui");
|
||||
const fileHandle = await exportCanvas(
|
||||
type,
|
||||
exportedElements,
|
||||
// FIXME once we split UI canvas from element canvas
|
||||
appState as AppState,
|
||||
files,
|
||||
{
|
||||
exportBackground: appState.exportBackground,
|
||||
name: appState.name,
|
||||
viewBackgroundColor: appState.viewBackgroundColor,
|
||||
},
|
||||
)
|
||||
.catch(muteFSAbortError)
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
setAppState({ errorMessage: error.message });
|
||||
});
|
||||
|
||||
if (
|
||||
appState.exportEmbedScene &&
|
||||
fileHandle &&
|
||||
isImageFileHandle(fileHandle)
|
||||
) {
|
||||
setAppState({ fileHandle });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ImageExportDialog
|
||||
elements={elements}
|
||||
appState={appState}
|
||||
setAppState={setAppState}
|
||||
files={files}
|
||||
actionManager={actionManager}
|
||||
onExportToPng={createExporter("png")}
|
||||
onExportToSvg={createExporter("svg")}
|
||||
onExportToClipboard={createExporter("clipboard")}
|
||||
onExportImage={onExportImage}
|
||||
onCloseRequest={() => setAppState({ openDialog: null })}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
@import "open-color/open-color";
|
||||
|
||||
.excalidraw {
|
||||
.library-menu-items-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.layer-ui__library {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -70,6 +65,16 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.625rem;
|
||||
position: relative;
|
||||
|
||||
&--at-bottom::before {
|
||||
content: "";
|
||||
width: calc(100% - 1.5rem);
|
||||
height: 1px;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
background: var(--sidebar-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.library-menu-browse-button {
|
||||
|
@ -126,4 +131,20 @@
|
|||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.layer-ui__library .library-menu-dropdown-container {
|
||||
position: relative;
|
||||
|
||||
&--in-heading {
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 0.75rem;
|
||||
z-index: 1;
|
||||
|
||||
.dropdown-menu {
|
||||
top: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,12 +121,11 @@ export const LibraryMenuContent = ({
|
|||
/>
|
||||
{showBtn && (
|
||||
<LibraryMenuControlButtons
|
||||
className="library-menu-control-buttons--at-bottom"
|
||||
style={{ padding: "16px 12px 0 12px" }}
|
||||
id={id}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
theme={appState.theme}
|
||||
selectedItems={selectedItems}
|
||||
onSelectItems={onSelectItems}
|
||||
/>
|
||||
)}
|
||||
</LibraryMenuWrapper>
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
import { LibraryItem, ExcalidrawProps, UIAppState } from "../types";
|
||||
import { ExcalidrawProps, UIAppState } from "../types";
|
||||
import LibraryMenuBrowseButton from "./LibraryMenuBrowseButton";
|
||||
import { LibraryDropdownMenu } from "./LibraryMenuHeaderContent";
|
||||
import clsx from "clsx";
|
||||
|
||||
export const LibraryMenuControlButtons = ({
|
||||
selectedItems,
|
||||
onSelectItems,
|
||||
libraryReturnUrl,
|
||||
theme,
|
||||
id,
|
||||
style,
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
selectedItems: LibraryItem["id"][];
|
||||
onSelectItems: (id: LibraryItem["id"][]) => void;
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
theme: UIAppState["theme"];
|
||||
id: string;
|
||||
style: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}) => {
|
||||
return (
|
||||
<div className="library-menu-control-buttons" style={style}>
|
||||
<div
|
||||
className={clsx("library-menu-control-buttons", className)}
|
||||
style={style}
|
||||
>
|
||||
<LibraryMenuBrowseButton
|
||||
id={id}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
theme={theme}
|
||||
/>
|
||||
<LibraryDropdownMenu
|
||||
selectedItems={selectedItems}
|
||||
onSelectItems={onSelectItems}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@ import { Dialog } from "./Dialog";
|
|||
import DropdownMenu from "./dropdownMenu/DropdownMenu";
|
||||
import { isLibraryMenuOpenAtom } from "./LibraryMenu";
|
||||
import { useUIAppState } from "../context/ui-appState";
|
||||
import clsx from "clsx";
|
||||
|
||||
const getSelectedItems = (
|
||||
libraryItems: LibraryItems,
|
||||
|
@ -37,6 +38,7 @@ export const LibraryDropdownMenuButton: React.FC<{
|
|||
resetLibrary: () => void;
|
||||
onSelectItems: (items: LibraryItem["id"][]) => void;
|
||||
appState: UIAppState;
|
||||
className?: string;
|
||||
}> = ({
|
||||
setAppState,
|
||||
selectedItems,
|
||||
|
@ -45,6 +47,7 @@ export const LibraryDropdownMenuButton: React.FC<{
|
|||
resetLibrary,
|
||||
onSelectItems,
|
||||
appState,
|
||||
className,
|
||||
}) => {
|
||||
const [libraryItemsData] = useAtom(libraryItemsAtom, jotaiScope);
|
||||
const [isLibraryMenuOpen, setIsLibraryMenuOpen] = useAtom(
|
||||
|
@ -236,7 +239,7 @@ export const LibraryDropdownMenuButton: React.FC<{
|
|||
};
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
<div className={clsx("library-menu-dropdown-container", className)}>
|
||||
{renderLibraryMenu()}
|
||||
{selectedItems.length > 0 && (
|
||||
<div className="library-actions-counter">{selectedItems.length}</div>
|
||||
|
@ -270,9 +273,11 @@ export const LibraryDropdownMenuButton: React.FC<{
|
|||
export const LibraryDropdownMenu = ({
|
||||
selectedItems,
|
||||
onSelectItems,
|
||||
className,
|
||||
}: {
|
||||
selectedItems: LibraryItem["id"][];
|
||||
onSelectItems: (id: LibraryItem["id"][]) => void;
|
||||
className?: string;
|
||||
}) => {
|
||||
const { library } = useApp();
|
||||
const appState = useUIAppState();
|
||||
|
@ -308,6 +313,7 @@ export const LibraryDropdownMenu = ({
|
|||
removeFromLibrary(libraryItemsData.libraryItems)
|
||||
}
|
||||
resetLibrary={resetLibrary}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
}
|
||||
|
||||
.library-menu-items-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
@ -35,10 +36,14 @@
|
|||
height: 100%;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid var(--sidebar-border-color);
|
||||
|
||||
position: relative;
|
||||
|
||||
& > div {
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
}
|
||||
|
||||
&__row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
|
@ -59,6 +64,9 @@
|
|||
font-size: 1.125rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.75rem;
|
||||
width: 100%;
|
||||
padding-right: 4rem; // due to dropdown button
|
||||
box-sizing: border-box;
|
||||
|
||||
&--excal {
|
||||
margin-top: 2rem;
|
||||
|
@ -75,4 +83,11 @@
|
|||
color: var(--text-primary-color);
|
||||
}
|
||||
}
|
||||
|
||||
.library-menu-items-private-library-container {
|
||||
// so that when you toggle between pending item and no items, there's
|
||||
// no layout shift (this is hardcoded and works only with ENG locale)
|
||||
min-height: 3.75rem;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import { MIME_TYPES } from "../constants";
|
|||
import Spinner from "./Spinner";
|
||||
import { duplicateElements } from "../element/newElement";
|
||||
import { LibraryMenuControlButtons } from "./LibraryMenuControlButtons";
|
||||
import { LibraryDropdownMenu } from "./LibraryMenuHeaderContent";
|
||||
|
||||
import "./LibraryMenuItems.scss";
|
||||
|
||||
|
@ -207,6 +208,11 @@ const LibraryMenuItems = ({
|
|||
|
||||
const showBtn = !libraryItems.length && !pendingElements.length;
|
||||
|
||||
const isLibraryEmpty =
|
||||
!pendingElements.length &&
|
||||
!unpublishedItems.length &&
|
||||
!publishedItems.length;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="library-menu-items-container"
|
||||
|
@ -218,6 +224,13 @@ const LibraryMenuItems = ({
|
|||
: { borderBottom: 0 }
|
||||
}
|
||||
>
|
||||
{!isLibraryEmpty && (
|
||||
<LibraryDropdownMenu
|
||||
selectedItems={selectedItems}
|
||||
onSelectItems={onSelectItems}
|
||||
className="library-menu-dropdown-container--in-heading"
|
||||
/>
|
||||
)}
|
||||
<Stack.Col
|
||||
className="library-menu-items-container__items"
|
||||
align="start"
|
||||
|
@ -228,47 +241,45 @@ const LibraryMenuItems = ({
|
|||
}}
|
||||
>
|
||||
<>
|
||||
<div>
|
||||
{(pendingElements.length > 0 ||
|
||||
unpublishedItems.length > 0 ||
|
||||
publishedItems.length > 0) && (
|
||||
<div className="library-menu-items-container__header">
|
||||
{t("labels.personalLib")}
|
||||
</div>
|
||||
)}
|
||||
{isLoading && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "var(--container-padding-y)",
|
||||
right: "var(--container-padding-x)",
|
||||
transform: "translateY(50%)",
|
||||
}}
|
||||
>
|
||||
<Spinner />
|
||||
{!isLibraryEmpty && (
|
||||
<div className="library-menu-items-container__header">
|
||||
{t("labels.personalLib")}
|
||||
</div>
|
||||
)}
|
||||
{isLoading && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "var(--container-padding-y)",
|
||||
right: "var(--container-padding-x)",
|
||||
transform: "translateY(50%)",
|
||||
}}
|
||||
>
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
<div className="library-menu-items-private-library-container">
|
||||
{!pendingElements.length && !unpublishedItems.length ? (
|
||||
<div className="library-menu-items__no-items">
|
||||
<div className="library-menu-items__no-items__label">
|
||||
{t("library.noItems")}
|
||||
</div>
|
||||
<div className="library-menu-items__no-items__hint">
|
||||
{publishedItems.length > 0
|
||||
? t("library.hint_emptyPrivateLibrary")
|
||||
: t("library.hint_emptyLibrary")}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
renderLibrarySection([
|
||||
// append pending library item
|
||||
...(pendingElements.length
|
||||
? [{ id: null, elements: pendingElements }]
|
||||
: []),
|
||||
...unpublishedItems,
|
||||
])
|
||||
)}
|
||||
</div>
|
||||
{!pendingElements.length && !unpublishedItems.length ? (
|
||||
<div className="library-menu-items__no-items">
|
||||
<div className="library-menu-items__no-items__label">
|
||||
{t("library.noItems")}
|
||||
</div>
|
||||
<div className="library-menu-items__no-items__hint">
|
||||
{publishedItems.length > 0
|
||||
? t("library.hint_emptyPrivateLibrary")
|
||||
: t("library.hint_emptyLibrary")}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
renderLibrarySection([
|
||||
// append pending library item
|
||||
...(pendingElements.length
|
||||
? [{ id: null, elements: pendingElements }]
|
||||
: []),
|
||||
...unpublishedItems,
|
||||
])
|
||||
)}
|
||||
</>
|
||||
|
||||
<>
|
||||
|
@ -304,9 +315,12 @@ const LibraryMenuItems = ({
|
|||
id={id}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
theme={theme}
|
||||
selectedItems={selectedItems}
|
||||
onSelectItems={onSelectItems}
|
||||
/>
|
||||
>
|
||||
<LibraryDropdownMenu
|
||||
selectedItems={selectedItems}
|
||||
onSelectItems={onSelectItems}
|
||||
/>
|
||||
</LibraryMenuControlButtons>
|
||||
)}
|
||||
</Stack.Col>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import clsx from "clsx";
|
||||
import oc from "open-color";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useDevice } from "../components/App";
|
||||
import { exportToSvg } from "../packages/utils";
|
||||
|
@ -7,6 +6,7 @@ import { LibraryItem } from "../types";
|
|||
import "./LibraryUnit.scss";
|
||||
import { CheckboxItem } from "./CheckboxItem";
|
||||
import { PlusIcon } from "./icons";
|
||||
import { COLOR_PALETTE } from "../colors";
|
||||
|
||||
export const LibraryUnit = ({
|
||||
id,
|
||||
|
@ -40,7 +40,7 @@ export const LibraryUnit = ({
|
|||
elements,
|
||||
appState: {
|
||||
exportBackground: false,
|
||||
viewBackgroundColor: oc.white,
|
||||
viewBackgroundColor: COLOR_PALETTE.white,
|
||||
},
|
||||
files: null,
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ import { focusNearestParent } from "../utils";
|
|||
|
||||
import "./ProjectName.scss";
|
||||
import { useExcalidrawContainer } from "./App";
|
||||
import { KEYS } from "../keys";
|
||||
|
||||
type Props = {
|
||||
value: string;
|
||||
|
@ -26,7 +27,7 @@ export const ProjectName = (props: Props) => {
|
|||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (event.key === "Enter") {
|
||||
if (event.key === KEYS.ENTER) {
|
||||
event.preventDefault();
|
||||
if (event.nativeEvent.isComposing || event.keyCode === 229) {
|
||||
return;
|
||||
|
|
|
@ -46,8 +46,17 @@
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
padding: 1rem 0.75rem;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
width: calc(100% - 1.5rem);
|
||||
height: 1px;
|
||||
background: var(--sidebar-border-color);
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar__header__buttons {
|
||||
|
@ -89,7 +98,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
padding: 1rem 0.75rem;
|
||||
padding: 1rem 0;
|
||||
|
||||
[role="tabpanel"] {
|
||||
flex: 1;
|
||||
|
@ -161,9 +170,5 @@
|
|||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar__header {
|
||||
border-bottom: 1px solid var(--sidebar-border-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ const MenuContent = ({
|
|||
<Island
|
||||
className="dropdown-menu-container"
|
||||
padding={2}
|
||||
style={{ zIndex: 1 }}
|
||||
style={{ zIndex: 2 }}
|
||||
>
|
||||
{children}
|
||||
</Island>
|
||||
|
|
100
src/components/hoc/withInternalFallback.test.tsx
Normal file
100
src/components/hoc/withInternalFallback.test.tsx
Normal file
|
@ -0,0 +1,100 @@
|
|||
import { render, queryAllByTestId } from "../../tests/test-utils";
|
||||
import { Excalidraw, MainMenu } from "../../packages/excalidraw/index";
|
||||
|
||||
describe("Test internal component fallback rendering", () => {
|
||||
it("should render only one menu per excalidraw instance (custom menu first scenario)", async () => {
|
||||
const { container } = await render(
|
||||
<div>
|
||||
<Excalidraw>
|
||||
<MainMenu>test</MainMenu>
|
||||
</Excalidraw>
|
||||
<Excalidraw />
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(queryAllByTestId(container, "dropdown-menu-button")?.length).toBe(2);
|
||||
|
||||
const excalContainers = container.querySelectorAll<HTMLDivElement>(
|
||||
".excalidraw-container",
|
||||
);
|
||||
|
||||
expect(
|
||||
queryAllByTestId(excalContainers[0], "dropdown-menu-button")?.length,
|
||||
).toBe(1);
|
||||
expect(
|
||||
queryAllByTestId(excalContainers[1], "dropdown-menu-button")?.length,
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it("should render only one menu per excalidraw instance (default menu first scenario)", async () => {
|
||||
const { container } = await render(
|
||||
<div>
|
||||
<Excalidraw />
|
||||
<Excalidraw>
|
||||
<MainMenu>test</MainMenu>
|
||||
</Excalidraw>
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(queryAllByTestId(container, "dropdown-menu-button")?.length).toBe(2);
|
||||
|
||||
const excalContainers = container.querySelectorAll<HTMLDivElement>(
|
||||
".excalidraw-container",
|
||||
);
|
||||
|
||||
expect(
|
||||
queryAllByTestId(excalContainers[0], "dropdown-menu-button")?.length,
|
||||
).toBe(1);
|
||||
expect(
|
||||
queryAllByTestId(excalContainers[1], "dropdown-menu-button")?.length,
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it("should render only one menu per excalidraw instance (two custom menus scenario)", async () => {
|
||||
const { container } = await render(
|
||||
<div>
|
||||
<Excalidraw>
|
||||
<MainMenu>test</MainMenu>
|
||||
</Excalidraw>
|
||||
<Excalidraw>
|
||||
<MainMenu>test</MainMenu>
|
||||
</Excalidraw>
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(queryAllByTestId(container, "dropdown-menu-button")?.length).toBe(2);
|
||||
|
||||
const excalContainers = container.querySelectorAll<HTMLDivElement>(
|
||||
".excalidraw-container",
|
||||
);
|
||||
|
||||
expect(
|
||||
queryAllByTestId(excalContainers[0], "dropdown-menu-button")?.length,
|
||||
).toBe(1);
|
||||
expect(
|
||||
queryAllByTestId(excalContainers[1], "dropdown-menu-button")?.length,
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it("should render only one menu per excalidraw instance (two default menus scenario)", async () => {
|
||||
const { container } = await render(
|
||||
<div>
|
||||
<Excalidraw />
|
||||
<Excalidraw />
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(queryAllByTestId(container, "dropdown-menu-button")?.length).toBe(2);
|
||||
|
||||
const excalContainers = container.querySelectorAll<HTMLDivElement>(
|
||||
".excalidraw-container",
|
||||
);
|
||||
|
||||
expect(
|
||||
queryAllByTestId(excalContainers[0], "dropdown-menu-button")?.length,
|
||||
).toBe(1);
|
||||
expect(
|
||||
queryAllByTestId(excalContainers[1], "dropdown-menu-button")?.length,
|
||||
).toBe(1);
|
||||
});
|
||||
});
|
|
@ -1,5 +1,5 @@
|
|||
import { atom, useAtom } from "jotai";
|
||||
import React, { useLayoutEffect } from "react";
|
||||
import React, { useLayoutEffect, useRef } from "react";
|
||||
import { useTunnels } from "../../context/tunnels";
|
||||
|
||||
export const withInternalFallback = <P,>(
|
||||
|
@ -7,13 +7,6 @@ export const withInternalFallback = <P,>(
|
|||
Component: React.FC<P>,
|
||||
) => {
|
||||
const renderAtom = atom(0);
|
||||
// flag set on initial render to tell the fallback component to skip the
|
||||
// render until mount counter are initialized. This is because the counter
|
||||
// is initialized in an effect, and thus we could end rendering both
|
||||
// components at the same time until counter is initialized.
|
||||
let preferHost = false;
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const WrapperComponent: React.FC<
|
||||
P & {
|
||||
|
@ -21,38 +14,52 @@ export const withInternalFallback = <P,>(
|
|||
}
|
||||
> = (props) => {
|
||||
const { jotaiScope } = useTunnels();
|
||||
const [, setRender] = useAtom(renderAtom, jotaiScope);
|
||||
// for rerenders
|
||||
const [, setCounter] = useAtom(renderAtom, jotaiScope);
|
||||
// for initial & subsequent renders. Tracked as component state
|
||||
// due to excalidraw multi-instance scanerios.
|
||||
const metaRef = useRef({
|
||||
// flag set on initial render to tell the fallback component to skip the
|
||||
// render until mount counter are initialized. This is because the counter
|
||||
// is initialized in an effect, and thus we could end rendering both
|
||||
// components at the same time until counter is initialized.
|
||||
preferHost: false,
|
||||
counter: 0,
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
setRender((c) => {
|
||||
const meta = metaRef.current;
|
||||
setCounter((c) => {
|
||||
const next = c + 1;
|
||||
counter = next;
|
||||
meta.counter = next;
|
||||
|
||||
return next;
|
||||
});
|
||||
return () => {
|
||||
setRender((c) => {
|
||||
setCounter((c) => {
|
||||
const next = c - 1;
|
||||
counter = next;
|
||||
meta.counter = next;
|
||||
if (!next) {
|
||||
preferHost = false;
|
||||
meta.preferHost = false;
|
||||
}
|
||||
return next;
|
||||
});
|
||||
};
|
||||
}, [setRender]);
|
||||
}, [setCounter]);
|
||||
|
||||
if (!props.__fallback) {
|
||||
preferHost = true;
|
||||
metaRef.current.preferHost = true;
|
||||
}
|
||||
|
||||
// ensure we don't render fallback and host components at the same time
|
||||
if (
|
||||
// either before the counters are initialized
|
||||
(!counter && props.__fallback && preferHost) ||
|
||||
(!metaRef.current.counter &&
|
||||
props.__fallback &&
|
||||
metaRef.current.preferHost) ||
|
||||
// or after the counters are initialized, and both are rendered
|
||||
// (this is the default when host renders as well)
|
||||
(counter > 1 && props.__fallback)
|
||||
(metaRef.current.counter > 1 && props.__fallback)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import cssVariables from "./css/variables.module.scss";
|
||||
import { AppProps } from "./types";
|
||||
import { ExcalidrawElement, FontFamilyValues } from "./element/types";
|
||||
import oc from "open-color";
|
||||
import { COLOR_PALETTE } from "./colors";
|
||||
|
||||
export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
||||
export const isWindows = /^Win/.test(navigator.platform);
|
||||
|
@ -131,6 +131,12 @@ export const MIME_TYPES = {
|
|||
...IMAGE_MIME_TYPES,
|
||||
} as const;
|
||||
|
||||
export const EXPORT_IMAGE_TYPES = {
|
||||
png: "png",
|
||||
svg: "svg",
|
||||
clipboard: "clipboard",
|
||||
} as const;
|
||||
|
||||
export const EXPORT_DATA_TYPES = {
|
||||
excalidraw: "excalidraw",
|
||||
excalidrawClipboard: "excalidraw/clipboard",
|
||||
|
@ -266,8 +272,8 @@ export const DEFAULT_ELEMENT_PROPS: {
|
|||
opacity: ExcalidrawElement["opacity"];
|
||||
locked: ExcalidrawElement["locked"];
|
||||
} = {
|
||||
strokeColor: oc.black,
|
||||
backgroundColor: "transparent",
|
||||
strokeColor: COLOR_PALETTE.black,
|
||||
backgroundColor: COLOR_PALETTE.transparent,
|
||||
fillStyle: "hachure",
|
||||
strokeWidth: 1,
|
||||
strokeStyle: "solid",
|
||||
|
|
|
@ -538,6 +538,10 @@
|
|||
height: 3px;
|
||||
}
|
||||
|
||||
select::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--scrollbar-thumb);
|
||||
border-radius: 10px;
|
||||
|
|
|
@ -35,7 +35,6 @@ import { LinearElementEditor } from "../element/linearElementEditor";
|
|||
import { bumpVersion } from "../element/mutateElement";
|
||||
import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils";
|
||||
import { arrayToMap } from "../utils";
|
||||
import oc from "open-color";
|
||||
import { MarkOptional, Mutable } from "../utility-types";
|
||||
import {
|
||||
detectLineHeight,
|
||||
|
@ -43,6 +42,7 @@ import {
|
|||
measureBaseline,
|
||||
} from "../element/textElement";
|
||||
import { convertToExcalidrawElements } from "../element/newElement";
|
||||
import { COLOR_PALETTE } from "../colors";
|
||||
|
||||
type RestoredAppState = Omit<
|
||||
AppState,
|
||||
|
|
|
@ -1521,7 +1521,7 @@ describe("textWysiwyg", () => {
|
|||
roundness: {
|
||||
type: 3,
|
||||
},
|
||||
strokeColor: "#000000",
|
||||
strokeColor: "#1e1e1e",
|
||||
strokeStyle: "solid",
|
||||
strokeWidth: 1,
|
||||
type: "rectangle",
|
||||
|
|
|
@ -254,7 +254,6 @@ export const textWysiwyg = ({
|
|||
const initialSelectionStart = editable.selectionStart;
|
||||
const initialSelectionEnd = editable.selectionEnd;
|
||||
const initialLength = editable.value.length;
|
||||
editable.value = updatedTextElement.originalText;
|
||||
|
||||
// restore cursor position after value updated so it doesn't
|
||||
// go to the end of text when container auto expanded
|
||||
|
@ -358,6 +357,7 @@ export const textWysiwyg = ({
|
|||
overflowWrap: "break-word",
|
||||
boxSizing: "content-box",
|
||||
});
|
||||
editable.value = element.originalText;
|
||||
updateWysiwygStyle();
|
||||
|
||||
if (onChange) {
|
||||
|
@ -636,20 +636,46 @@ export const textWysiwyg = ({
|
|||
// in that same tick.
|
||||
const target = event?.target;
|
||||
|
||||
const isTargetColorPicker =
|
||||
target instanceof HTMLInputElement &&
|
||||
target.closest(".color-picker-input") &&
|
||||
isWritableElement(target);
|
||||
const isTargetPickerTrigger =
|
||||
target instanceof HTMLElement &&
|
||||
target.classList.contains("active-color");
|
||||
|
||||
setTimeout(() => {
|
||||
editable.onblur = handleSubmit;
|
||||
if (target && isTargetColorPicker) {
|
||||
target.onblur = () => {
|
||||
editable.focus();
|
||||
|
||||
if (isTargetPickerTrigger) {
|
||||
const callback = (
|
||||
mutationList: MutationRecord[],
|
||||
observer: MutationObserver,
|
||||
) => {
|
||||
const radixIsRemoved = mutationList.find(
|
||||
(mutation) =>
|
||||
mutation.removedNodes.length > 0 &&
|
||||
(mutation.removedNodes[0] as HTMLElement).dataset
|
||||
?.radixPopperContentWrapper !== undefined,
|
||||
);
|
||||
|
||||
if (radixIsRemoved) {
|
||||
// should work without this in theory
|
||||
// and i think it does actually but radix probably somewhere,
|
||||
// somehow sets the focus elsewhere
|
||||
setTimeout(() => {
|
||||
editable.focus();
|
||||
});
|
||||
|
||||
observer.disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
const observer = new MutationObserver(callback);
|
||||
|
||||
observer.observe(document.querySelector(".excalidraw-container")!, {
|
||||
childList: true,
|
||||
});
|
||||
}
|
||||
|
||||
// case: clicking on the same property → no change → no update → no focus
|
||||
if (!isTargetColorPicker) {
|
||||
if (!isTargetPickerTrigger) {
|
||||
editable.focus();
|
||||
}
|
||||
});
|
||||
|
@ -657,16 +683,16 @@ export const textWysiwyg = ({
|
|||
|
||||
// prevent blur when changing properties from the menu
|
||||
const onPointerDown = (event: MouseEvent) => {
|
||||
const isTargetColorPicker =
|
||||
event.target instanceof HTMLInputElement &&
|
||||
event.target.closest(".color-picker-input") &&
|
||||
isWritableElement(event.target);
|
||||
const isTargetPickerTrigger =
|
||||
event.target instanceof HTMLElement &&
|
||||
event.target.classList.contains("active-color");
|
||||
|
||||
if (
|
||||
((event.target instanceof HTMLElement ||
|
||||
event.target instanceof SVGElement) &&
|
||||
event.target.closest(`.${CLASSES.SHAPE_ACTIONS_MENU}`) &&
|
||||
!isWritableElement(event.target)) ||
|
||||
isTargetColorPicker
|
||||
isTargetPickerTrigger
|
||||
) {
|
||||
editable.onblur = null;
|
||||
window.addEventListener("pointerup", bindBlurEvent);
|
||||
|
@ -680,7 +706,7 @@ export const textWysiwyg = ({
|
|||
const unbindUpdate = Scene.getScene(element)!.addCallback(() => {
|
||||
updateWysiwygStyle();
|
||||
const isColorPickerActive = !!document.activeElement?.closest(
|
||||
".color-picker-input",
|
||||
".color-picker-content",
|
||||
);
|
||||
if (!isColorPickerActive) {
|
||||
editable.focus();
|
||||
|
|
|
@ -17,6 +17,7 @@ import { trackEvent } from "../../analytics";
|
|||
import { getFrame } from "../../utils";
|
||||
import DialogActionButton from "../../components/DialogActionButton";
|
||||
import { useI18n } from "../../i18n";
|
||||
import { KEYS } from "../../keys";
|
||||
|
||||
const getShareIcon = () => {
|
||||
const navigator = window.navigator as any;
|
||||
|
@ -148,13 +149,15 @@ const RoomDialog = ({
|
|||
value={username.trim() || ""}
|
||||
className="RoomDialog-username TextInput"
|
||||
onChange={(event) => onUsernameChange(event.target.value)}
|
||||
onKeyPress={(event) => event.key === "Enter" && handleClose()}
|
||||
onKeyPress={(event) =>
|
||||
event.key === KEYS.ENTER && handleClose()
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
<span role="img" aria-hidden="true" className="RoomDialog-emoji">
|
||||
{"🔒"}
|
||||
</span>{" "}
|
||||
</span>
|
||||
{t("roomDialog.desc_privacy")}
|
||||
</p>
|
||||
<p>{t("roomDialog.desc_exitSession")}</p>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useSetAtom } from "jotai";
|
||||
import React from "react";
|
||||
import { appLangCodeAtom } from "..";
|
||||
import { defaultLang, useI18n } from "../../i18n";
|
||||
import { useI18n } from "../../i18n";
|
||||
import { languages } from "../../i18n";
|
||||
|
||||
export const LanguageList = ({ style }: { style?: React.CSSProperties }) => {
|
||||
|
@ -16,9 +16,6 @@ export const LanguageList = ({ style }: { style?: React.CSSProperties }) => {
|
|||
aria-label={t("buttons.selectLanguage")}
|
||||
style={style}
|
||||
>
|
||||
<option key={defaultLang.code} value={defaultLang.code}>
|
||||
{defaultLang.label}
|
||||
</option>
|
||||
{languages.map((lang) => (
|
||||
<option key={lang.code} value={lang.code}>
|
||||
{lang.label}
|
||||
|
|
123
src/i18n.ts
123
src/i18n.ts
|
@ -14,60 +14,61 @@ export interface Language {
|
|||
|
||||
export const defaultLang = { code: "en", label: "English" };
|
||||
|
||||
const allLanguages: Language[] = [
|
||||
{ code: "ar-SA", label: "العربية", rtl: true },
|
||||
{ code: "bg-BG", label: "Български" },
|
||||
{ code: "ca-ES", label: "Català" },
|
||||
{ code: "cs-CZ", label: "Česky" },
|
||||
{ code: "de-DE", label: "Deutsch" },
|
||||
{ code: "el-GR", label: "Ελληνικά" },
|
||||
{ code: "es-ES", label: "Español" },
|
||||
{ code: "eu-ES", label: "Euskara" },
|
||||
{ code: "fa-IR", label: "فارسی", rtl: true },
|
||||
{ code: "fi-FI", label: "Suomi" },
|
||||
{ code: "fr-FR", label: "Français" },
|
||||
{ code: "gl-ES", label: "Galego" },
|
||||
{ code: "he-IL", label: "עברית", rtl: true },
|
||||
{ code: "hi-IN", label: "हिन्दी" },
|
||||
{ code: "hu-HU", label: "Magyar" },
|
||||
{ code: "id-ID", label: "Bahasa Indonesia" },
|
||||
{ code: "it-IT", label: "Italiano" },
|
||||
{ code: "ja-JP", label: "日本語" },
|
||||
{ code: "kab-KAB", label: "Taqbaylit" },
|
||||
{ code: "kk-KZ", label: "Қазақ тілі" },
|
||||
{ code: "ko-KR", label: "한국어" },
|
||||
{ code: "ku-TR", label: "Kurdî" },
|
||||
{ code: "lt-LT", label: "Lietuvių" },
|
||||
{ code: "lv-LV", label: "Latviešu" },
|
||||
{ code: "my-MM", label: "Burmese" },
|
||||
{ code: "nb-NO", label: "Norsk bokmål" },
|
||||
{ code: "nl-NL", label: "Nederlands" },
|
||||
{ code: "nn-NO", label: "Norsk nynorsk" },
|
||||
{ code: "oc-FR", label: "Occitan" },
|
||||
{ code: "pa-IN", label: "ਪੰਜਾਬੀ" },
|
||||
{ code: "pl-PL", label: "Polski" },
|
||||
{ code: "pt-BR", label: "Português Brasileiro" },
|
||||
{ code: "pt-PT", label: "Português" },
|
||||
{ code: "ro-RO", label: "Română" },
|
||||
{ code: "ru-RU", label: "Русский" },
|
||||
{ code: "sk-SK", label: "Slovenčina" },
|
||||
{ code: "sv-SE", label: "Svenska" },
|
||||
{ code: "sl-SI", label: "Slovenščina" },
|
||||
{ code: "tr-TR", label: "Türkçe" },
|
||||
{ code: "uk-UA", label: "Українська" },
|
||||
{ code: "zh-CN", label: "简体中文" },
|
||||
{ code: "zh-TW", label: "繁體中文" },
|
||||
{ code: "vi-VN", label: "Tiếng Việt" },
|
||||
{ code: "mr-IN", label: "मराठी" },
|
||||
].concat([defaultLang]);
|
||||
|
||||
export const languages: Language[] = allLanguages
|
||||
.sort((left, right) => (left.label > right.label ? 1 : -1))
|
||||
.filter(
|
||||
(lang) =>
|
||||
(percentages as Record<string, number>)[lang.code] >=
|
||||
COMPLETION_THRESHOLD,
|
||||
);
|
||||
export const languages: Language[] = [
|
||||
defaultLang,
|
||||
...[
|
||||
{ code: "ar-SA", label: "العربية", rtl: true },
|
||||
{ code: "bg-BG", label: "Български" },
|
||||
{ code: "ca-ES", label: "Català" },
|
||||
{ code: "cs-CZ", label: "Česky" },
|
||||
{ code: "de-DE", label: "Deutsch" },
|
||||
{ code: "el-GR", label: "Ελληνικά" },
|
||||
{ code: "es-ES", label: "Español" },
|
||||
{ code: "eu-ES", label: "Euskara" },
|
||||
{ code: "fa-IR", label: "فارسی", rtl: true },
|
||||
{ code: "fi-FI", label: "Suomi" },
|
||||
{ code: "fr-FR", label: "Français" },
|
||||
{ code: "gl-ES", label: "Galego" },
|
||||
{ code: "he-IL", label: "עברית", rtl: true },
|
||||
{ code: "hi-IN", label: "हिन्दी" },
|
||||
{ code: "hu-HU", label: "Magyar" },
|
||||
{ code: "id-ID", label: "Bahasa Indonesia" },
|
||||
{ code: "it-IT", label: "Italiano" },
|
||||
{ code: "ja-JP", label: "日本語" },
|
||||
{ code: "kab-KAB", label: "Taqbaylit" },
|
||||
{ code: "kk-KZ", label: "Қазақ тілі" },
|
||||
{ code: "ko-KR", label: "한국어" },
|
||||
{ code: "ku-TR", label: "Kurdî" },
|
||||
{ code: "lt-LT", label: "Lietuvių" },
|
||||
{ code: "lv-LV", label: "Latviešu" },
|
||||
{ code: "my-MM", label: "Burmese" },
|
||||
{ code: "nb-NO", label: "Norsk bokmål" },
|
||||
{ code: "nl-NL", label: "Nederlands" },
|
||||
{ code: "nn-NO", label: "Norsk nynorsk" },
|
||||
{ code: "oc-FR", label: "Occitan" },
|
||||
{ code: "pa-IN", label: "ਪੰਜਾਬੀ" },
|
||||
{ code: "pl-PL", label: "Polski" },
|
||||
{ code: "pt-BR", label: "Português Brasileiro" },
|
||||
{ code: "pt-PT", label: "Português" },
|
||||
{ code: "ro-RO", label: "Română" },
|
||||
{ code: "ru-RU", label: "Русский" },
|
||||
{ code: "sk-SK", label: "Slovenčina" },
|
||||
{ code: "sv-SE", label: "Svenska" },
|
||||
{ code: "sl-SI", label: "Slovenščina" },
|
||||
{ code: "tr-TR", label: "Türkçe" },
|
||||
{ code: "uk-UA", label: "Українська" },
|
||||
{ code: "zh-CN", label: "简体中文" },
|
||||
{ code: "zh-TW", label: "繁體中文" },
|
||||
{ code: "vi-VN", label: "Tiếng Việt" },
|
||||
{ code: "mr-IN", label: "मराठी" },
|
||||
]
|
||||
.filter(
|
||||
(lang) =>
|
||||
(percentages as Record<string, number>)[lang.code] >=
|
||||
COMPLETION_THRESHOLD,
|
||||
)
|
||||
.sort((left, right) => (left.label > right.label ? 1 : -1)),
|
||||
];
|
||||
|
||||
const TEST_LANG_CODE = "__test__";
|
||||
if (process.env.NODE_ENV === ENV.DEVELOPMENT) {
|
||||
|
@ -123,7 +124,8 @@ const findPartsForData = (data: any, parts: string[]) => {
|
|||
|
||||
export const t = (
|
||||
path: string,
|
||||
replacement?: { [key: string]: string | number },
|
||||
replacement?: { [key: string]: string | number } | null,
|
||||
fallback?: string,
|
||||
) => {
|
||||
if (currentLang.code.startsWith(TEST_LANG_CODE)) {
|
||||
const name = replacement
|
||||
|
@ -135,9 +137,16 @@ export const t = (
|
|||
const parts = path.split(".");
|
||||
let translation =
|
||||
findPartsForData(currentLangData, parts) ||
|
||||
findPartsForData(fallbackLangData, parts);
|
||||
findPartsForData(fallbackLangData, parts) ||
|
||||
fallback;
|
||||
if (translation === undefined) {
|
||||
throw new Error(`Can't find translation for ${path}`);
|
||||
const errorMessage = `Can't find translation for ${path}`;
|
||||
// in production, don't blow up the app on a missing translation key
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
console.warn(errorMessage);
|
||||
return "";
|
||||
}
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
if (replacement) {
|
||||
|
|
|
@ -264,16 +264,11 @@
|
|||
"canvasTooBigTip": "نصيحة: حاول تحريك العناصر البعيدة بشكل أقرب قليلاً."
|
||||
},
|
||||
"errorSplash": {
|
||||
"headingMain_pre": "حدث خطأ، حاول مرة أخرى ",
|
||||
"headingMain_button": "إعادة تحميل الصفحة.",
|
||||
"headingMain": "",
|
||||
"clearCanvasMessage": "إذا لم تعمل إعادة التحميل، حاول مرة أخرى ",
|
||||
"clearCanvasMessage_button": "مسح اللوحة.",
|
||||
"clearCanvasCaveat": " هذا سيؤدي إلى فقدان العمل ",
|
||||
"trackedToSentry_pre": "الخطأ ",
|
||||
"trackedToSentry_post": " تم تعقبه على نظامنا.",
|
||||
"openIssueMessage_pre": "كنا حذرين جدا لعدم تضمين معلومات المشهد الخاصة بك في الخطأ. إذا لم يكن المشهد خاصًا ، يرجى النظر في متابعة هذا الأمر ",
|
||||
"openIssueMessage_button": "متعقّب الخلل.",
|
||||
"openIssueMessage_post": " يرجى تضمين المعلومات أدناة عن طريق نسخ ولصق المشكلة في GitHub.",
|
||||
"trackedToSentry": "",
|
||||
"openIssueMessage": "",
|
||||
"sceneContent": "محتوى المشهد:"
|
||||
},
|
||||
"roomDialog": {
|
||||
|
@ -353,29 +348,16 @@
|
|||
"required": "مطلوب",
|
||||
"website": "أدخل عنوان URL صالح"
|
||||
},
|
||||
"noteDescription": {
|
||||
"pre": "",
|
||||
"link": "مستودع المكتبة العامة",
|
||||
"post": "ليستخدمها الآخرون في رسوماتهم."
|
||||
},
|
||||
"noteGuidelines": {
|
||||
"pre": "يجب الموافقة على المكتبة يدويًا أولاً. يرجى قراءة ",
|
||||
"link": "الإرشادات",
|
||||
"post": ""
|
||||
},
|
||||
"noteLicense": {
|
||||
"pre": "",
|
||||
"link": "رخصة إم أي تي ",
|
||||
"post": "وهو ما يعني باختصار أنه يمكن لأي شخص استخدامها دون قيود."
|
||||
},
|
||||
"noteDescription": "",
|
||||
"noteGuidelines": "",
|
||||
"noteLicense": "",
|
||||
"noteItems": "يجب أن يكون لكل عنصر مكتبة اسمه الخاص حتى يكون قابلاً للتصفية. سيتم تضمين عناصر المكتبة التالية:",
|
||||
"atleastOneLibItem": "يرجى تحديد عنصر مكتبة واحد على الأقل للبدء",
|
||||
"republishWarning": ""
|
||||
},
|
||||
"publishSuccessDialog": {
|
||||
"title": "تم إرسال المكتبة",
|
||||
"content": "شكرا لك {{authorName}}. لقد تم إرسال مكتبتك للمراجعة. يمكنك تتبع الحالة",
|
||||
"link": "هنا"
|
||||
"content": "شكرا لك {{authorName}}. لقد تم إرسال مكتبتك للمراجعة. يمكنك تتبع الحالة"
|
||||
},
|
||||
"confirmDialog": {
|
||||
"resetLibrary": "إعادة ضبط المكتبة",
|
||||
|
@ -412,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "أبيض",
|
||||
"f8f9fa": "رمادي 0",
|
||||
"f1f3f5": "رمادي 1",
|
||||
"fff5f5": "أحمر 0",
|
||||
"fff0f6": "وردي 0",
|
||||
"f8f0fc": "عنبي 0",
|
||||
"f3f0ff": "بنفسجي 0",
|
||||
"edf2ff": "نيلي 0",
|
||||
"e7f5ff": "أزرق 0",
|
||||
"e3fafc": "سماوي 0",
|
||||
"e6fcf5": "تركواز 0",
|
||||
"ebfbee": "أخضر 0",
|
||||
"f4fce3": "ليموني 0",
|
||||
"fff9db": "أصفر 0",
|
||||
"fff4e6": "برتقالي 0",
|
||||
"transparent": "شفاف",
|
||||
"ced4da": "رمادي 4",
|
||||
"868e96": "رمادي 6",
|
||||
"fa5252": "أحمر 6",
|
||||
"e64980": "وردي 6",
|
||||
"be4bdb": "عنبي 6",
|
||||
"7950f2": "بنفسجي 6",
|
||||
"4c6ef5": "نيلي 6",
|
||||
"228be6": "أزرق 6",
|
||||
"15aabf": "سماوي 6",
|
||||
"12b886": "تركواز 6",
|
||||
"40c057": "أخضر 6",
|
||||
"82c91e": "ليموني 6",
|
||||
"fab005": "أصفر 6",
|
||||
"fd7e14": "برتقالي 6",
|
||||
"000000": "أسود",
|
||||
"343a40": "رمادي 8",
|
||||
"495057": "رمادي 7",
|
||||
"c92a2a": "أحمر 9",
|
||||
"a61e4d": "وردي 9",
|
||||
"862e9c": "عنبي 9",
|
||||
"5f3dc4": "بنفسجي 9",
|
||||
"364fc7": "نيلي 9",
|
||||
"1864ab": "أزرق 9",
|
||||
"0b7285": "سماوي 9",
|
||||
"087f5b": "تركواز 9",
|
||||
"2b8a3e": "أخضر 9",
|
||||
"5c940d": "ليموني 9",
|
||||
"e67700": "أصفر 9",
|
||||
"d9480f": "برتقالي 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -470,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "",
|
||||
"fff4e6": "",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "",
|
||||
"82c91e": "",
|
||||
"fab005": "",
|
||||
"fd7e14": "",
|
||||
"000000": "",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "",
|
||||
"5c940d": "",
|
||||
"e67700": "",
|
||||
"d9480f": ""
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "সাদা",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "",
|
||||
"fff4e6": "",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "",
|
||||
"82c91e": "",
|
||||
"fab005": "",
|
||||
"fd7e14": "",
|
||||
"000000": "কালো",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "",
|
||||
"5c940d": "",
|
||||
"e67700": "",
|
||||
"d9480f": ""
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Fer servir {{shortcut}} per enganxar com un sol element,\no enganxeu-lo en un editor de text existent"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Blanc",
|
||||
"f8f9fa": "Gris 0",
|
||||
"f1f3f5": "Gris 1",
|
||||
"fff5f5": "Vermell 0",
|
||||
"fff0f6": "Rosa 0",
|
||||
"f8f0fc": "Malva 0",
|
||||
"f3f0ff": "Violat 0",
|
||||
"edf2ff": "Indi 0",
|
||||
"e7f5ff": "Blau 0",
|
||||
"e3fafc": "Cian 0",
|
||||
"e6fcf5": "Xarxet 0",
|
||||
"ebfbee": "Verd 0",
|
||||
"f4fce3": "Llima 0",
|
||||
"fff9db": "Groc 0",
|
||||
"fff4e6": "Taronja 0",
|
||||
"transparent": "Transparent",
|
||||
"ced4da": "Gris 4",
|
||||
"868e96": "Gris 6",
|
||||
"fa5252": "Vermell 6",
|
||||
"e64980": "Rosa 6",
|
||||
"be4bdb": "Malva 6",
|
||||
"7950f2": "Violat 6",
|
||||
"4c6ef5": "Indi 6",
|
||||
"228be6": "Blau 6",
|
||||
"15aabf": "Cian 6",
|
||||
"12b886": "Xarxet 6",
|
||||
"40c057": "Verd 6",
|
||||
"82c91e": "Llima 6",
|
||||
"fab005": "Groc 6",
|
||||
"fd7e14": "Taronja 6",
|
||||
"000000": "Negre",
|
||||
"343a40": "Gris 8",
|
||||
"495057": "Gris 7",
|
||||
"c92a2a": "Vermell 9",
|
||||
"a61e4d": "Rosa 9",
|
||||
"862e9c": "Malva 9",
|
||||
"5f3dc4": "Violat 9",
|
||||
"364fc7": "Indi 9",
|
||||
"1864ab": "Blau 9",
|
||||
"0b7285": "Cian 9",
|
||||
"087f5b": "Xarxet 9",
|
||||
"2b8a3e": "Verd 9",
|
||||
"5c940d": "Llima 9",
|
||||
"e67700": "Groc 9",
|
||||
"d9480f": "Taronja 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Selecciona una eina i comença a dibuixar!",
|
||||
"helpHint": "Dreceres i ajuda"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Bílá",
|
||||
"f8f9fa": "Šedá 0",
|
||||
"f1f3f5": "Šedá 1",
|
||||
"fff5f5": "Červená 0",
|
||||
"fff0f6": "Růžová 0",
|
||||
"f8f0fc": "Vínová 0",
|
||||
"f3f0ff": "Fialová 0",
|
||||
"edf2ff": "Indigová 0",
|
||||
"e7f5ff": "Modrá 0",
|
||||
"e3fafc": "Azurová 0",
|
||||
"e6fcf5": "Modrozelená 0",
|
||||
"ebfbee": "Zelená 0",
|
||||
"f4fce3": "Limetková 0",
|
||||
"fff9db": "Žlutá 0",
|
||||
"fff4e6": "Oranžová 0",
|
||||
"transparent": "Průhledná",
|
||||
"ced4da": "Šedá 4",
|
||||
"868e96": "Šedá 6",
|
||||
"fa5252": "Červená 6",
|
||||
"e64980": "Růžová 6",
|
||||
"be4bdb": "Vínová 6",
|
||||
"7950f2": "Fialová 6",
|
||||
"4c6ef5": "Indigová 6",
|
||||
"228be6": "Modrá 6",
|
||||
"15aabf": "Azurová 6",
|
||||
"12b886": "Modrozelená 6",
|
||||
"40c057": "Zelená 6",
|
||||
"82c91e": "Limetková 6",
|
||||
"fab005": "Žlutá 6",
|
||||
"fd7e14": "Oranžová 6",
|
||||
"000000": "Černá",
|
||||
"343a40": "Šedá 8",
|
||||
"495057": "Šedá 7",
|
||||
"c92a2a": "Červená 9",
|
||||
"a61e4d": "Růžová 9",
|
||||
"862e9c": "Vínová 9",
|
||||
"5f3dc4": "Fialová 9",
|
||||
"364fc7": "Indigová 9",
|
||||
"1864ab": "Modrá 9",
|
||||
"0b7285": "Azurová 9",
|
||||
"087f5b": "Modrozelená 9",
|
||||
"2b8a3e": "Zelená 9",
|
||||
"5c940d": "Limetková 9",
|
||||
"e67700": "Žlutá 9",
|
||||
"d9480f": "Oranzova"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "",
|
||||
"fff4e6": "",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "",
|
||||
"82c91e": "",
|
||||
"fab005": "",
|
||||
"fd7e14": "",
|
||||
"000000": "",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "",
|
||||
"5c940d": "",
|
||||
"e67700": "",
|
||||
"d9480f": ""
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,7 +268,7 @@
|
|||
"clearCanvasMessage": "Wenn das Neuladen nicht funktioniert, versuche <button>die Zeichenfläche zu löschen.</button>",
|
||||
"clearCanvasCaveat": " Dies wird zum Verlust von Daten führen ",
|
||||
"trackedToSentry": "Der Fehler mit der Kennung {{eventId}} wurde in unserem System registriert.",
|
||||
"openIssueMessage": "Wir waren sehr vorsichtig und haben deine Zeichnungsinformationen nicht in die Fehlerinformationen aufgenommen. Wenn deine Zeichnung nicht privat ist, unterstütze uns bitte über unseren <button>Bug-Tracker.</button> Bitte teile die unten stehenden Informationen mit uns im GitHub Issue (Kopieren und Einfügen).",
|
||||
"openIssueMessage": "Wir waren sehr vorsichtig und haben deine Zeichnungsinformationen nicht in die Fehlerinformationen aufgenommen. Wenn deine Zeichnung nicht privat ist, unterstütze uns bitte über unseren <button>Bug-Tracker</button>. Bitte teile die unten stehenden Informationen mit uns im GitHub Issue (Kopieren und Einfügen).",
|
||||
"sceneContent": "Zeichnungsinhalt:"
|
||||
},
|
||||
"roomDialog": {
|
||||
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Verwende {{shortcut}} , um als einzelnes Element\neinzufügen oder in einen existierenden Texteditor einzufügen"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Weiß",
|
||||
"f8f9fa": "Grau 0",
|
||||
"f1f3f5": "Grau 1",
|
||||
"fff5f5": "Rot 0",
|
||||
"fff0f6": "Pink 0",
|
||||
"f8f0fc": "Traube 0",
|
||||
"f3f0ff": "Violett 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Blau 0",
|
||||
"e3fafc": "Cyan 0",
|
||||
"e6fcf5": "Teal 0",
|
||||
"ebfbee": "Grün 0",
|
||||
"f4fce3": "Hellgrün 0",
|
||||
"fff9db": "Gelb 0",
|
||||
"fff4e6": "Orange 0",
|
||||
"transparent": "Transparent",
|
||||
"ced4da": "Grau 4",
|
||||
"868e96": "Grau 6",
|
||||
"fa5252": "Rot 6",
|
||||
"e64980": "Pink 6",
|
||||
"be4bdb": "Traube 6",
|
||||
"7950f2": "Violett 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Blau 6",
|
||||
"15aabf": "Cyan 6",
|
||||
"12b886": "Teal 6",
|
||||
"40c057": "Grün 6",
|
||||
"82c91e": "Hellgrün 6",
|
||||
"fab005": "Gelb 6",
|
||||
"fd7e14": "Orange 6",
|
||||
"000000": "Schwarz",
|
||||
"343a40": "Grau 8",
|
||||
"495057": "Grau 7",
|
||||
"c92a2a": "Rot 9",
|
||||
"a61e4d": "Pink 9",
|
||||
"862e9c": "Traube 9",
|
||||
"5f3dc4": "Violett 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Blau 9",
|
||||
"0b7285": "Cyan 9",
|
||||
"087f5b": "Teal 9",
|
||||
"2b8a3e": "Grün 9",
|
||||
"5c940d": "Hellgrün 9",
|
||||
"e67700": "Gelb 9",
|
||||
"d9480f": "Orange 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Wähle ein Werkzeug & beginne zu zeichnen!",
|
||||
"helpHint": "Kurzbefehle & Hilfe"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Χρησιμοποίησε το {{shortcut}} για να επικολλήσεις ως ένα μόνο στοιχείο,\nή να επικολλήσεις σε έναν υπάρχοντα επεξεργαστή κειμένου"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Λευκό",
|
||||
"f8f9fa": "Γκρι 0",
|
||||
"f1f3f5": "Γκρι 1",
|
||||
"fff5f5": "Κόκκινο 0",
|
||||
"fff0f6": "Ροζ 0",
|
||||
"f8f0fc": "Σταφυλί 0",
|
||||
"f3f0ff": "Βιολετί 0",
|
||||
"edf2ff": "Λουλάκι 0",
|
||||
"e7f5ff": "Μπλε 0",
|
||||
"e3fafc": "Κυανό 0",
|
||||
"e6fcf5": "Τιρκουάζ 0",
|
||||
"ebfbee": "Πράσινο 0",
|
||||
"f4fce3": "Πρασινοκίτρινο 0",
|
||||
"fff9db": "Κίτρινο 0",
|
||||
"fff4e6": "Πορτοκαλί 0",
|
||||
"transparent": "Διαφανές",
|
||||
"ced4da": "Γκρι 4",
|
||||
"868e96": "Γκρι 6",
|
||||
"fa5252": "Κόκκινο 6",
|
||||
"e64980": "Ροζ 6",
|
||||
"be4bdb": "Σταφυλί 6",
|
||||
"7950f2": "Βιολετί 6",
|
||||
"4c6ef5": "Λουλάκι 6",
|
||||
"228be6": "Μπλε 6",
|
||||
"15aabf": "Κυανό 6",
|
||||
"12b886": "Τιρκουάζ 6",
|
||||
"40c057": "Πράσινο 6",
|
||||
"82c91e": "Πρασινοκίτρινο 6",
|
||||
"fab005": "Κίτρινο 6",
|
||||
"fd7e14": "Πορτοκαλί 6",
|
||||
"000000": "Μαύρο",
|
||||
"343a40": "Γκρι 8",
|
||||
"495057": "Γκρι 7",
|
||||
"c92a2a": "Κόκκινο 9",
|
||||
"a61e4d": "Ροζ 9",
|
||||
"862e9c": "Σταφυλί 9",
|
||||
"5f3dc4": "Βιολετί 9",
|
||||
"364fc7": "Λουλάκι 9",
|
||||
"1864ab": "Μπλε 9",
|
||||
"0b7285": "Κυανό 9",
|
||||
"087f5b": "Τιρκουάζ 9",
|
||||
"2b8a3e": "Πράσινο 9",
|
||||
"5c940d": "Πρασινοκίτρινο 9",
|
||||
"e67700": "Κίτρινο 9",
|
||||
"d9480f": "Πορτοκαλί 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Επιλέξτε ένα εργαλείο και ξεκινήστε να σχεδιάζεται!",
|
||||
"helpHint": "Συντομεύσεις και βοήθεια"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Use {{shortcut}} to paste as a single element,\nor paste into an existing text editor"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "White",
|
||||
"f8f9fa": "Gray 0",
|
||||
"f1f3f5": "Gray 1",
|
||||
"fff5f5": "Red 0",
|
||||
"fff0f6": "Pink 0",
|
||||
"f8f0fc": "Grape 0",
|
||||
"f3f0ff": "Violet 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Blue 0",
|
||||
"e3fafc": "Cyan 0",
|
||||
"e6fcf5": "Teal 0",
|
||||
"ebfbee": "Green 0",
|
||||
"f4fce3": "Lime 0",
|
||||
"fff9db": "Yellow 0",
|
||||
"fff4e6": "Orange 0",
|
||||
"transparent": "Transparent",
|
||||
"ced4da": "Gray 4",
|
||||
"868e96": "Gray 6",
|
||||
"fa5252": "Red 6",
|
||||
"e64980": "Pink 6",
|
||||
"be4bdb": "Grape 6",
|
||||
"7950f2": "Violet 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Blue 6",
|
||||
"15aabf": "Cyan 6",
|
||||
"12b886": "Teal 6",
|
||||
"40c057": "Green 6",
|
||||
"82c91e": "Lime 6",
|
||||
"fab005": "Yellow 6",
|
||||
"fd7e14": "Orange 6",
|
||||
"000000": "Black",
|
||||
"343a40": "Gray 8",
|
||||
"495057": "Gray 7",
|
||||
"c92a2a": "Red 9",
|
||||
"a61e4d": "Pink 9",
|
||||
"862e9c": "Grape 9",
|
||||
"5f3dc4": "Violet 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Blue 9",
|
||||
"0b7285": "Cyan 9",
|
||||
"087f5b": "Teal 9",
|
||||
"2b8a3e": "Green 9",
|
||||
"5c940d": "Lime 9",
|
||||
"e67700": "Yellow 9",
|
||||
"d9480f": "Orange 9"
|
||||
"black": "Black",
|
||||
"white": "White",
|
||||
"red": "Red",
|
||||
"pink": "Pink",
|
||||
"grape": "Grape",
|
||||
"violet": "Violet",
|
||||
"gray": "Gray",
|
||||
"blue": "Blue",
|
||||
"cyan": "Cyan",
|
||||
"teal": "Teal",
|
||||
"green": "Green",
|
||||
"yellow": "Yellow",
|
||||
"orange": "Orange",
|
||||
"bronze": "Bronze"
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Pick a tool & Start drawing!",
|
||||
"helpHint": "Shortcuts & help"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "Most used custom colors",
|
||||
"colors": "Colors",
|
||||
"shades": "Shades",
|
||||
"hexCode": "Hex code",
|
||||
"noShades": "No shades available for this color"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Usa {{shortcut}} para pegar como un solo elemento,\no pegar en un editor de texto existente"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Blanco",
|
||||
"f8f9fa": "Gris 0",
|
||||
"f1f3f5": "Gris 1",
|
||||
"fff5f5": "Rojo 0",
|
||||
"fff0f6": "Rosa 0",
|
||||
"f8f0fc": "Uva 0",
|
||||
"f3f0ff": "Violeta 0",
|
||||
"edf2ff": "Índigo 0",
|
||||
"e7f5ff": "Azul 0",
|
||||
"e3fafc": "Cian 0",
|
||||
"e6fcf5": "Turquesa 0",
|
||||
"ebfbee": "Verde 0",
|
||||
"f4fce3": "Lima 0",
|
||||
"fff9db": "Amarillo 0",
|
||||
"fff4e6": "Naranja 0",
|
||||
"transparent": "Transparente",
|
||||
"ced4da": "Gris 4",
|
||||
"868e96": "Gris 6",
|
||||
"fa5252": "Rojo 6",
|
||||
"e64980": "Rosa 6",
|
||||
"be4bdb": "Uva 6",
|
||||
"7950f2": "Violeta 6",
|
||||
"4c6ef5": "Índigo 6",
|
||||
"228be6": "Azul 6",
|
||||
"15aabf": "Cian 6",
|
||||
"12b886": "Turquesa 6",
|
||||
"40c057": "Verde 6",
|
||||
"82c91e": "Lima 6",
|
||||
"fab005": "Amarillo 6",
|
||||
"fd7e14": "Naranja 6",
|
||||
"000000": "Negro",
|
||||
"343a40": "Gris 8",
|
||||
"495057": "Gris 7",
|
||||
"c92a2a": "Rojo 9",
|
||||
"a61e4d": "Rosa 9",
|
||||
"862e9c": "Uva 9",
|
||||
"5f3dc4": "Violeta 9",
|
||||
"364fc7": "Índigo 9",
|
||||
"1864ab": "Azul 9",
|
||||
"0b7285": "Cian 9",
|
||||
"087f5b": "Turquesa 9",
|
||||
"2b8a3e": "Verde 9",
|
||||
"5c940d": "Lima 9",
|
||||
"e67700": "Amarillo 9",
|
||||
"d9480f": "Naranja 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "¡Elige una herramienta y empieza a dibujar!",
|
||||
"helpHint": "Atajos y ayuda"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
"veryLarge": "Oso handia",
|
||||
"solid": "Solidoa",
|
||||
"hachure": "Itzalduna",
|
||||
"zigzag": "",
|
||||
"zigzag": "Sigi-saga",
|
||||
"crossHatch": "Marraduna",
|
||||
"thin": "Mehea",
|
||||
"bold": "Lodia",
|
||||
|
@ -208,10 +208,10 @@
|
|||
"collabSaveFailed": "Ezin izan da backend datu-basean gorde. Arazoak jarraitzen badu, zure fitxategia lokalean gorde beharko zenuke zure lana ez duzula galtzen ziurtatzeko.",
|
||||
"collabSaveFailed_sizeExceeded": "Ezin izan da backend datu-basean gorde, ohiala handiegia dela dirudi. Fitxategia lokalean gorde beharko zenuke zure lana galtzen ez duzula ziurtatzeko.",
|
||||
"brave_measure_text_error": {
|
||||
"line1": "",
|
||||
"line2": "",
|
||||
"line3": "",
|
||||
"line4": ""
|
||||
"line1": "Brave arakatzailea erabiltzen ari zarela dirudi <bold>Blokeatu hatz-markak erasokorki</bold> ezarpena gaituta.",
|
||||
"line2": "Honek zure marrazkietako <bold>Testu-elementuak</bold> hautsi ditzake.",
|
||||
"line3": "Ezarpen hau desgaitzea gomendatzen dugu. <link>urrats hauek</link> jarrai ditzakezu hori nola egin jakiteko.",
|
||||
"line4": "Ezarpen hau desgaituz gero, testu-elementuen bistaratzea konpontzen ez bada, ireki <issueLink>arazo</issueLink> gure GitHub-en edo idatzi iezaguzu <discordLink>Discord</discordLink> helbidera"
|
||||
}
|
||||
},
|
||||
"toolBar": {
|
||||
|
@ -306,8 +306,8 @@
|
|||
"doubleClick": "klik bikoitza",
|
||||
"drag": "arrastatu",
|
||||
"editor": "Editorea",
|
||||
"editLineArrowPoints": "",
|
||||
"editText": "",
|
||||
"editLineArrowPoints": "Editatu lerroak/gezi-puntuak",
|
||||
"editText": "Editatu testua / gehitu etiketa",
|
||||
"github": "Arazorik izan al duzu? Eman horren berri",
|
||||
"howto": "Jarraitu gure gidak",
|
||||
"or": "edo",
|
||||
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Erabili {{shortcut}} elementu bakar gisa itsasteko,\nedo itsatsi lehendik dagoen testu-editore batean"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Zuria",
|
||||
"f8f9fa": "Grisa 0",
|
||||
"f1f3f5": "Grisa 1",
|
||||
"fff5f5": "Gorria 0",
|
||||
"fff0f6": "Arrosa 0",
|
||||
"f8f0fc": "Mahats kolorea 0",
|
||||
"f3f0ff": "Bioleta 0",
|
||||
"edf2ff": "Indigoa 0",
|
||||
"e7f5ff": "Urdina 0",
|
||||
"e3fafc": "Ziana 0",
|
||||
"e6fcf5": "Berde urdinxka 0",
|
||||
"ebfbee": "Berdea 0",
|
||||
"f4fce3": "Lima 0",
|
||||
"fff9db": "Horia 0",
|
||||
"fff4e6": "Laranja 0",
|
||||
"transparent": "Gardena",
|
||||
"ced4da": "Grisa 4",
|
||||
"868e96": "Grisa 6",
|
||||
"fa5252": "Gorria 6",
|
||||
"e64980": "Arrosa 6",
|
||||
"be4bdb": "Mahats kolorea 6",
|
||||
"7950f2": "Bioleta 6",
|
||||
"4c6ef5": "Indigoa 6",
|
||||
"228be6": "Urdina 6",
|
||||
"15aabf": "Ziana 6",
|
||||
"12b886": "Berde urdinxka 6",
|
||||
"40c057": "Berdea 6",
|
||||
"82c91e": "Lima 6",
|
||||
"fab005": "Horia 6",
|
||||
"fd7e14": "Laranja 6",
|
||||
"000000": "Beltza",
|
||||
"343a40": "Grisa 8",
|
||||
"495057": "Grisa 7",
|
||||
"c92a2a": "Gorria 9",
|
||||
"a61e4d": "Arrosa 9",
|
||||
"862e9c": "Mahats kolorea 9",
|
||||
"5f3dc4": "Bioleta 9",
|
||||
"364fc7": "Indigoa 9",
|
||||
"1864ab": "Urdina 9",
|
||||
"0b7285": "Ziana 9",
|
||||
"087f5b": "Berde urdinxka 9",
|
||||
"2b8a3e": "Berdea 9",
|
||||
"5c940d": "Lima 9",
|
||||
"e67700": "Horia 9",
|
||||
"d9480f": "Laranja 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Aukeratu tresna bat eta hasi marrazten!",
|
||||
"helpHint": "Lasterbideak eta laguntza"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,16 +264,11 @@
|
|||
"canvasTooBigTip": "نکته: سعی کنید دورترین عناصر را کمی به همدیگر نزدیک کنید."
|
||||
},
|
||||
"errorSplash": {
|
||||
"headingMain_pre": "با مشکلی مواجه شدیم. این را امتحان کنید ",
|
||||
"headingMain_button": "در حال بازنشانی صفحه.",
|
||||
"headingMain": "",
|
||||
"clearCanvasMessage": "اگر بازنشانی صفحه مشکل را حل نکرد این را امتحان کنید ",
|
||||
"clearCanvasMessage_button": "در حال تمیز کردن بوم",
|
||||
"clearCanvasCaveat": " این باعث میشود کارهای شما ذخیره نشود ",
|
||||
"trackedToSentry_pre": "خطا در شناسه ",
|
||||
"trackedToSentry_post": " در سیستم ما رهگیری شد.",
|
||||
"openIssueMessage_pre": "ما خیلی محتاط هستیم که اطلاعات شما را در خطا قرار ندهیم. با این حال اگر اطلاعات شما خصوصی نیست لطفا پیگیری کنید ",
|
||||
"openIssueMessage_button": "پیگیری اشکالات.",
|
||||
"openIssueMessage_post": " لطفا اطلاعات زیر را با کپی کردن در صفحه مشکلات GitHub بگذارید.",
|
||||
"trackedToSentry": "",
|
||||
"openIssueMessage": "",
|
||||
"sceneContent": "محتوای صحنه:"
|
||||
},
|
||||
"roomDialog": {
|
||||
|
@ -353,29 +348,16 @@
|
|||
"required": "لازم",
|
||||
"website": "وارد کردن آدرس درست"
|
||||
},
|
||||
"noteDescription": {
|
||||
"pre": "کتابخانه خود را ارسال کنید تا در آن گنجانده شود ",
|
||||
"link": "مخزن کتابخانه عمومی",
|
||||
"post": "تا افراد دیگر در نقاشی های خود از آن استفاده کنند."
|
||||
},
|
||||
"noteGuidelines": {
|
||||
"pre": "کتابخانه باید ابتدا به صورت دستی تایید شود. لطفاً بخوانید ",
|
||||
"link": "دستورالعملها",
|
||||
"post": " قبل از ارسال برای برقراری ارتباط و ایجاد تغییرات در صورت درخواست، به یک حساب GitHub نیاز دارید، اما به شدت الزامی نیست."
|
||||
},
|
||||
"noteLicense": {
|
||||
"pre": "با ارسال، موافقت می کنید که کتابخانه تحت عنوان منتشر شود ",
|
||||
"link": "پروانهٔ MIT ",
|
||||
"post": "که به طور خلاصه به این معنی است که هر کسی می تواند بدون محدودیت از آنها استفاده کند."
|
||||
},
|
||||
"noteDescription": "",
|
||||
"noteGuidelines": "",
|
||||
"noteLicense": "",
|
||||
"noteItems": "هر مورد کتابخانه باید نام خاص خود را داشته باشد تا قابل فیلتر باشد. اقلام کتابخانه زیر شامل خواهد شد:",
|
||||
"atleastOneLibItem": "لطفاً حداقل یک مورد از کتابخانه را برای شروع انتخاب کنید",
|
||||
"republishWarning": "توجه: برخی از موارد انتخاب شده به عنوان قبلاً منتشر شده/ارسال شده علامت گذاری شده اند. شما فقط باید هنگام بهروزرسانی یک کتابخانه موجود یا ارسال، موارد را دوباره ارسال کنید."
|
||||
},
|
||||
"publishSuccessDialog": {
|
||||
"title": "کتابخانه ارسال شد",
|
||||
"content": "تشکر از شما {{authorName}}. کتابخانه شما برای بررسی ارسال شده است. می توانید وضعیت را پیگیری کنید",
|
||||
"link": "اینجا"
|
||||
"content": "تشکر از شما {{authorName}}. کتابخانه شما برای بررسی ارسال شده است. می توانید وضعیت را پیگیری کنید"
|
||||
},
|
||||
"confirmDialog": {
|
||||
"resetLibrary": "تنظیم مجدد کتابخانه",
|
||||
|
@ -412,51 +394,21 @@
|
|||
"pasteAsSingleElement": "از {{shortcut}} برای چسباندن به عنوان یک عنصر استفاده کنید،\nیا در یک ویرایشگر متن موجود جایگذاری کنید"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "سفید",
|
||||
"f8f9fa": "خاکستری 0",
|
||||
"f1f3f5": "خاکستری 1",
|
||||
"fff5f5": "قرمز 0",
|
||||
"fff0f6": "صورتی 0",
|
||||
"f8f0fc": "انگوری 0",
|
||||
"f3f0ff": "بنفش 0",
|
||||
"edf2ff": "نیلی 0",
|
||||
"e7f5ff": "آبی 0",
|
||||
"e3fafc": "آبی نفتی 0",
|
||||
"e6fcf5": "آبی فیروزه ای 0",
|
||||
"ebfbee": "سبز 0",
|
||||
"f4fce3": "لیمویی 0",
|
||||
"fff9db": "زرد 0",
|
||||
"fff4e6": "نارنجی 0",
|
||||
"transparent": "شفاف",
|
||||
"ced4da": "خاکستری 4",
|
||||
"868e96": "خاکستری 6",
|
||||
"fa5252": "قرمز 6",
|
||||
"e64980": "صورتی 6",
|
||||
"be4bdb": "انگوری 6",
|
||||
"7950f2": "بنفش 6",
|
||||
"4c6ef5": "نیلی 6",
|
||||
"228be6": "آبی 6",
|
||||
"15aabf": "آبی نفتی 6",
|
||||
"12b886": "آبی فیروزه ای 6",
|
||||
"40c057": "سبز 6",
|
||||
"82c91e": "لیمویی 6",
|
||||
"fab005": "زرد 6",
|
||||
"fd7e14": "نارنجی 6",
|
||||
"000000": "سیاه",
|
||||
"343a40": "خاکستری 8",
|
||||
"495057": "خاکستری 7",
|
||||
"c92a2a": "قرمز 9",
|
||||
"a61e4d": "صورتی 9",
|
||||
"862e9c": "انگوری 9",
|
||||
"5f3dc4": "بنفش 9",
|
||||
"364fc7": "نیلی 9",
|
||||
"1864ab": "آبی 9",
|
||||
"0b7285": "آبی نفتی 9",
|
||||
"087f5b": "آبی فیروزه ای 9",
|
||||
"2b8a3e": "سبز 9",
|
||||
"5c940d": "لیمویی 9",
|
||||
"e67700": "زرد 9",
|
||||
"d9480f": "نارنجی 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -470,5 +422,12 @@
|
|||
"toolbarHint": "ابزاری را انتخاب کنید و نقاشی را شروع کنید!",
|
||||
"helpHint": "میانبرها و راهنما"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Käytä {{shortcut}} liittääksesi yhtenä elementtinä,\ntai liittääksesi olemassa olevaan tekstieditoriin"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Valkoinen",
|
||||
"f8f9fa": "Harmaa 0",
|
||||
"f1f3f5": "Harmaa 1",
|
||||
"fff5f5": "Punainen 0",
|
||||
"fff0f6": "Pinkki 0",
|
||||
"f8f0fc": "Rypäle 0",
|
||||
"f3f0ff": "Violetti 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Sininen 0",
|
||||
"e3fafc": "Syaani 0",
|
||||
"e6fcf5": "Sinivihreä 0",
|
||||
"ebfbee": "Vihreä 0",
|
||||
"f4fce3": "Limenvihreä 0",
|
||||
"fff9db": "Keltainen 0",
|
||||
"fff4e6": "Oranssi 0",
|
||||
"transparent": "Läpinäkyvä",
|
||||
"ced4da": "Harmaa 4",
|
||||
"868e96": "Harmaa 6",
|
||||
"fa5252": "Punainen 6",
|
||||
"e64980": "Pinkki 6",
|
||||
"be4bdb": "Rypäle 6",
|
||||
"7950f2": "Violetti 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Sininen 6",
|
||||
"15aabf": "Syaani 6",
|
||||
"12b886": "Sinivihreä 6",
|
||||
"40c057": "Vihreä 6",
|
||||
"82c91e": "Limenvihreä 6",
|
||||
"fab005": "Keltainen 6",
|
||||
"fd7e14": "Oranssi 6",
|
||||
"000000": "Musta",
|
||||
"343a40": "Harmaa 8",
|
||||
"495057": "Harmaa 7",
|
||||
"c92a2a": "Punainen 9",
|
||||
"a61e4d": "Pinkki 9",
|
||||
"862e9c": "Rypäle 9",
|
||||
"5f3dc4": "Violetti 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Sininen 9",
|
||||
"0b7285": "Syaani 9",
|
||||
"087f5b": "Sinivihreä 9",
|
||||
"2b8a3e": "Vihreä 9",
|
||||
"5c940d": "Limenvihreä 9",
|
||||
"e67700": "Keltainen 9",
|
||||
"d9480f": "Oranssi 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Valitse työkalu ja aloita piirtäminen!",
|
||||
"helpHint": "Pikanäppäimet & ohje"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Utiliser {{shortcut}} pour coller comme un seul élément,\nou coller dans un éditeur de texte existant"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Blanc",
|
||||
"f8f9fa": "Gris 0",
|
||||
"f1f3f5": "Gris 1",
|
||||
"fff5f5": "Rouge 0",
|
||||
"fff0f6": "Rose 0",
|
||||
"f8f0fc": "Mauve 0",
|
||||
"f3f0ff": "Violet 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Bleu 0",
|
||||
"e3fafc": "Cyan 0",
|
||||
"e6fcf5": "Turquoise 0",
|
||||
"ebfbee": "Vert 0",
|
||||
"f4fce3": "Citron vert 0",
|
||||
"fff9db": "Jaune 0",
|
||||
"fff4e6": "Orange 0",
|
||||
"transparent": "Transparent",
|
||||
"ced4da": "Gris 4",
|
||||
"868e96": "Gris 6",
|
||||
"fa5252": "Rouge 6",
|
||||
"e64980": "Rose 6",
|
||||
"be4bdb": "Mauve 6",
|
||||
"7950f2": "Violet 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Bleu 6",
|
||||
"15aabf": "Cyan 6",
|
||||
"12b886": "Turquoise 6",
|
||||
"40c057": "Vert 6",
|
||||
"82c91e": "Citron vert 6",
|
||||
"fab005": "Jaune 6",
|
||||
"fd7e14": "Orange 6",
|
||||
"000000": "Noir",
|
||||
"343a40": "Gris 8",
|
||||
"495057": "Gris 7",
|
||||
"c92a2a": "Rouge 9",
|
||||
"a61e4d": "Rose 9",
|
||||
"862e9c": "Mauve 9",
|
||||
"5f3dc4": "Violet 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Bleu 9",
|
||||
"0b7285": "Cyan 9",
|
||||
"087f5b": "Turquoise 9",
|
||||
"2b8a3e": "Vert 9",
|
||||
"5c940d": "Citron vert 9",
|
||||
"e67700": "Jaune 9",
|
||||
"d9480f": "Orange 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Choisissez un outil et commencez à dessiner !",
|
||||
"helpHint": "Raccourcis et aide"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Usa {{shortcut}} para pegar como un único elemento\nou pega nun editor de texto existente"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Branco",
|
||||
"f8f9fa": "Gris 0",
|
||||
"f1f3f5": "Gris 1",
|
||||
"fff5f5": "Vermello 0",
|
||||
"fff0f6": "Rosa 0",
|
||||
"f8f0fc": "Uva 0",
|
||||
"f3f0ff": "Violeta 0",
|
||||
"edf2ff": "Índigo 0",
|
||||
"e7f5ff": "Azul 0",
|
||||
"e3fafc": "Ciano 0",
|
||||
"e6fcf5": "Turquesa 0",
|
||||
"ebfbee": "Verde 0",
|
||||
"f4fce3": "Lima 0",
|
||||
"fff9db": "Amarelo 0",
|
||||
"fff4e6": "Laranxa 0",
|
||||
"transparent": "Transparente",
|
||||
"ced4da": "Gris 4",
|
||||
"868e96": "Gris 6",
|
||||
"fa5252": "Vermello 6",
|
||||
"e64980": "Rosa 6",
|
||||
"be4bdb": "Uva 6",
|
||||
"7950f2": "Violeta 6",
|
||||
"4c6ef5": "Índigo 6",
|
||||
"228be6": "Azul 6",
|
||||
"15aabf": "Ciano 6",
|
||||
"12b886": "Turquesa 6",
|
||||
"40c057": "Verde 6",
|
||||
"82c91e": "Lima 6",
|
||||
"fab005": "Amarelo 6",
|
||||
"fd7e14": "Laranxa 6",
|
||||
"000000": "Negro",
|
||||
"343a40": "Gris 8",
|
||||
"495057": "Gris 7",
|
||||
"c92a2a": "Vermello 9",
|
||||
"a61e4d": "Rosa 9",
|
||||
"862e9c": "Uva 9",
|
||||
"5f3dc4": "Violeta 9",
|
||||
"364fc7": "Índigo 9",
|
||||
"1864ab": "Azul 9",
|
||||
"0b7285": "Ciano 9",
|
||||
"087f5b": "Turquesa 9",
|
||||
"2b8a3e": "Verde 9",
|
||||
"5c940d": "Lima 9",
|
||||
"e67700": "Amarelo 9",
|
||||
"d9480f": "Laranxa 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Escolle unha ferramenta & Comeza a debuxar!",
|
||||
"helpHint": "Atallos & axuda"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,16 +264,11 @@
|
|||
"canvasTooBigTip": "טיפ: נסה להזיז את הרכיבים הרחוקים ביותר מעט קרוב יותר האחד לשני."
|
||||
},
|
||||
"errorSplash": {
|
||||
"headingMain_pre": "אירעה שגיאה. נסה ",
|
||||
"headingMain_button": "טוען את העמוד מחדש.",
|
||||
"headingMain": "",
|
||||
"clearCanvasMessage": "אם טעינה מחדש לא עובדת, נסה ",
|
||||
"clearCanvasMessage_button": "מנקה את הקנבאס.",
|
||||
"clearCanvasCaveat": " זה יגרום לאובדן העבודה ",
|
||||
"trackedToSentry_pre": "השגיאה עם מזהה ",
|
||||
"trackedToSentry_post": " נמצאה במערכת שלנו.",
|
||||
"openIssueMessage_pre": "נזהרנו מאוד שלא לכלול מידע מהקנבאס שלך בשגיאה. אם המידע בקנבאס אינו אישי, שקול לבצע מעקב אחר הטיפול שלנו ",
|
||||
"openIssueMessage_button": "מעקב באגים.",
|
||||
"openIssueMessage_post": " בבקשה כלול את המידע מטה באמצעות העתקתה שלו, והדבקה שלו ב- GitHub Issue.",
|
||||
"trackedToSentry": "",
|
||||
"openIssueMessage": "",
|
||||
"sceneContent": "תוכן הקנבאס:"
|
||||
},
|
||||
"roomDialog": {
|
||||
|
@ -353,29 +348,16 @@
|
|||
"required": "נדרש",
|
||||
"website": "הזינו כתובת URL תקינה"
|
||||
},
|
||||
"noteDescription": {
|
||||
"pre": "הגש את הספריה שלך להכללתה ב ",
|
||||
"link": "מאגר הספריה הציבורית",
|
||||
"post": "לשימושם של אנשים אחרים בציורים שלהם."
|
||||
},
|
||||
"noteGuidelines": {
|
||||
"pre": "הספריה צריכה לקבל אישור ידני קודם לכן. אנא קרא את ",
|
||||
"link": "הנחיות",
|
||||
"post": " לפני השליחה. אתה תצטרך לחשבון GitHub כדי לתקשר ולבצע שינויים אם תתבקש, אבל זה לא דרישה הכרחית."
|
||||
},
|
||||
"noteLicense": {
|
||||
"pre": "על ידי שליחה, אתה מסכים שהסיפריה תפורסם תחת ה- ",
|
||||
"link": "רישיון MIT, ",
|
||||
"post": "שאומר בקצרה, שכל אחד יכול לעשות בהם שימוש ללא מגבלות."
|
||||
},
|
||||
"noteDescription": "",
|
||||
"noteGuidelines": "",
|
||||
"noteLicense": "",
|
||||
"noteItems": "לכל פריט בסיפריה חייב להיות שם כדי שאפשר יהיה לסנן. הפריטי סיפריה הבאים יהיו כלולים:",
|
||||
"atleastOneLibItem": "אנא בחר לפחות פריט אחד מספריה כדי להתחיל",
|
||||
"republishWarning": "הערה: חלק מהפריטים שבחרת מסומנים ככאלו שכבר פורסמו/נשלחו. אתה צריך לשלוח פריטים מחדש כאשר אתה מעדכן ספריה או הגשה קיימים."
|
||||
},
|
||||
"publishSuccessDialog": {
|
||||
"title": "הספריה הוגשה",
|
||||
"content": "תודה {{authorName}}. הספריה שלך נשלחה לבחינה. תוכל לעקוב אחרי סטטוס הפרסום",
|
||||
"link": "כאן"
|
||||
"content": "תודה {{authorName}}. הספריה שלך נשלחה לבחינה. תוכל לעקוב אחרי סטטוס הפרסום"
|
||||
},
|
||||
"confirmDialog": {
|
||||
"resetLibrary": "איפוס ספריה",
|
||||
|
@ -412,51 +394,21 @@
|
|||
"pasteAsSingleElement": "השתמש ב- {{shortcut}} כדי להדביק כפריט יחיד,\nאו הדבק לתוך עורך טקסט קיים"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "לבן",
|
||||
"f8f9fa": "אפור 0",
|
||||
"f1f3f5": "אפור 1",
|
||||
"fff5f5": "אדום 0",
|
||||
"fff0f6": "ורוד 0",
|
||||
"f8f0fc": "ענבים 0",
|
||||
"f3f0ff": "סגול 0",
|
||||
"edf2ff": "כחול כהה 0",
|
||||
"e7f5ff": "כחול 0",
|
||||
"e3fafc": "טורקיז 0",
|
||||
"e6fcf5": "ירקרק 0",
|
||||
"ebfbee": "ירוק 0",
|
||||
"f4fce3": "ליים 0",
|
||||
"fff9db": "צהוב",
|
||||
"fff4e6": "כתום 0",
|
||||
"transparent": "שקוף",
|
||||
"ced4da": "אפור 4",
|
||||
"868e96": "אפור 6",
|
||||
"fa5252": "אדום 6",
|
||||
"e64980": "ורוד 6",
|
||||
"be4bdb": "ענבים 6",
|
||||
"7950f2": "סגול 6",
|
||||
"4c6ef5": "כחול כהה 6",
|
||||
"228be6": "כחול 6",
|
||||
"15aabf": "טורקיז 6",
|
||||
"12b886": "ירקרק 6",
|
||||
"40c057": "ירוק 6",
|
||||
"82c91e": "ליים 6",
|
||||
"fab005": "צהוב 6",
|
||||
"fd7e14": "כתום 6",
|
||||
"000000": "שחור",
|
||||
"343a40": "אפור 8",
|
||||
"495057": "אפור 7",
|
||||
"c92a2a": "אדום 9",
|
||||
"a61e4d": "ורוד 9",
|
||||
"862e9c": "ענבים 9",
|
||||
"5f3dc4": "סגול 9",
|
||||
"364fc7": "כחול כהה 9",
|
||||
"1864ab": "כחול 9",
|
||||
"0b7285": "טורקיז 9",
|
||||
"087f5b": "ירוק-כחול 9",
|
||||
"2b8a3e": "ירוק 9",
|
||||
"5c940d": "ליים 9",
|
||||
"e67700": "צהוב 9",
|
||||
"d9480f": "כתום 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -470,5 +422,12 @@
|
|||
"toolbarHint": "בחר כלי & והתחל לצייר!",
|
||||
"helpHint": "קיצורים & עזרה"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -350,14 +350,14 @@
|
|||
},
|
||||
"noteDescription": "संग्रह सम्मिलित करने हेतु प्रस्तुत करें <link>सार्वजनिक संग्रहालय</link>अन्य वक्तियों को उनके चित्रकारी में उपयोग के लिये",
|
||||
"noteGuidelines": "संग्रह को पहले स्वीकृति आवश्यक कृपया यह पढ़ें <link>दिशा-निर्देश</link>",
|
||||
"noteLicense": "",
|
||||
"noteLicense": "जमा करके, आप सहमत हैं कि संग्रहण को <link>MIT लाइसेंस</link> के तहत प्रकाशित किया जाएगा, जिसका संक्षिप्त अर्थ है कि कोई भी बिना किसी प्रतिबंध के उनका उपयोग कर सकता है।",
|
||||
"noteItems": "",
|
||||
"atleastOneLibItem": "",
|
||||
"republishWarning": "टिप्पणी: कुछ चुने हुवे आइटम पहले ही प्रकाशित/प्रस्तुत किए जा चुके हैं। किसी प्रकाशित संग्रह को अद्यतन करते समय या पहले से प्रस्तुत आइटम को पुन्हा प्रस्तुत करते समय, आप बस उसे केवल अद्यतन करें ।"
|
||||
},
|
||||
"publishSuccessDialog": {
|
||||
"title": "",
|
||||
"content": ""
|
||||
"content": "{{authorName}} धन्यवाद. आपका संग्रहण समीक्षा के लिए दर्ज हो चुका है. समीक्षा स्थिति <link>यहाँ</link>जान सकते हैं."
|
||||
},
|
||||
"confirmDialog": {
|
||||
"resetLibrary": "",
|
||||
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "एक अवयव के रूप में चिपकाने के लिए {{shortcut}} का उपयोग करें,\nया किसी मौजूदा पाठ संपादक में चिपकायें"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "सफेद",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "अंगूरी 0",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "नील 0",
|
||||
"e7f5ff": "नीला 0",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "",
|
||||
"fff4e6": "",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "",
|
||||
"82c91e": "",
|
||||
"fab005": "",
|
||||
"fd7e14": "",
|
||||
"000000": "",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "",
|
||||
"0b7285": "आसमानी",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "हरा",
|
||||
"5c940d": "",
|
||||
"e67700": "पीला",
|
||||
"d9480f": "नारंगी"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "एक औजार चुने और चित्रकारी प्रारंभ करे!",
|
||||
"helpHint": "शॉर्ट्कट और सहाय्य"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Fehér",
|
||||
"f8f9fa": "Szürke 0",
|
||||
"f1f3f5": "Szürke 1",
|
||||
"fff5f5": "Piros 0",
|
||||
"fff0f6": "Pink 0",
|
||||
"f8f0fc": "Szőlő 0",
|
||||
"f3f0ff": "Ibolya 0",
|
||||
"edf2ff": "Indigó 0",
|
||||
"e7f5ff": "Kék 0",
|
||||
"e3fafc": "Cián 0",
|
||||
"e6fcf5": "Kékes-zöld 0",
|
||||
"ebfbee": "Zöld 0",
|
||||
"f4fce3": "Lime 0",
|
||||
"fff9db": "Sárga 0",
|
||||
"fff4e6": "Narancs 0",
|
||||
"transparent": "Átlátszó",
|
||||
"ced4da": "Szürke 4",
|
||||
"868e96": "Szürke 6",
|
||||
"fa5252": "Piros 6",
|
||||
"e64980": "Pink 6",
|
||||
"be4bdb": "Szőlő 6",
|
||||
"7950f2": "Ibolya 6",
|
||||
"4c6ef5": "Indigó 6",
|
||||
"228be6": "Kék 6",
|
||||
"15aabf": "Cián 6",
|
||||
"12b886": "Kékes-zöld 6",
|
||||
"40c057": "Zöld 6",
|
||||
"82c91e": "Lime 6",
|
||||
"fab005": "Sárga 6",
|
||||
"fd7e14": "Narancs 6",
|
||||
"000000": "Fekete",
|
||||
"343a40": "Szürke 8",
|
||||
"495057": "Szürke 7",
|
||||
"c92a2a": "Piros 9",
|
||||
"a61e4d": "Pink 9",
|
||||
"862e9c": "Szőlő 9",
|
||||
"5f3dc4": "Ibolya 9",
|
||||
"364fc7": "Indigó 9",
|
||||
"1864ab": "Kék 9",
|
||||
"0b7285": "Cián 9",
|
||||
"087f5b": "Kékes-zöld 9",
|
||||
"2b8a3e": "Zöld 9",
|
||||
"5c940d": "Lime 9",
|
||||
"e67700": "Sárga 9",
|
||||
"d9480f": "Narancs 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Gunakan {{shortcut}} untuk menempelkan sebagai satu elemen,\natau tempelkan ke teks editor yang ada"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Putih",
|
||||
"f8f9fa": "Abu-abu 0",
|
||||
"f1f3f5": "Abu-abu 1",
|
||||
"fff5f5": "Merah 0",
|
||||
"fff0f6": "Merah muda 0",
|
||||
"f8f0fc": "Ungu 0",
|
||||
"f3f0ff": "Violet 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Biru 0",
|
||||
"e3fafc": "Cyan 0",
|
||||
"e6fcf5": "Teal 0",
|
||||
"ebfbee": "Hijau 0",
|
||||
"f4fce3": "Lime 0",
|
||||
"fff9db": "Kuning 0",
|
||||
"fff4e6": "Jingga 0",
|
||||
"transparent": "Transparan",
|
||||
"ced4da": "Abu-abu 4",
|
||||
"868e96": "Abu-abu 6",
|
||||
"fa5252": "Merah 6",
|
||||
"e64980": "Merah muda 6",
|
||||
"be4bdb": "Ungu 6",
|
||||
"7950f2": "Violet 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Biru 6",
|
||||
"15aabf": "Cyan 6",
|
||||
"12b886": "Teal 6",
|
||||
"40c057": "Hijau 6",
|
||||
"82c91e": "Lime 6",
|
||||
"fab005": "Kuning 6",
|
||||
"fd7e14": "Jingga 6",
|
||||
"000000": "Hitam",
|
||||
"343a40": "Abu-abu 8",
|
||||
"495057": "Abu-abu 7",
|
||||
"c92a2a": "Merah 9",
|
||||
"a61e4d": "Merah muda 9",
|
||||
"862e9c": "Ungu 9",
|
||||
"5f3dc4": "Violet 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Biru 9",
|
||||
"0b7285": "Cyan 9",
|
||||
"087f5b": "Teal 9",
|
||||
"2b8a3e": "Hijau 9",
|
||||
"5c940d": "Lime 9",
|
||||
"e67700": "Kuning 9",
|
||||
"d9480f": "Jingga 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Pilih alat & mulai menggambar!",
|
||||
"helpHint": "Pintasan & bantuan"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,10 +208,10 @@
|
|||
"collabSaveFailed": "Impossibile salvare nel database di backend. Se i problemi persistono, dovresti salvare il tuo file localmente per assicurarti di non perdere il tuo lavoro.",
|
||||
"collabSaveFailed_sizeExceeded": "Impossibile salvare nel database di backend, la tela sembra essere troppo grande. Dovresti salvare il file localmente per assicurarti di non perdere il tuo lavoro.",
|
||||
"brave_measure_text_error": {
|
||||
"line1": "",
|
||||
"line2": "",
|
||||
"line3": "",
|
||||
"line4": ""
|
||||
"line1": "Sembra che tu stia utilizzando il browser Brave con l'impostazione <bold>Blocco aggressivo delle impronte digitali</bold> abilitata.",
|
||||
"line2": "Ciò potrebbe causare la rottura degli <bold>Elementi di testo</bold> nei tuoi disegni.",
|
||||
"line3": "Consigliamo vivamente di disabilitare questa impostazione. Puoi seguire <link>questi passaggi</link> su come farlo.",
|
||||
"line4": "Se la disattivazione di questa impostazione non risolve la visualizzazione degli elementi di testo, apri un <issueLink>problema</issueLink> sul nostro GitHub o scrivici su <discordLink>Discord</discordLink>"
|
||||
}
|
||||
},
|
||||
"toolBar": {
|
||||
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Usa {{shortcut}} per incollare come un singolo elemento,\no incollare in un editor di testo esistente"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Bianco",
|
||||
"f8f9fa": "Grigio 0",
|
||||
"f1f3f5": "Grigio 1",
|
||||
"fff5f5": "Rosso 0",
|
||||
"fff0f6": "Rosa 0",
|
||||
"f8f0fc": "Uva 0",
|
||||
"f3f0ff": "Viola 0",
|
||||
"edf2ff": "Indaco 0",
|
||||
"e7f5ff": "Blu 0",
|
||||
"e3fafc": "Ciano 0",
|
||||
"e6fcf5": "Verde acqua 0",
|
||||
"ebfbee": "Verde 0",
|
||||
"f4fce3": "Lime 0",
|
||||
"fff9db": "Giallo 0",
|
||||
"fff4e6": "Arancio 0",
|
||||
"transparent": "Trasparente",
|
||||
"ced4da": "Grigio 4",
|
||||
"868e96": "Grigio 6",
|
||||
"fa5252": "Rosso 6",
|
||||
"e64980": "Rosa 6",
|
||||
"be4bdb": "Uva 6",
|
||||
"7950f2": "Viola 6",
|
||||
"4c6ef5": "Indaco 6",
|
||||
"228be6": "Blu 6",
|
||||
"15aabf": "Ciano 6",
|
||||
"12b886": "Verde acqua 6",
|
||||
"40c057": "Verde 6",
|
||||
"82c91e": "Lime 6",
|
||||
"fab005": "Giallo 6",
|
||||
"fd7e14": "Arancio 6",
|
||||
"000000": "Nero",
|
||||
"343a40": "Grigio 8",
|
||||
"495057": "Grigio 7",
|
||||
"c92a2a": "Rosso 9",
|
||||
"a61e4d": "Rosa 9",
|
||||
"862e9c": "Uva 9",
|
||||
"5f3dc4": "Viola 9",
|
||||
"364fc7": "Indaco 9",
|
||||
"1864ab": "Blu 9",
|
||||
"0b7285": "Ciano 9",
|
||||
"087f5b": "Verde acqua 9",
|
||||
"2b8a3e": "Verde 9",
|
||||
"5c940d": "Lime 9",
|
||||
"e67700": "Giallo 9",
|
||||
"d9480f": "Arancio 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Scegli uno strumento & Inizia a disegnare!",
|
||||
"helpHint": "Scorciatoie & aiuto"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "{{shortcut}} を使用して単一の要素として貼り付けるか、\n既存のテキストエディタに貼り付け"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "ホワイト",
|
||||
"f8f9fa": "グレー 0",
|
||||
"f1f3f5": "グレー 1",
|
||||
"fff5f5": "レッド 0",
|
||||
"fff0f6": "ピンク 0",
|
||||
"f8f0fc": "グレープ 0",
|
||||
"f3f0ff": "バイオレット 0",
|
||||
"edf2ff": "インディゴ 0",
|
||||
"e7f5ff": "ブルー 0",
|
||||
"e3fafc": "シアン 0",
|
||||
"e6fcf5": "ティール 0",
|
||||
"ebfbee": "グリーン 0",
|
||||
"f4fce3": "ライム 0",
|
||||
"fff9db": "イエロー 0",
|
||||
"fff4e6": "オレンジ 0",
|
||||
"transparent": "透明",
|
||||
"ced4da": "グレー 4",
|
||||
"868e96": "グレー 6",
|
||||
"fa5252": "レッド 6",
|
||||
"e64980": "ピンク 6",
|
||||
"be4bdb": "グレープ 6",
|
||||
"7950f2": "バイオレット 6",
|
||||
"4c6ef5": "インディゴ 6",
|
||||
"228be6": "ブルー 6",
|
||||
"15aabf": "シアン 6",
|
||||
"12b886": "ティール 6",
|
||||
"40c057": "グリーン 6",
|
||||
"82c91e": "ライム 6",
|
||||
"fab005": "イエロー 6",
|
||||
"fd7e14": "オレンジ 6",
|
||||
"000000": "ブラック",
|
||||
"343a40": "グレー 8",
|
||||
"495057": "グレー 7",
|
||||
"c92a2a": "レッド 9",
|
||||
"a61e4d": "ピンク 9",
|
||||
"862e9c": "グレープ 9",
|
||||
"5f3dc4": "バイオレット 9",
|
||||
"364fc7": "インディゴ 9",
|
||||
"1864ab": "ブルー 9",
|
||||
"0b7285": "シアン 9",
|
||||
"087f5b": "ティール 9",
|
||||
"2b8a3e": "グリーン 9",
|
||||
"5c940d": "ライム 9",
|
||||
"e67700": "イエロー 9",
|
||||
"d9480f": "オレンジ 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "ツールを選んで描き始めよう!",
|
||||
"helpHint": "ショートカットとヘルプ"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,16 +264,11 @@
|
|||
"canvasTooBigTip": ""
|
||||
},
|
||||
"errorSplash": {
|
||||
"headingMain_pre": "",
|
||||
"headingMain_button": "",
|
||||
"headingMain": "",
|
||||
"clearCanvasMessage": "",
|
||||
"clearCanvasMessage_button": "",
|
||||
"clearCanvasCaveat": "",
|
||||
"trackedToSentry_pre": "",
|
||||
"trackedToSentry_post": "",
|
||||
"openIssueMessage_pre": "",
|
||||
"openIssueMessage_button": "",
|
||||
"openIssueMessage_post": "",
|
||||
"trackedToSentry": "",
|
||||
"openIssueMessage": "",
|
||||
"sceneContent": ""
|
||||
},
|
||||
"roomDialog": {
|
||||
|
@ -353,29 +348,16 @@
|
|||
"required": "",
|
||||
"website": ""
|
||||
},
|
||||
"noteDescription": {
|
||||
"pre": "",
|
||||
"link": "",
|
||||
"post": ""
|
||||
},
|
||||
"noteGuidelines": {
|
||||
"pre": "",
|
||||
"link": "",
|
||||
"post": ""
|
||||
},
|
||||
"noteLicense": {
|
||||
"pre": "",
|
||||
"link": "",
|
||||
"post": ""
|
||||
},
|
||||
"noteDescription": "",
|
||||
"noteGuidelines": "",
|
||||
"noteLicense": "",
|
||||
"noteItems": "",
|
||||
"atleastOneLibItem": "",
|
||||
"republishWarning": ""
|
||||
},
|
||||
"publishSuccessDialog": {
|
||||
"title": "",
|
||||
"content": "",
|
||||
"link": "usı jerde"
|
||||
"content": ""
|
||||
},
|
||||
"confirmDialog": {
|
||||
"resetLibrary": "",
|
||||
|
@ -390,13 +372,13 @@
|
|||
"element": "",
|
||||
"elements": "",
|
||||
"height": "",
|
||||
"scene": "",
|
||||
"scene": "Saxna",
|
||||
"selected": "Tańlandı",
|
||||
"storage": "",
|
||||
"title": "",
|
||||
"total": "",
|
||||
"version": "Versiya",
|
||||
"versionCopy": "",
|
||||
"versionCopy": "Kóshirip alıw ushın basıń",
|
||||
"versionNotAvailable": "",
|
||||
"width": ""
|
||||
},
|
||||
|
@ -406,57 +388,27 @@
|
|||
"copyToClipboard": "",
|
||||
"copyToClipboardAsPng": "",
|
||||
"fileSaved": "Fayl saqlandı.",
|
||||
"fileSavedToFilename": "",
|
||||
"fileSavedToFilename": "{filename} saqlandı",
|
||||
"canvas": "",
|
||||
"selection": "",
|
||||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Aq",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "Qızıl 0",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "Kók",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "Sarı 0",
|
||||
"fff4e6": "Qızǵılt sarı 0",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "Qızıl 6",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "Kók 6",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "Jasıl 6",
|
||||
"82c91e": "",
|
||||
"fab005": "Sarı 6",
|
||||
"fd7e14": "",
|
||||
"000000": "Qara",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "Qızıl 9",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "Kók 9",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "Jasıl 9",
|
||||
"5c940d": "",
|
||||
"e67700": "Sarı 9",
|
||||
"d9480f": "Qızǵılt sarı 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -470,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -209,8 +209,8 @@
|
|||
"collabSaveFailed_sizeExceeded": "Ulamek asekles deg uzadur n yisefka deg ugilal, taɣzut n usuneɣ tettban-d temqer aṭas. Isefk ad teskelseḍ afaylu s wudem adigan akken ad tetḥeqqeḍ ur tesruḥuyeḍ ara amahil-inek•inem.",
|
||||
"brave_measure_text_error": {
|
||||
"line1": "",
|
||||
"line2": "",
|
||||
"line3": "",
|
||||
"line2": "Ayagi yezmer ad d-iglu s truẓi n<bold>Iferdisen n uḍris</bold>deg wunuɣen-inek.",
|
||||
"line3": "Ad k-nsemter ad tsexsiḍ aɣewwar-agi. Tzemreḍ ad tḍefreḍ<link>isurifen-agi</link> ɣef wamek ara txedmeḍ.",
|
||||
"line4": ""
|
||||
}
|
||||
},
|
||||
|
@ -306,8 +306,8 @@
|
|||
"doubleClick": "ssit snat n tikkal",
|
||||
"drag": "zuɣer",
|
||||
"editor": "Amaẓrag",
|
||||
"editLineArrowPoints": "",
|
||||
"editText": "",
|
||||
"editLineArrowPoints": "Ẓreg tinqiḍin n yizirig/taneccabt",
|
||||
"editText": "Ẓreg aḍris/rnu tabzimt",
|
||||
"github": "Tufiḍ-d ugur? Azen-aɣ-d",
|
||||
"howto": "Ḍfer imniren-nneɣ",
|
||||
"or": "neɣ",
|
||||
|
@ -394,63 +394,40 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Amellal",
|
||||
"f8f9fa": "Aɣiɣdi 0",
|
||||
"f1f3f5": "Aɣiɣdi 1",
|
||||
"fff5f5": "Azeggaɣ",
|
||||
"fff0f6": "Axuxi 0",
|
||||
"f8f0fc": "Tiẓurin 0",
|
||||
"f3f0ff": "Amidadi 0",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "Anili 0",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "Azegzaw 0",
|
||||
"f4fce3": "Llim 0",
|
||||
"fff9db": "Awraɣ 0",
|
||||
"fff4e6": "Aččinawi 0",
|
||||
"transparent": "Afrawan",
|
||||
"ced4da": "Aɣiɣdi 4",
|
||||
"868e96": "Aɣiɣdi 6",
|
||||
"fa5252": "Azeggaɣ 6",
|
||||
"e64980": "Axuxi 6",
|
||||
"be4bdb": "",
|
||||
"7950f2": "Amidadi 6",
|
||||
"4c6ef5": "",
|
||||
"228be6": "Anili 6",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "Azegzaw 0",
|
||||
"82c91e": "Llim 6",
|
||||
"fab005": "Awraɣ 6",
|
||||
"fd7e14": "Aččinawi 6",
|
||||
"000000": "Aberkan",
|
||||
"343a40": "Aɣiɣdi 8",
|
||||
"495057": "Aɣiɣdi 7",
|
||||
"c92a2a": "Azeggaɣ 9",
|
||||
"a61e4d": "Axuxi 9",
|
||||
"862e9c": "Tiẓurin 9",
|
||||
"5f3dc4": "Amidadi 9",
|
||||
"364fc7": "",
|
||||
"1864ab": "Anili 9",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "Azegzaw 9",
|
||||
"5c940d": "Llim 9",
|
||||
"e67700": "Awraɣ 9",
|
||||
"d9480f": "Aččinawi 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
"center_heading": "",
|
||||
"center_heading": "Akk isefka-inek•inem ttwakelsen s wudem adigan deg yiminig-inek•inem.",
|
||||
"center_heading_plus": "Tebɣiḍ ad tedduḍ ɣer Excalidraw+ deg umḍiq?",
|
||||
"menuHint": "Asifeḍ, ismenyifen, tutlayin, ..."
|
||||
},
|
||||
"defaults": {
|
||||
"menuHint": "Asifeḍ, ismenyifen, d wayen-nniḍen...",
|
||||
"center_heading": "",
|
||||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
"toolbarHint": "Fren afecku tebduḍ asuneɣ!",
|
||||
"helpHint": "Inegzumen akked tallelt"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "",
|
||||
"fff4e6": "",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "",
|
||||
"82c91e": "",
|
||||
"fab005": "",
|
||||
"fd7e14": "",
|
||||
"000000": "",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "",
|
||||
"5c940d": "",
|
||||
"e67700": "",
|
||||
"d9480f": ""
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,16 +264,11 @@
|
|||
"canvasTooBigTip": ""
|
||||
},
|
||||
"errorSplash": {
|
||||
"headingMain_pre": "",
|
||||
"headingMain_button": "",
|
||||
"headingMain": "",
|
||||
"clearCanvasMessage": "",
|
||||
"clearCanvasMessage_button": "",
|
||||
"clearCanvasCaveat": "",
|
||||
"trackedToSentry_pre": "",
|
||||
"trackedToSentry_post": "",
|
||||
"openIssueMessage_pre": "",
|
||||
"openIssueMessage_button": "",
|
||||
"openIssueMessage_post": "",
|
||||
"trackedToSentry": "",
|
||||
"openIssueMessage": "",
|
||||
"sceneContent": ""
|
||||
},
|
||||
"roomDialog": {
|
||||
|
@ -353,29 +348,16 @@
|
|||
"required": "",
|
||||
"website": ""
|
||||
},
|
||||
"noteDescription": {
|
||||
"pre": "",
|
||||
"link": "",
|
||||
"post": ""
|
||||
},
|
||||
"noteGuidelines": {
|
||||
"pre": "",
|
||||
"link": "",
|
||||
"post": ""
|
||||
},
|
||||
"noteLicense": {
|
||||
"pre": "",
|
||||
"link": "",
|
||||
"post": ""
|
||||
},
|
||||
"noteDescription": "",
|
||||
"noteGuidelines": "",
|
||||
"noteLicense": "",
|
||||
"noteItems": "",
|
||||
"atleastOneLibItem": "",
|
||||
"republishWarning": ""
|
||||
},
|
||||
"publishSuccessDialog": {
|
||||
"title": "",
|
||||
"content": "",
|
||||
"link": ""
|
||||
"content": ""
|
||||
},
|
||||
"confirmDialog": {
|
||||
"resetLibrary": "",
|
||||
|
@ -412,63 +394,40 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "",
|
||||
"fff4e6": "",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "",
|
||||
"82c91e": "",
|
||||
"fab005": "",
|
||||
"fd7e14": "",
|
||||
"000000": "",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "",
|
||||
"5c940d": "",
|
||||
"e67700": "",
|
||||
"d9480f": ""
|
||||
"transparent": "ថ្លាមើលធ្លុះ",
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
"center_heading": "",
|
||||
"center_heading_plus": "",
|
||||
"menuHint": ""
|
||||
"center_heading": "ទិន្នន័យទាំងអស់របស់អ្នក ត្រូវបានរក្សាទុកនៅក្នុង browser របស់អ្នក ។",
|
||||
"center_heading_plus": "តើអ្នកចង់ទៅ Excalidraw+ វិញ ឬ មែន?",
|
||||
"menuHint": "នាំចេញ ចំណូលចិត្ត ភាសា ..."
|
||||
},
|
||||
"defaults": {
|
||||
"menuHint": "",
|
||||
"center_heading": "",
|
||||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
"menuHint": "ការនាំចេញ ចំណូលចិត្ត និង ច្រើនទៀត...",
|
||||
"center_heading": "ងាយស្រួល ។ ធ្វើ ។ ដ្យាក្រាម ។",
|
||||
"toolbarHint": "ជ្រើសរើសឧបករណ៍មួយ និង ចាប់ផ្តើមគូរ!",
|
||||
"helpHint": "ផ្លូវកាត់ & ជំនួយ"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "단일 요소로 붙여넣거나, 기존 텍스트 에디터에 붙여넣으려면 {{shortcut}} 을 사용하세요."
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "화이트",
|
||||
"f8f9fa": "회색 0",
|
||||
"f1f3f5": "회색 1",
|
||||
"fff5f5": "빨강색 0",
|
||||
"fff0f6": "핑크색 0",
|
||||
"f8f0fc": "그레이프 0",
|
||||
"f3f0ff": "바이올렛 0",
|
||||
"edf2ff": "남색 0",
|
||||
"e7f5ff": "파란색 0",
|
||||
"e3fafc": "청록색 0",
|
||||
"e6fcf5": "틸 0",
|
||||
"ebfbee": "녹색 0",
|
||||
"f4fce3": "라임 0",
|
||||
"fff9db": "노란색 0",
|
||||
"fff4e6": "주황색 0",
|
||||
"transparent": "투명",
|
||||
"ced4da": "회색 4",
|
||||
"868e96": "회색 6",
|
||||
"fa5252": "빨강색 6",
|
||||
"e64980": "핑크색 6",
|
||||
"be4bdb": "그레이프 6",
|
||||
"7950f2": "바이올렛 6",
|
||||
"4c6ef5": "남색 6",
|
||||
"228be6": "파란색 6",
|
||||
"15aabf": "청록색 6",
|
||||
"12b886": "틸 6",
|
||||
"40c057": "녹색 6",
|
||||
"82c91e": "라임 6",
|
||||
"fab005": "노란색 6",
|
||||
"fd7e14": "주황색 6",
|
||||
"000000": "검정색",
|
||||
"343a40": "회색 8",
|
||||
"495057": "회색 7",
|
||||
"c92a2a": "빨강색 9",
|
||||
"a61e4d": "핑크색 9",
|
||||
"862e9c": "그레이프 9",
|
||||
"5f3dc4": "바이올렛 9",
|
||||
"364fc7": "남색 9",
|
||||
"1864ab": "파란색 9",
|
||||
"0b7285": "청록색 9",
|
||||
"087f5b": "틸 9",
|
||||
"2b8a3e": "녹색 9",
|
||||
"5c940d": "라임 9",
|
||||
"e67700": "노란색 9",
|
||||
"d9480f": "주황색 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "도구를 선택하고, 그리세요!",
|
||||
"helpHint": "단축키 & 도움말"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "بۆ دانانەوە وەکو یەک توخم یان دانانەوە بۆ نێو دەسکاریکەرێکی دەق کە بوونی هەیە {{shortcut}} بەکاربهێنە"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "سپی",
|
||||
"f8f9fa": "خۆڵەمێشی 0",
|
||||
"f1f3f5": "خۆڵەمێشی 1",
|
||||
"fff5f5": "سور 0",
|
||||
"fff0f6": "پەمەی 0",
|
||||
"f8f0fc": "مێوژی 0",
|
||||
"f3f0ff": "مۆر 0",
|
||||
"edf2ff": "نیلی 0",
|
||||
"e7f5ff": "شین 0",
|
||||
"e3fafc": "شینی ئاسمانی 0",
|
||||
"e6fcf5": "سەوزباوی 0",
|
||||
"ebfbee": "سهوز 0",
|
||||
"f4fce3": "نارنجی 0",
|
||||
"fff9db": "زەرد 0",
|
||||
"fff4e6": "پرتەقاڵی 0",
|
||||
"transparent": "ڕوون",
|
||||
"ced4da": "خۆڵەمێشی 4",
|
||||
"868e96": "خۆڵەمێشی 6",
|
||||
"fa5252": "سور 6",
|
||||
"e64980": "پەمەی 6",
|
||||
"be4bdb": "مێوژی 6",
|
||||
"7950f2": "مۆر 6",
|
||||
"4c6ef5": "نیلی 6",
|
||||
"228be6": "شین 6",
|
||||
"15aabf": "شینی ئاسمانی 6",
|
||||
"12b886": "سەوزباوی 6",
|
||||
"40c057": "سهوز 6",
|
||||
"82c91e": "نارنجی 6",
|
||||
"fab005": "زەرد 6",
|
||||
"fd7e14": "پرتەقاڵی 6",
|
||||
"000000": "ڕەش",
|
||||
"343a40": "خۆڵەمێشی 8",
|
||||
"495057": "خۆڵەمێشی 7",
|
||||
"c92a2a": "سور 9",
|
||||
"a61e4d": "پەمەی 9",
|
||||
"862e9c": "مێوژی 9",
|
||||
"5f3dc4": "مۆر 9",
|
||||
"364fc7": "نیلی 9",
|
||||
"1864ab": "شین 9",
|
||||
"0b7285": "شینی ئاسمانی 9",
|
||||
"087f5b": "سەوزباوی 9",
|
||||
"2b8a3e": "سهوز 9",
|
||||
"5c940d": "نارنجی 9",
|
||||
"e67700": "زەرد 9",
|
||||
"d9480f": "پرتەقاڵی 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "ئامرازێک هەڵبگرە و دەستبکە بە کێشان!",
|
||||
"helpHint": "قەدبڕەکان و یارمەتی"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Balta",
|
||||
"f8f9fa": "Pilka 0",
|
||||
"f1f3f5": "Pilka 1",
|
||||
"fff5f5": "Raudona 0",
|
||||
"fff0f6": "Rožinė 0",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "Violetinė 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Mėlyna 0",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "Žalia 0",
|
||||
"f4fce3": "",
|
||||
"fff9db": "Geltona 0",
|
||||
"fff4e6": "Oranžinė 0",
|
||||
"transparent": "Permatoma",
|
||||
"ced4da": "Pilka 4",
|
||||
"868e96": "Pilka 6",
|
||||
"fa5252": "Raudona 6",
|
||||
"e64980": "Rožinė 6",
|
||||
"be4bdb": "",
|
||||
"7950f2": "Violetinė 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Mėlyna 6",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "Žalia 6",
|
||||
"82c91e": "",
|
||||
"fab005": "Geltona 6",
|
||||
"fd7e14": "Oranžinė 6",
|
||||
"000000": "Juoda",
|
||||
"343a40": "Pilna 8",
|
||||
"495057": "Pilka 7",
|
||||
"c92a2a": "Raudona 9",
|
||||
"a61e4d": "Rožinė 9",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "Violetinė 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Mėlyna 9",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "Žalia 9",
|
||||
"5c940d": "",
|
||||
"e67700": "Geltona 9",
|
||||
"d9480f": "Oranžinė 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Izmantojiet {{shortcut}}, lai ielīmētu kā jaunu elementu, vai ielīmētu esošā teksta lauciņā"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Balts",
|
||||
"f8f9fa": "Pelēks 0",
|
||||
"f1f3f5": "Pelēks 1",
|
||||
"fff5f5": "Sarkans 0",
|
||||
"fff0f6": "Rozā 0",
|
||||
"f8f0fc": "Vīnogu 0",
|
||||
"f3f0ff": "Violets 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Zils 0",
|
||||
"e3fafc": "Ciāns 0",
|
||||
"e6fcf5": "Zilganzaļš 0",
|
||||
"ebfbee": "Zaļš 0",
|
||||
"f4fce3": "Laims 0",
|
||||
"fff9db": "Dzeltens 0",
|
||||
"fff4e6": "Oranžs 0",
|
||||
"transparent": "Caurspīdīgs",
|
||||
"ced4da": "Pelēks 4",
|
||||
"868e96": "Pelēks 6",
|
||||
"fa5252": "Sarkans 6",
|
||||
"e64980": "Rozā 6",
|
||||
"be4bdb": "Vīnogu 6",
|
||||
"7950f2": "Violets 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Zils 6",
|
||||
"15aabf": "Ciāns 6",
|
||||
"12b886": "Zilganzaļš 6",
|
||||
"40c057": "Zaļš 6",
|
||||
"82c91e": "Laims 6",
|
||||
"fab005": "Dzeltens 6",
|
||||
"fd7e14": "Oranžs 6",
|
||||
"000000": "Melns",
|
||||
"343a40": "Pelēks 8",
|
||||
"495057": "Pelēks 7",
|
||||
"c92a2a": "Sarkans 9",
|
||||
"a61e4d": "Rozā 9",
|
||||
"862e9c": "Vīnogu 9",
|
||||
"5f3dc4": "Violets 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Zils 9",
|
||||
"0b7285": "Ciāns 9",
|
||||
"087f5b": "Zilganzaļš 9",
|
||||
"2b8a3e": "Zaļš 9",
|
||||
"5c940d": "Laims 9",
|
||||
"e67700": "Dzeltens 9",
|
||||
"d9480f": "Oranžs 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Izvēlies rīku un sāc zīmēt!",
|
||||
"helpHint": "Īsceļi un palīdzība"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "एक घटक म्हणून चिपकावण्या साठी {{shortcut}} वापरा,\nकिंवा विद्यमान मजकूर संपादकात चिपकवा"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "पांढरा",
|
||||
"f8f9fa": "करडा 0",
|
||||
"f1f3f5": "करडा 1",
|
||||
"fff5f5": "लाल 0",
|
||||
"fff0f6": "गुलाबी 0",
|
||||
"f8f0fc": "अंगूरी 0",
|
||||
"f3f0ff": "जांभळा 0",
|
||||
"edf2ff": "बैंगनी 0",
|
||||
"e7f5ff": "नीळा 0",
|
||||
"e3fafc": "आसमानी 0",
|
||||
"e6fcf5": "पाचू 0",
|
||||
"ebfbee": "हिरवा 0",
|
||||
"f4fce3": "लिंबु 0",
|
||||
"fff9db": "पिवळा 0",
|
||||
"fff4e6": "नारंगी 0",
|
||||
"transparent": "पारदर्शक",
|
||||
"ced4da": "करडा 4",
|
||||
"868e96": "करडा 6",
|
||||
"fa5252": "लाल 6",
|
||||
"e64980": "गुलाबी 6",
|
||||
"be4bdb": "अंगूरी 6",
|
||||
"7950f2": "जांभळा 6",
|
||||
"4c6ef5": "बैंगनी 6",
|
||||
"228be6": "नीळा 6",
|
||||
"15aabf": "आसमानी 6",
|
||||
"12b886": "पाचू 6",
|
||||
"40c057": "हिरवा 6",
|
||||
"82c91e": "लिंबु 6",
|
||||
"fab005": "पिवळा 6",
|
||||
"fd7e14": "नारंगी 6",
|
||||
"000000": "काळा",
|
||||
"343a40": "करडा 8",
|
||||
"495057": "करडा 7",
|
||||
"c92a2a": "लाल 9",
|
||||
"a61e4d": "गुलाबी 9",
|
||||
"862e9c": "अंगूरी 9",
|
||||
"5f3dc4": "जामुनी 9",
|
||||
"364fc7": "बैंगनी 9",
|
||||
"1864ab": "नीला 9",
|
||||
"0b7285": "आसमानी 9",
|
||||
"087f5b": "पाचू 9",
|
||||
"2b8a3e": "हरा 9",
|
||||
"5c940d": "नीबू 9",
|
||||
"e67700": "पीला 9",
|
||||
"d9480f": "नारंगी 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "एक साधन निवडा आणि चित्रीकरण सुरु करा!",
|
||||
"helpHint": "शॉर्टकट आणि सहाय्य"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "",
|
||||
"fff4e6": "",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "",
|
||||
"82c91e": "",
|
||||
"fab005": "",
|
||||
"fd7e14": "",
|
||||
"000000": "",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "",
|
||||
"5c940d": "",
|
||||
"e67700": "",
|
||||
"d9480f": ""
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Bruk {{shortcut}} for å lime inn som ett enkelt element,\neller lim inn i en eksisterende tekstbehandler"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Hvit",
|
||||
"f8f9fa": "Grå 0",
|
||||
"f1f3f5": "Grå 1",
|
||||
"fff5f5": "Rød 0",
|
||||
"fff0f6": "Rosa 0",
|
||||
"f8f0fc": "Drue 0",
|
||||
"f3f0ff": "Fiolett 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Blå 0",
|
||||
"e3fafc": "Turkis 0",
|
||||
"e6fcf5": "Blågrønn 0",
|
||||
"ebfbee": "Grønn 0",
|
||||
"f4fce3": "Limegrønn 0",
|
||||
"fff9db": "Gul 0",
|
||||
"fff4e6": "Oransje 0",
|
||||
"transparent": "Gjennomsiktig",
|
||||
"ced4da": "Grå 4",
|
||||
"868e96": "Grå 6",
|
||||
"fa5252": "Rød 6",
|
||||
"e64980": "Rosa 6",
|
||||
"be4bdb": "Drue 6",
|
||||
"7950f2": "Fiolett 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Blå 6",
|
||||
"15aabf": "Turkis 6",
|
||||
"12b886": "Blågrønn 6",
|
||||
"40c057": "Grønn 6",
|
||||
"82c91e": "Limegrønn 6",
|
||||
"fab005": "Gul 6",
|
||||
"fd7e14": "Oransje 6",
|
||||
"000000": "Sort",
|
||||
"343a40": "Grå 8",
|
||||
"495057": "Grå 7",
|
||||
"c92a2a": "Rød 9",
|
||||
"a61e4d": "Rosa 9",
|
||||
"862e9c": "Drue 9",
|
||||
"5f3dc4": "Fiolett 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Blå 9",
|
||||
"0b7285": "Turkis 9",
|
||||
"087f5b": "Blågrønn 9",
|
||||
"2b8a3e": "Grønn 9",
|
||||
"5c940d": "Limegrønn 9",
|
||||
"e67700": "Gul 9",
|
||||
"d9480f": "Oransje 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Velg et verktøy og start å tegne!",
|
||||
"helpHint": "Snarveier & hjelp"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Gebruik {{shortcut}} om te plakken als een enkel element,\nof plak in een bestaande teksteditor"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Wit",
|
||||
"f8f9fa": "Grijs 0",
|
||||
"f1f3f5": "Grijs 1",
|
||||
"fff5f5": "Rood 0",
|
||||
"fff0f6": "Roze 0",
|
||||
"f8f0fc": "Druiven 0",
|
||||
"f3f0ff": "Violet 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Blauw 0",
|
||||
"e3fafc": "Cyaan 0",
|
||||
"e6fcf5": "Groenblauw 0",
|
||||
"ebfbee": "Groen 0",
|
||||
"f4fce3": "Limoen 0",
|
||||
"fff9db": "Geel 0",
|
||||
"fff4e6": "Oranje 0",
|
||||
"transparent": "Transparant",
|
||||
"ced4da": "Grijs 4",
|
||||
"868e96": "Grijs 6",
|
||||
"fa5252": "Rood 6",
|
||||
"e64980": "Roze 6",
|
||||
"be4bdb": "Druiven 6",
|
||||
"7950f2": "Violet",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Blauw 6",
|
||||
"15aabf": "Cyaan 6",
|
||||
"12b886": "Groenblauw 6",
|
||||
"40c057": "Groen 6",
|
||||
"82c91e": "Limoen 6",
|
||||
"fab005": "Geel 6",
|
||||
"fd7e14": "Oranje 6",
|
||||
"000000": "Zwart",
|
||||
"343a40": "Grijs 8",
|
||||
"495057": "Grijs 7",
|
||||
"c92a2a": "Rood 9",
|
||||
"a61e4d": "Roze 9",
|
||||
"862e9c": "Druiven 9",
|
||||
"5f3dc4": "Violet 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Blauw 9",
|
||||
"0b7285": "Cyaan 9",
|
||||
"087f5b": "Groenblauw 9",
|
||||
"2b8a3e": "Groen 9",
|
||||
"5c940d": "Limoen 9",
|
||||
"e67700": "Geel 9",
|
||||
"d9480f": "Oranje 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Kies een tool & begin met tekenen!",
|
||||
"helpHint": "Snelkoppelingen en hulp"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Kvit",
|
||||
"f8f9fa": "Grå 0",
|
||||
"f1f3f5": "Grå 1",
|
||||
"fff5f5": "Raud 0",
|
||||
"fff0f6": "Rosa 0",
|
||||
"f8f0fc": "Drue 0",
|
||||
"f3f0ff": "Fiolett 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Blå 0",
|
||||
"e3fafc": "Turkis 0",
|
||||
"e6fcf5": "Blågrøn 0",
|
||||
"ebfbee": "Grøn 0",
|
||||
"f4fce3": "Limegrøn 0",
|
||||
"fff9db": "Gul 0",
|
||||
"fff4e6": "Oransje 0",
|
||||
"transparent": "Gjennomsiktig",
|
||||
"ced4da": "Grå 4",
|
||||
"868e96": "Grå 6",
|
||||
"fa5252": "Raud 6",
|
||||
"e64980": "Rosa 6",
|
||||
"be4bdb": "Drue 6",
|
||||
"7950f2": "Fiolett 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Blå 6",
|
||||
"15aabf": "Turkis 6",
|
||||
"12b886": "Blågrøn 6",
|
||||
"40c057": "Grøn 6",
|
||||
"82c91e": "Limegrøn 6",
|
||||
"fab005": "Gul 6",
|
||||
"fd7e14": "Oransje 6",
|
||||
"000000": "Svart",
|
||||
"343a40": "Grå 8",
|
||||
"495057": "Grå 7",
|
||||
"c92a2a": "Raud 9",
|
||||
"a61e4d": "Rosa 9",
|
||||
"862e9c": "Drue 9",
|
||||
"5f3dc4": "Fiolett 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Blå 9",
|
||||
"0b7285": "Turkis 9",
|
||||
"087f5b": "Blågrøn 9",
|
||||
"2b8a3e": "Grøn 9",
|
||||
"5c940d": "Limegrøn 9",
|
||||
"e67700": "Gul 9",
|
||||
"d9480f": "Oransj 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Blanc",
|
||||
"f8f9fa": "Gris 0",
|
||||
"f1f3f5": "Gris 0",
|
||||
"fff5f5": "Roge 0",
|
||||
"fff0f6": "Ròse 0",
|
||||
"f8f0fc": "Bordèu 0",
|
||||
"f3f0ff": "Violet 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Blau 0",
|
||||
"e3fafc": "Cian 0",
|
||||
"e6fcf5": "Esmerauda 0",
|
||||
"ebfbee": "Verd 0",
|
||||
"f4fce3": "Verd citron 0",
|
||||
"fff9db": "Jaune 0",
|
||||
"fff4e6": "Irange 0",
|
||||
"transparent": "Transparéncia",
|
||||
"ced4da": "Gris 4",
|
||||
"868e96": "Gris 6",
|
||||
"fa5252": "Roge 6",
|
||||
"e64980": "Ròse 6",
|
||||
"be4bdb": "Bordèu 6",
|
||||
"7950f2": "Violet 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Blau 6",
|
||||
"15aabf": "Cian 6",
|
||||
"12b886": "Esmerauda 6",
|
||||
"40c057": "Verd 6",
|
||||
"82c91e": "Verd citron 6",
|
||||
"fab005": "Jaune 6",
|
||||
"fd7e14": "Irange 6",
|
||||
"000000": "Negre",
|
||||
"343a40": "Gris 8",
|
||||
"495057": "Gris 7",
|
||||
"c92a2a": "Roge 9",
|
||||
"a61e4d": "Ròse 9",
|
||||
"862e9c": "Bordèu 9",
|
||||
"5f3dc4": "Violet 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Blau 9",
|
||||
"0b7285": "Cian 9",
|
||||
"087f5b": "Esmerauda 9",
|
||||
"2b8a3e": "Verd 9",
|
||||
"5c940d": "Verd citron 9",
|
||||
"e67700": "Jaune 9",
|
||||
"d9480f": "Irange 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Prenètz un esplech e començatz de dessenhar !",
|
||||
"helpHint": "Acorchis e ajuda"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"labels": {
|
||||
"paste": "ਪੇਸਟ ਕਰੋ",
|
||||
"pasteAsPlaintext": "",
|
||||
"pasteAsPlaintext": "ਸਾਦੇ ਪਾਠ ਵਜੋਂ ਪੇਸਟ ਕਰੋ",
|
||||
"pasteCharts": "ਚਾਰਟ ਪੇਸਟ ਕਰੋ",
|
||||
"selectAll": "ਸਾਰੇ ਚੁਣੋ",
|
||||
"multiSelect": "ਐਲੀਮੈਂਟ ਨੂੰ ਚੋਣ ਵਿੱਚ ਜੋੜੋ",
|
||||
|
@ -10,7 +10,7 @@
|
|||
"copy": "ਕਾਪੀ ਕਰੋ",
|
||||
"copyAsPng": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕਰੋ",
|
||||
"copyAsSvg": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ SVG ਵਜੋਂ ਕਾਪੀ ਕਰੋ",
|
||||
"copyText": "",
|
||||
"copyText": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਪਾਠ ਵਜੋਂ ਕਾਪੀ ਕਰੋ",
|
||||
"bringForward": "ਅੱਗੇ ਲਿਆਓ",
|
||||
"sendToBack": "ਸਭ ਤੋਂ ਪਿੱਛੇ ਭੇਜੋ",
|
||||
"bringToFront": "ਸਭ ਤੋਂ ਅੱਗੇ ਲਿਆਓ",
|
||||
|
@ -73,7 +73,7 @@
|
|||
"layers": "ਪਰਤਾਂ",
|
||||
"actions": "ਕਾਰਵਾਈਆਂ",
|
||||
"language": "ਭਾਸ਼ਾ",
|
||||
"liveCollaboration": "",
|
||||
"liveCollaboration": "ਲਾਇਵ ਸਹਿਯੋਗ...",
|
||||
"duplicateSelection": "ਡੁਪਲੀਕੇਟ ਬਣਾਓ",
|
||||
"untitled": "ਬੇ-ਸਿਰਨਾਵਾਂ",
|
||||
"name": "ਨਾਂ",
|
||||
|
@ -109,37 +109,37 @@
|
|||
"excalidrawLib": "ਐਕਸਕਲੀਡਰਾਅ ਲਾਇਬ੍ਰੇਰੀ",
|
||||
"decreaseFontSize": "ਫੌਂਟ ਦਾ ਅਕਾਰ ਘਟਾਓ",
|
||||
"increaseFontSize": "ਫੌਂਟ ਦਾ ਅਕਾਰ ਵਧਾਓ",
|
||||
"unbindText": "",
|
||||
"unbindText": "ਪਾਠ ਨੂੰ ਵੱਖ ਕਰੋ",
|
||||
"bindText": "ਪਾਠ ਨੂੰ ਕੰਟੇਨਰ ਨਾਲ ਬੰਨ੍ਹੋ",
|
||||
"createContainerFromText": "",
|
||||
"createContainerFromText": "ਪਾਠ ਨੂੰ ਕੰਟੇਨਰ ਵਿੱਚ ਇਕੱਠਾ ਕਰੋ",
|
||||
"link": {
|
||||
"edit": "ਕੜੀ ਸੋਧੋ",
|
||||
"create": "ਕੜੀ ਬਣਾਓ",
|
||||
"label": "ਕੜੀ"
|
||||
},
|
||||
"lineEditor": {
|
||||
"edit": "",
|
||||
"exit": ""
|
||||
"edit": "ਪੰਕਤੀ ਸੋਧੋ",
|
||||
"exit": "ਪੰਕਤੀ ਸੋਧਕ 'ਤੋਂ ਬਾਹਰ ਨਿਕਲੋ"
|
||||
},
|
||||
"elementLock": {
|
||||
"lock": "",
|
||||
"unlock": "",
|
||||
"lockAll": "",
|
||||
"unlockAll": ""
|
||||
"lock": "ਲਾਕ ਕਰੋ",
|
||||
"unlock": "ਅਨਲਾਕ ਕਰੋ",
|
||||
"lockAll": "ਸਭ ਲਾਕ ਕਰੋ",
|
||||
"unlockAll": "ਸਭ ਅਨਲਾਕ ਕਰੋ"
|
||||
},
|
||||
"statusPublished": "",
|
||||
"sidebarLock": ""
|
||||
"statusPublished": "ਪ੍ਰਕਾਸ਼ਤ ਹੈ",
|
||||
"sidebarLock": "ਸਾਈਡਬਾਰ ਨੂੰ ਖੁੱਲ੍ਹਾ ਰੱਖੋ"
|
||||
},
|
||||
"library": {
|
||||
"noItems": "",
|
||||
"noItems": "ਹਾਲੇ ਤੱਕ ਕੋਈ ਚੀਜ ਜੋੜੀ ਨਹੀਂ ਗਈ...",
|
||||
"hint_emptyLibrary": "",
|
||||
"hint_emptyPrivateLibrary": ""
|
||||
},
|
||||
"buttons": {
|
||||
"clearReset": "ਕੈਨਵਸ ਰੀਸੈੱਟ ਕਰੋ",
|
||||
"exportJSON": "ਫਾਈਲ ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ",
|
||||
"exportImage": "",
|
||||
"export": "",
|
||||
"exportImage": "ਤਸਵੀਰ ਨਿਰਯਾਤ ਕਰੋ...",
|
||||
"export": "ਇਸ ਵਿੱਚ ਸਾਂਭੋ...",
|
||||
"exportToPng": "PNG ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ",
|
||||
"exportToSvg": "SVG ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ",
|
||||
"copyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕਰੋ",
|
||||
|
@ -147,7 +147,7 @@
|
|||
"scale": "ਪੈਮਾਇਸ਼",
|
||||
"save": "ਮੌਜੂਦਾ ਫਾਈਲ ਵਿੱਚ ਸਾਂਭੋ",
|
||||
"saveAs": "ਇਸ ਵਜੋਂ ਸਾਂਭੋ",
|
||||
"load": "",
|
||||
"load": "ਖੋਲ੍ਹੋ",
|
||||
"getShareableLink": "ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ ਲਵੋ",
|
||||
"close": "ਬੰਦ ਕਰੋ",
|
||||
"selectLanguage": "ਭਾਸ਼ਾ ਚੁਣੋ",
|
||||
|
@ -181,7 +181,7 @@
|
|||
"couldNotLoadInvalidFile": "ਨਜਾਇਜ਼ ਫਾਈਲ ਲੋਡ ਨਹੀਂ ਕਰ ਸਕੇ",
|
||||
"importBackendFailed": "ਬੈਕਐੱਨਡ ਤੋਂ ਆਯਾਤ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਰਹੇ।",
|
||||
"cannotExportEmptyCanvas": "ਖਾਲੀ ਕੈਨਵਸ ਨਿਰਯਾਤ ਨਹੀਂ ਕਰ ਸਕਦੇ।",
|
||||
"couldNotCopyToClipboard": "",
|
||||
"couldNotCopyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।",
|
||||
"decryptFailed": "ਡਾਟਾ ਡੀਕਰਿਪਟ ਨਹੀਂ ਕਰ ਸਕੇ।",
|
||||
"uploadedSecurly": "ਅੱਪਲੋਡ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਸ਼ਨ ਨਾਲ ਸੁਰੱਖਿਅਤ ਕੀਤੀ ਹੋਈ ਹੈ, ਜਿਸਦਾ ਮਤਲਬ ਇਹ ਹੈ ਕਿ Excalidraw ਸਰਵਰ ਅਤੇ ਤੀਜੀ ਧਿਰ ਦੇ ਬੰਦੇ ਸਮੱਗਰੀ ਨੂੰ ਪੜ੍ਹ ਨਹੀਂ ਸਕਦੇ।",
|
||||
"loadSceneOverridePrompt": "ਬਾਹਰੀ ਡਰਾਇੰਗ ਨੂੰ ਲੋਡ ਕਰਨਾ ਤੁਹਾਡੀ ਮੌਜੂਦਾ ਸਮੱਗਰੀ ਦੀ ਥਾਂ ਲੈ ਲਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?",
|
||||
|
@ -198,13 +198,13 @@
|
|||
"collabOfflineWarning": ""
|
||||
},
|
||||
"errors": {
|
||||
"unsupportedFileType": "",
|
||||
"imageInsertError": "",
|
||||
"fileTooBig": "",
|
||||
"unsupportedFileType": "ਫਾਈਲ ਦੀ ਕਿਸਮ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ।",
|
||||
"imageInsertError": "ਚਿੱਤਰ ਸ਼ਾਮਲ ਨਹੀਂ ਜਾ ਸਕਿਆ, ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ...",
|
||||
"fileTooBig": "ਫਾਈਲ ਬਹੁਤ ਜ਼ਿਆਦਾ ਵੱਡੀ ਹੈ। ਵੱਧ-ਤੋਂ-ਵੱਧ ਪ੍ਰਵਾਨਤ ਅਕਾਰ {{maxSize}} ਹੈ।",
|
||||
"svgImageInsertError": "",
|
||||
"invalidSVGString": "SVG ਨਜਾਇਜ਼ ਹੈ।",
|
||||
"cannotResolveCollabServer": "",
|
||||
"importLibraryError": "",
|
||||
"importLibraryError": "ਲਾਇਬ੍ਰੇਰੀ ਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ",
|
||||
"collabSaveFailed": "",
|
||||
"collabSaveFailed_sizeExceeded": "",
|
||||
"brave_measure_text_error": {
|
||||
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "ਚਿੱਟਾ",
|
||||
"f8f9fa": "ਸੁਰਮਈ 0",
|
||||
"f1f3f5": "ਸੁਰਮਈ 1",
|
||||
"fff5f5": "ਲਾਲ 0",
|
||||
"fff0f6": "ਗੁਲਾਬੀ 0",
|
||||
"f8f0fc": "ਅੰਗੂਰੀ 0",
|
||||
"f3f0ff": "ਜਾਮਣੀ 0",
|
||||
"edf2ff": "ਗੂੜ੍ਹਾ ਨੀਲਾ 0",
|
||||
"e7f5ff": "ਨੀਲਾ 0",
|
||||
"e3fafc": "ਫਿਰੋਜੀ 0",
|
||||
"e6fcf5": "ਟੀਲ 0",
|
||||
"ebfbee": "ਹਰਾ 0",
|
||||
"f4fce3": "ਲਾਇਮ 0",
|
||||
"fff9db": "ਪੀਲਾ 0",
|
||||
"fff4e6": "ਸੰਤਰੀ 0",
|
||||
"transparent": "ਪਾਰਦਰਸ਼ੀ",
|
||||
"ced4da": "ਸੁਰਮਈ 4",
|
||||
"868e96": "ਸੁਰਮਈ 6",
|
||||
"fa5252": "ਲਾਲ 6",
|
||||
"e64980": "ਗੁਲਾਬੀ 6",
|
||||
"be4bdb": "ਅੰਗੂਰੀ 6",
|
||||
"7950f2": "ਜਾਮਣੀ 6",
|
||||
"4c6ef5": "ਗੂੜ੍ਹਾ ਨੀਲਾ 6",
|
||||
"228be6": "ਨੀਲਾ 6",
|
||||
"15aabf": "ਫਿਰੋਜੀ 6",
|
||||
"12b886": "ਟੀਲ 6",
|
||||
"40c057": "ਹਰਾ 6",
|
||||
"82c91e": "ਲਾਇਮ 6",
|
||||
"fab005": "ਪੀਲਾ 6",
|
||||
"fd7e14": "ਸੰਤਰੀ 6",
|
||||
"000000": "ਕਾਲਾ",
|
||||
"343a40": "ਸੁਰਮਈ 8",
|
||||
"495057": "ਸੁਰਮਈ 7",
|
||||
"c92a2a": "ਲਾਲ 9",
|
||||
"a61e4d": "ਗੁਲਾਬੀ 9",
|
||||
"862e9c": "ਅੰਗੂਰੀ 9",
|
||||
"5f3dc4": "ਜਾਮਣੀ 9",
|
||||
"364fc7": "ਗੂੜ੍ਹਾ ਨੀਲਾ 9",
|
||||
"1864ab": "ਨੀਲਾ 9",
|
||||
"0b7285": "ਫਿਰੋਜੀ 9",
|
||||
"087f5b": "ਟੀਲ 9",
|
||||
"2b8a3e": "ਹਰਾ 9",
|
||||
"5c940d": "ਲਾਇਮ 9",
|
||||
"e67700": "ਪੀਲਾ 9",
|
||||
"d9480f": "ਸੰਤਰੀ 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +1,55 @@
|
|||
{
|
||||
"ar-SA": 90,
|
||||
"bg-BG": 53,
|
||||
"bn-BD": 59,
|
||||
"ca-ES": 98,
|
||||
"cs-CZ": 73,
|
||||
"da-DK": 32,
|
||||
"de-DE": 100,
|
||||
"el-GR": 97,
|
||||
"ar-SA": 83,
|
||||
"bg-BG": 57,
|
||||
"bn-BD": 63,
|
||||
"ca-ES": 92,
|
||||
"cs-CZ": 67,
|
||||
"da-DK": 35,
|
||||
"de-DE": 94,
|
||||
"el-GR": 92,
|
||||
"en": 100,
|
||||
"es-ES": 99,
|
||||
"eu-ES": 98,
|
||||
"fa-IR": 100,
|
||||
"fi-FI": 98,
|
||||
"fr-FR": 98,
|
||||
"gl-ES": 98,
|
||||
"he-IL": 98,
|
||||
"hi-IN": 71,
|
||||
"hu-HU": 87,
|
||||
"id-ID": 97,
|
||||
"it-IT": 98,
|
||||
"ja-JP": 98,
|
||||
"kaa": 20,
|
||||
"kab-KAB": 93,
|
||||
"kk-KZ": 20,
|
||||
"km-KH": 0,
|
||||
"ko-KR": 100,
|
||||
"ku-TR": 100,
|
||||
"lt-LT": 62,
|
||||
"lv-LV": 99,
|
||||
"mr-IN": 99,
|
||||
"my-MM": 40,
|
||||
"nb-NO": 100,
|
||||
"nl-NL": 91,
|
||||
"nn-NO": 87,
|
||||
"oc-FR": 96,
|
||||
"pa-IN": 81,
|
||||
"pl-PL": 88,
|
||||
"pt-BR": 98,
|
||||
"pt-PT": 99,
|
||||
"ro-RO": 100,
|
||||
"ru-RU": 100,
|
||||
"si-LK": 8,
|
||||
"sk-SK": 100,
|
||||
"sl-SI": 100,
|
||||
"sv-SE": 100,
|
||||
"ta-IN": 92,
|
||||
"th-TH": 40,
|
||||
"tr-TR": 96,
|
||||
"uk-UA": 95,
|
||||
"vi-VN": 56,
|
||||
"zh-CN": 100,
|
||||
"zh-HK": 25,
|
||||
"zh-TW": 100
|
||||
"es-ES": 93,
|
||||
"eu-ES": 94,
|
||||
"fa-IR": 93,
|
||||
"fi-FI": 92,
|
||||
"fr-FR": 93,
|
||||
"gl-ES": 92,
|
||||
"he-IL": 91,
|
||||
"hi-IN": 74,
|
||||
"hu-HU": 80,
|
||||
"id-ID": 92,
|
||||
"it-IT": 94,
|
||||
"ja-JP": 92,
|
||||
"kaa": 18,
|
||||
"kab-KAB": 92,
|
||||
"kk-KZ": 22,
|
||||
"km-KH": 2,
|
||||
"ko-KR": 94,
|
||||
"ku-TR": 94,
|
||||
"lt-LT": 59,
|
||||
"lv-LV": 93,
|
||||
"mr-IN": 93,
|
||||
"my-MM": 43,
|
||||
"nb-NO": 94,
|
||||
"nl-NL": 87,
|
||||
"nn-NO": 81,
|
||||
"oc-FR": 91,
|
||||
"pa-IN": 82,
|
||||
"pl-PL": 83,
|
||||
"pt-BR": 94,
|
||||
"pt-PT": 93,
|
||||
"ro-RO": 94,
|
||||
"ru-RU": 94,
|
||||
"si-LK": 9,
|
||||
"sk-SK": 94,
|
||||
"sl-SI": 94,
|
||||
"sv-SE": 94,
|
||||
"ta-IN": 86,
|
||||
"th-TH": 41,
|
||||
"tr-TR": 91,
|
||||
"uk-UA": 94,
|
||||
"vi-VN": 59,
|
||||
"zh-CN": 94,
|
||||
"zh-HK": 27,
|
||||
"zh-TW": 94
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Biały",
|
||||
"f8f9fa": "Szary 0",
|
||||
"f1f3f5": "Szary 1",
|
||||
"fff5f5": "Czerwony 0",
|
||||
"fff0f6": "Różowy 0",
|
||||
"f8f0fc": "Bordowy 0",
|
||||
"f3f0ff": "Fioletowy 0",
|
||||
"edf2ff": "Granatowy 0",
|
||||
"e7f5ff": "Niebieski 0",
|
||||
"e3fafc": "Błękitny 0",
|
||||
"e6fcf5": "Turkusowy 0",
|
||||
"ebfbee": "Zielony 0",
|
||||
"f4fce3": "Limonkowy 0",
|
||||
"fff9db": "Żółty 0",
|
||||
"fff4e6": "Pomarańczowy 0",
|
||||
"transparent": "Przezroczysty",
|
||||
"ced4da": "Szary 4",
|
||||
"868e96": "Szary 6",
|
||||
"fa5252": "Czerwony 6",
|
||||
"e64980": "Różowy 6",
|
||||
"be4bdb": "Bordowy 6",
|
||||
"7950f2": "Fioletowy 6",
|
||||
"4c6ef5": "Granatowy 6",
|
||||
"228be6": "Niebieski 6",
|
||||
"15aabf": "Błękitny 6",
|
||||
"12b886": "Turkusowy 6",
|
||||
"40c057": "Zielony 6",
|
||||
"82c91e": "Limonkowy 6",
|
||||
"fab005": "Żółty 6",
|
||||
"fd7e14": "Pomarańczowy 6",
|
||||
"000000": "Czarny",
|
||||
"343a40": "Szary 8",
|
||||
"495057": "Szary 7",
|
||||
"c92a2a": "Czerwony 9",
|
||||
"a61e4d": "Różowy 9",
|
||||
"862e9c": "Bordowy 9",
|
||||
"5f3dc4": "Fioletowy 9",
|
||||
"364fc7": "Granatowy 9",
|
||||
"1864ab": "Niebieski 9",
|
||||
"0b7285": "Błękitny 9",
|
||||
"087f5b": "Turkusowy 9",
|
||||
"2b8a3e": "Zielony 9",
|
||||
"5c940d": "Limonkowy 9",
|
||||
"e67700": "Żółty 9",
|
||||
"d9480f": "Pomarańczowy 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
"veryLarge": "Muito grande",
|
||||
"solid": "Sólido",
|
||||
"hachure": "Hachura",
|
||||
"zigzag": "",
|
||||
"zigzag": "Zigue-zague",
|
||||
"crossHatch": "Hachura cruzada",
|
||||
"thin": "Fino",
|
||||
"bold": "Espesso",
|
||||
|
@ -111,7 +111,7 @@
|
|||
"increaseFontSize": "Aumentar o tamanho da fonte",
|
||||
"unbindText": "Desvincular texto",
|
||||
"bindText": "Vincular texto ao contêiner",
|
||||
"createContainerFromText": "",
|
||||
"createContainerFromText": "Envolver texto em um contêiner",
|
||||
"link": {
|
||||
"edit": "Editar link",
|
||||
"create": "Criar link",
|
||||
|
@ -208,10 +208,10 @@
|
|||
"collabSaveFailed": "Não foi possível salvar no banco de dados do servidor. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho.",
|
||||
"collabSaveFailed_sizeExceeded": "Não foi possível salvar no banco de dados do servidor, a tela parece ser muito grande. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho.",
|
||||
"brave_measure_text_error": {
|
||||
"line1": "",
|
||||
"line2": "",
|
||||
"line3": "",
|
||||
"line4": ""
|
||||
"line1": "Parece que você está usando o navegador Brave com a configuração <bold>Bloquear Impressões Digitais</bold> no modo agressivo.",
|
||||
"line2": "Isso pode acabar quebrando <bold>Elementos de Texto</bold> em seus desenhos.",
|
||||
"line3": "Recomendamos fortemente desativar essa configuração. Você pode acessar o <link>passo a passo</link> sobre como fazer isso.",
|
||||
"line4": "Se desativar essa configuração não corrigir a exibição de elementos de texto, por favor abra uma <issueLink>issue</issueLink> em nosso GitHub, ou mande uma mensagem em nosso <discordLink>Discord</discordLink>"
|
||||
}
|
||||
},
|
||||
"toolBar": {
|
||||
|
@ -306,8 +306,8 @@
|
|||
"doubleClick": "clique duplo",
|
||||
"drag": "arrastar",
|
||||
"editor": "Editor",
|
||||
"editLineArrowPoints": "",
|
||||
"editText": "",
|
||||
"editLineArrowPoints": "Editar linha/ponta da seta",
|
||||
"editText": "Editar texto / adicionar etiqueta",
|
||||
"github": "Encontrou algum problema? Nos informe",
|
||||
"howto": "Siga nossos guias",
|
||||
"or": "ou",
|
||||
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Use {{shortcut}} para colar como um único elemento,\nou cole em um editor de texto já existente"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Braco",
|
||||
"f8f9fa": "Cinza 0",
|
||||
"f1f3f5": "Cinza 1",
|
||||
"fff5f5": "Vermelho 0",
|
||||
"fff0f6": "Rosa 0",
|
||||
"f8f0fc": "Uva 0",
|
||||
"f3f0ff": "Violeta 0",
|
||||
"edf2ff": "Índigo 0",
|
||||
"e7f5ff": "Azul 0",
|
||||
"e3fafc": "Ciano 0",
|
||||
"e6fcf5": "Verde-azulado 0",
|
||||
"ebfbee": "Verde 0",
|
||||
"f4fce3": "Lima 0",
|
||||
"fff9db": "Amarelo 0",
|
||||
"fff4e6": "Laranja 0",
|
||||
"transparent": "Transparente",
|
||||
"ced4da": "Cinza 4",
|
||||
"868e96": "Cinza 6",
|
||||
"fa5252": "Vermelho 6",
|
||||
"e64980": "Rosa 6",
|
||||
"be4bdb": "Uva 6",
|
||||
"7950f2": "Violeta 6",
|
||||
"4c6ef5": "Índigo 6",
|
||||
"228be6": "Azul 6",
|
||||
"15aabf": "Ciano 6",
|
||||
"12b886": "Verde-azulado 6",
|
||||
"40c057": "Verde 6",
|
||||
"82c91e": "Lima 6",
|
||||
"fab005": "Amarelo 6",
|
||||
"fd7e14": "Laranja 6",
|
||||
"000000": "Preto",
|
||||
"343a40": "Cinza 8",
|
||||
"495057": "Cinza 7",
|
||||
"c92a2a": "Vermelho 9",
|
||||
"a61e4d": "Rosa 9",
|
||||
"862e9c": "Uva 9",
|
||||
"5f3dc4": "Violeta 9",
|
||||
"364fc7": "Índigo 9",
|
||||
"1864ab": "Azul 9",
|
||||
"0b7285": "Ciano 9",
|
||||
"087f5b": "Verde-azulado 9",
|
||||
"2b8a3e": "Verde 9",
|
||||
"5c940d": "Lima 9",
|
||||
"e67700": "Amarelo 9",
|
||||
"d9480f": "Laranja 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Escolha uma ferramenta e comece a desenhar!",
|
||||
"helpHint": "Atalhos e ajuda"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Usar {{shortcut}} para colar como um único elemento,\nou colar num editor de texto existente"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Branco",
|
||||
"f8f9fa": "Cinza 0",
|
||||
"f1f3f5": "Cinza 1",
|
||||
"fff5f5": "Vermelho 0",
|
||||
"fff0f6": "Rosa 0",
|
||||
"f8f0fc": "Uva 0",
|
||||
"f3f0ff": "Violeta 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Azul 0",
|
||||
"e3fafc": "Ciano 0",
|
||||
"e6fcf5": "Verde-azulado 0",
|
||||
"ebfbee": "Verde 0",
|
||||
"f4fce3": "Lima 0",
|
||||
"fff9db": "Amarelo 0",
|
||||
"fff4e6": "Laranja 0",
|
||||
"transparent": "Transparente",
|
||||
"ced4da": "Cinza 4",
|
||||
"868e96": "Cinza 6",
|
||||
"fa5252": "Vermelho 6",
|
||||
"e64980": "Rosa 6",
|
||||
"be4bdb": "Uva 6",
|
||||
"7950f2": "Violeta 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Azul 6",
|
||||
"15aabf": "Ciano 6",
|
||||
"12b886": "Verde-azulado 6",
|
||||
"40c057": "Verde 6",
|
||||
"82c91e": "Lima 6",
|
||||
"fab005": "Amarelo 6",
|
||||
"fd7e14": "Laranja 6",
|
||||
"000000": "Preto",
|
||||
"343a40": "Cinza 8",
|
||||
"495057": "Cinza 7",
|
||||
"c92a2a": "Vermelho 9",
|
||||
"a61e4d": "Rosa 9",
|
||||
"862e9c": "Uva 9",
|
||||
"5f3dc4": "Violeta 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Azul 9",
|
||||
"0b7285": "Ciano 9",
|
||||
"087f5b": "Verde-azulado 9",
|
||||
"2b8a3e": "Verde 9",
|
||||
"5c940d": "Lima 9",
|
||||
"e67700": "Amarelo 9",
|
||||
"d9480f": "Laranja 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Escolha uma ferramenta e comece a desenhar!",
|
||||
"helpHint": "Atalhos e ajuda"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,11 +264,11 @@
|
|||
"canvasTooBigTip": "Sfat: încearcă să apropii puțin mai mult elementele cele mai îndepărtate."
|
||||
},
|
||||
"errorSplash": {
|
||||
"headingMain": "A apărut o eroare. Încearcă <button>să reîncarci pagina.</button>",
|
||||
"clearCanvasMessage": "Dacă reîncărcarea nu funcționează, încearcă <button>să golești pânza.</button>",
|
||||
"headingMain": "A apărut o eroare. Încearcă <button>să reîncarci pagina</button>.",
|
||||
"clearCanvasMessage": "Dacă reîncărcarea nu funcționează, încearcă <button>să ștergi pânza</button>.",
|
||||
"clearCanvasCaveat": " Acest lucru va duce la pierderea progresului ",
|
||||
"trackedToSentry": "Eroarea cu identificatorul {{eventId}} a fost urmărită în sistemul nostru.",
|
||||
"openIssueMessage": "Am luat măsuri de precauție pentru a nu include informații despre scenă în eroare. Dacă scena nu este privată, te rugăm să ne oferi mai multe informații în <button>monitorul nostru pentru erori.</button> Te rugăm să incluzi informațiile de mai jos prin copierea și lipirea în problema GitHub.",
|
||||
"openIssueMessage": "Am luat măsuri de precauție pentru a nu include informații despre scenă în eroare. Dacă scena nu este privată, oferă-ne mai multe informații în <button>monitorul nostru pentru erori</button>. Include informațiile de mai jos copiindu-le și lipindu-le în tichetul cu problemă de pe GitHub.",
|
||||
"sceneContent": "Conținutul scenei:"
|
||||
},
|
||||
"roomDialog": {
|
||||
|
@ -348,8 +348,8 @@
|
|||
"required": "Obligatoriu",
|
||||
"website": "Introdu un URL valid"
|
||||
},
|
||||
"noteDescription": "Trimite-ți biblioteca pentru fi inclus în <link>depozitul de biblioteci publice</link>pentru utilizarea de către alte persoane în desenele lor.",
|
||||
"noteGuidelines": "Biblioteca trebuie aprobată manual. Citește <link>orientările</link> înainte de trimitere. Vei avea nevoie de un cont GitHub pentru a comunica și efectua modificări, dacă este cazul, însă nu este strict necesar.",
|
||||
"noteDescription": "Trimite-ți biblioteca pentru a fi inclusă în <link>depozitul de biblioteci publice</link> în vederea utilizării de către alte persoane în desenele lor.",
|
||||
"noteGuidelines": "Biblioteca trebuie aprobată manual mai întâi. Citește <link>orientările</link> înainte de trimitere. Vei avea nevoie de un cont GitHub pentru a comunica și efectua modificări, dacă este cazul, însă nu este strict necesar.",
|
||||
"noteLicense": "Prin trimiterea bibliotecii, ești de acord că aceasta va fi publicată sub <link>Licența MIT, </link>care, pe scurt, înseamnă că oricine o poate folosi fără restricții.",
|
||||
"noteItems": "Fiecare element din bibliotecă trebuie să aibă propriul nume astfel încât să fie filtrabil. Următoarele elemente din bibliotecă vor fi incluse:",
|
||||
"atleastOneLibItem": "Selectează cel puțin un element din bibliotecă pentru a începe",
|
||||
|
@ -357,7 +357,7 @@
|
|||
},
|
||||
"publishSuccessDialog": {
|
||||
"title": "Bibliotecă trimisă",
|
||||
"content": "Îți mulțumim, {{authorName}}. Biblioteca ta a fost trimisă spre revizuire. Poți urmări starea<link>aici</link>"
|
||||
"content": "Îți mulțumim, {{authorName}}. Biblioteca a fost trimisă spre revizuire. Poți urmări starea <link>aici</link>"
|
||||
},
|
||||
"confirmDialog": {
|
||||
"resetLibrary": "Resetare bibliotecă",
|
||||
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Folosește {{shortcut}} pentru a insera ca un singur element\nsau insera într-un editor de text existent"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Alb",
|
||||
"f8f9fa": "Gri 0",
|
||||
"f1f3f5": "Gri 1",
|
||||
"fff5f5": "Roșu 0",
|
||||
"fff0f6": "Roz 0",
|
||||
"f8f0fc": "Struguriu 0",
|
||||
"f3f0ff": "Violet 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Albastru 0",
|
||||
"e3fafc": "Cyan 0",
|
||||
"e6fcf5": "Cyan-verde",
|
||||
"ebfbee": "Verde 0",
|
||||
"f4fce3": "Verde-limetă",
|
||||
"fff9db": "Galben 0",
|
||||
"fff4e6": "Portocaliu 0",
|
||||
"transparent": "Transparent",
|
||||
"ced4da": "Gri 4",
|
||||
"868e96": "Gri 6",
|
||||
"fa5252": "Roșu 6",
|
||||
"e64980": "Roz 6",
|
||||
"be4bdb": "Struguriu 6",
|
||||
"7950f2": "Violet 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Albastru 6",
|
||||
"15aabf": "Cyan 6",
|
||||
"12b886": "Cyan-verde 6",
|
||||
"40c057": "Verde 6",
|
||||
"82c91e": "Verde-limetă 6",
|
||||
"fab005": "Galben 6",
|
||||
"fd7e14": "Portocaliu 6",
|
||||
"000000": "Negru",
|
||||
"343a40": "Gri 8",
|
||||
"495057": "Gri 7",
|
||||
"c92a2a": "Roșu 9",
|
||||
"a61e4d": "Roz 9",
|
||||
"862e9c": "Struguriu 9",
|
||||
"5f3dc4": "Violet 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Albastru 9",
|
||||
"0b7285": "Cyan 9",
|
||||
"087f5b": "Cyan-verde 9",
|
||||
"2b8a3e": "Verde 9",
|
||||
"5c940d": "Verde-limetă 9",
|
||||
"e67700": "Galben 9",
|
||||
"d9480f": "Portocaliu 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Alege un instrument și începe să desenezi!",
|
||||
"helpHint": "Comenzi rapide și ajutor"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Используйте {{shortcut}}, чтобы вставить один объект,\nили вставьте в существующий текстовый редактор"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Белый",
|
||||
"f8f9fa": "Серый 0",
|
||||
"f1f3f5": "Серый 1",
|
||||
"fff5f5": "Красный 0",
|
||||
"fff0f6": "Розовый 0",
|
||||
"f8f0fc": "Виноградный 0",
|
||||
"f3f0ff": "Фиолетовый 0",
|
||||
"edf2ff": "Индиго 0",
|
||||
"e7f5ff": "Синий 0",
|
||||
"e3fafc": "Голубой 0",
|
||||
"e6fcf5": "Бирюзовый 0",
|
||||
"ebfbee": "Зелёный 0",
|
||||
"f4fce3": "Лайм 0",
|
||||
"fff9db": "Жёлтый 0",
|
||||
"fff4e6": "Оранжевый 0",
|
||||
"transparent": "Прозрачный",
|
||||
"ced4da": "Серый 4",
|
||||
"868e96": "Серый 6",
|
||||
"fa5252": "Красный 6",
|
||||
"e64980": "Розовый 6",
|
||||
"be4bdb": "Виноградный 6",
|
||||
"7950f2": "Фиолетовый 6",
|
||||
"4c6ef5": "Индиго 6",
|
||||
"228be6": "Синий 6",
|
||||
"15aabf": "Голубой 6",
|
||||
"12b886": "Бирюзовый 6",
|
||||
"40c057": "Зелёный 6",
|
||||
"82c91e": "Лайм 6",
|
||||
"fab005": "Жёлтый 6",
|
||||
"fd7e14": "Оранжевый 6",
|
||||
"000000": "Чёрный",
|
||||
"343a40": "Серый 8",
|
||||
"495057": "Серый 7",
|
||||
"c92a2a": "Красный 9",
|
||||
"a61e4d": "Розовый 9",
|
||||
"862e9c": "Виноградный 9",
|
||||
"5f3dc4": "Фиолетовый 9",
|
||||
"364fc7": "Индиго 9",
|
||||
"1864ab": "Синий 9",
|
||||
"0b7285": "Голубой 9",
|
||||
"087f5b": "Бирюзовый 9",
|
||||
"2b8a3e": "Зелёный 9",
|
||||
"5c940d": "Лайм 9",
|
||||
"e67700": "Жёлтый 9",
|
||||
"d9480f": "Оранжевый 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Выберите инструмент и начните рисовать!",
|
||||
"helpHint": "Сочетания клавиш и помощь"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": ""
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "",
|
||||
"f8f9fa": "",
|
||||
"f1f3f5": "",
|
||||
"fff5f5": "",
|
||||
"fff0f6": "",
|
||||
"f8f0fc": "",
|
||||
"f3f0ff": "",
|
||||
"edf2ff": "",
|
||||
"e7f5ff": "",
|
||||
"e3fafc": "",
|
||||
"e6fcf5": "",
|
||||
"ebfbee": "",
|
||||
"f4fce3": "",
|
||||
"fff9db": "",
|
||||
"fff4e6": "",
|
||||
"transparent": "",
|
||||
"ced4da": "",
|
||||
"868e96": "",
|
||||
"fa5252": "",
|
||||
"e64980": "",
|
||||
"be4bdb": "",
|
||||
"7950f2": "",
|
||||
"4c6ef5": "",
|
||||
"228be6": "",
|
||||
"15aabf": "",
|
||||
"12b886": "",
|
||||
"40c057": "",
|
||||
"82c91e": "",
|
||||
"fab005": "",
|
||||
"fd7e14": "",
|
||||
"000000": "",
|
||||
"343a40": "",
|
||||
"495057": "",
|
||||
"c92a2a": "",
|
||||
"a61e4d": "",
|
||||
"862e9c": "",
|
||||
"5f3dc4": "",
|
||||
"364fc7": "",
|
||||
"1864ab": "",
|
||||
"0b7285": "",
|
||||
"087f5b": "",
|
||||
"2b8a3e": "",
|
||||
"5c940d": "",
|
||||
"e67700": "",
|
||||
"d9480f": ""
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "",
|
||||
"helpHint": ""
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Použitím {{shortcut}} vložte ako samostatný prvok alebo vložte do existujúceho editovaného textu"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Biela",
|
||||
"f8f9fa": "Sivá 0",
|
||||
"f1f3f5": "Sivá 1",
|
||||
"fff5f5": "Červená 0",
|
||||
"fff0f6": "Ružová 0",
|
||||
"f8f0fc": "Hroznová fialová 0",
|
||||
"f3f0ff": "Fialová 0",
|
||||
"edf2ff": "Tmavomodrá 0",
|
||||
"e7f5ff": "Modrá 0",
|
||||
"e3fafc": "Azúrová 0",
|
||||
"e6fcf5": "Modrozelená 0",
|
||||
"ebfbee": "Zelená 0",
|
||||
"f4fce3": "Limetková 0",
|
||||
"fff9db": "Žltá 0",
|
||||
"fff4e6": "Oranžová 0",
|
||||
"transparent": "Priehľadná",
|
||||
"ced4da": "Sivá 4",
|
||||
"868e96": "Sivá 6",
|
||||
"fa5252": "Červená 6",
|
||||
"e64980": "Ružová 6",
|
||||
"be4bdb": "Hroznová fialová 6",
|
||||
"7950f2": "Fialová 6",
|
||||
"4c6ef5": "Tmavomodrá 6",
|
||||
"228be6": "Modrá 6",
|
||||
"15aabf": "Azúrová 6",
|
||||
"12b886": "Modrozelená 6",
|
||||
"40c057": "Zelená 6",
|
||||
"82c91e": "Limetková 6",
|
||||
"fab005": "Žltá 6",
|
||||
"fd7e14": "Oranžová 6",
|
||||
"000000": "Čierna",
|
||||
"343a40": "Sivá 8",
|
||||
"495057": "Sivá 7",
|
||||
"c92a2a": "Červená 9",
|
||||
"a61e4d": "Ružová 9",
|
||||
"862e9c": "Hroznová fialová 9",
|
||||
"5f3dc4": "Fialová 9",
|
||||
"364fc7": "Tmavomodrá 9",
|
||||
"1864ab": "Modrá 9",
|
||||
"0b7285": "Azúrová 9",
|
||||
"087f5b": "Modrozelená 9",
|
||||
"2b8a3e": "Zelená 9",
|
||||
"5c940d": "Limetková 9",
|
||||
"e67700": "Žltá 9",
|
||||
"d9480f": "Oranžová 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Zvoľte nástroj a začnite kresliť!",
|
||||
"helpHint": "Klávesové skratky a pomocník"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,51 +394,21 @@
|
|||
"pasteAsSingleElement": "Uporabite {{shortcut}}, da prilepite kot en element,\n ali prilepite v obstoječ urejevalnik besedil"
|
||||
},
|
||||
"colors": {
|
||||
"ffffff": "Bela",
|
||||
"f8f9fa": "Siva 0",
|
||||
"f1f3f5": "Siva 1",
|
||||
"fff5f5": "Rdeča 0",
|
||||
"fff0f6": "Roza 0",
|
||||
"f8f0fc": "Grozdje 0",
|
||||
"f3f0ff": "Vijolična 0",
|
||||
"edf2ff": "Indigo 0",
|
||||
"e7f5ff": "Modra 0",
|
||||
"e3fafc": "Cijan 0",
|
||||
"e6fcf5": "Modrozelena 0",
|
||||
"ebfbee": "Zelena 0",
|
||||
"f4fce3": "Limeta 0",
|
||||
"fff9db": "Rumena 0",
|
||||
"fff4e6": "Oranžna 0",
|
||||
"transparent": "Prosojno",
|
||||
"ced4da": "Siva 4",
|
||||
"868e96": "Siva 6",
|
||||
"fa5252": "Rdeča 6",
|
||||
"e64980": "Roza 6",
|
||||
"be4bdb": "Grozdje 6",
|
||||
"7950f2": "Vijolična 6",
|
||||
"4c6ef5": "Indigo 6",
|
||||
"228be6": "Modra 6",
|
||||
"15aabf": "Cijan 6",
|
||||
"12b886": "Modrozelena 6",
|
||||
"40c057": "Zelena 6",
|
||||
"82c91e": "Limeta 6",
|
||||
"fab005": "Rumena 6",
|
||||
"fd7e14": "Oranžna 6",
|
||||
"000000": "Črna",
|
||||
"343a40": "Siva 8",
|
||||
"495057": "Siva 7",
|
||||
"c92a2a": "Rdeča 9",
|
||||
"a61e4d": "Roza 9",
|
||||
"862e9c": "Grozdje 9",
|
||||
"5f3dc4": "Vijolična 9",
|
||||
"364fc7": "Indigo 9",
|
||||
"1864ab": "Modra 9",
|
||||
"0b7285": "Cijan 9",
|
||||
"087f5b": "Modrozelena 9",
|
||||
"2b8a3e": "Zelena 9",
|
||||
"5c940d": "Limeta 9",
|
||||
"e67700": "Rumena 9",
|
||||
"d9480f": "Oranžna 9"
|
||||
"black": "",
|
||||
"white": "",
|
||||
"red": "",
|
||||
"pink": "",
|
||||
"grape": "",
|
||||
"violet": "",
|
||||
"gray": "",
|
||||
"blue": "",
|
||||
"cyan": "",
|
||||
"teal": "",
|
||||
"green": "",
|
||||
"yellow": "",
|
||||
"orange": "",
|
||||
"bronze": ""
|
||||
},
|
||||
"welcomeScreen": {
|
||||
"app": {
|
||||
|
@ -452,5 +422,12 @@
|
|||
"toolbarHint": "Izberi orodje in začni z risanjem!",
|
||||
"helpHint": "Bližnjice in pomoč"
|
||||
}
|
||||
},
|
||||
"colorPicker": {
|
||||
"mostUsedCustomColors": "",
|
||||
"colors": "",
|
||||
"shades": "",
|
||||
"hexCode": "",
|
||||
"noShades": ""
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue