mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-24 09:38:29 +02:00
snake_case icons and better toast styles
This commit is contained in:
@@ -46,7 +46,7 @@
|
|||||||
"@tauri-apps/plugin-log": "^2.0.0-rc.1",
|
"@tauri-apps/plugin-log": "^2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-os": "^2.0.0-rc.1",
|
"@tauri-apps/plugin-os": "^2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-shell": "^2.0.0-rc.1",
|
"@tauri-apps/plugin-shell": "^2.0.0-rc.1",
|
||||||
"@yaakapp/api": "^0.2.3",
|
"@yaakapp/api": "^0.2.4",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"cm6-graphql": "^0.0.9",
|
"cm6-graphql": "^0.0.9",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@yaakapp/api",
|
"name": "@yaakapp/api",
|
||||||
"version": "0.2.3",
|
"version": "0.2.5",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"typings": "./lib/index.d.ts",
|
"typings": "./lib/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ export type CallTemplateFunctionRequest = { name: string, args: CallTemplateFunc
|
|||||||
|
|
||||||
export type CallTemplateFunctionResponse = { value: string | null, };
|
export type CallTemplateFunctionResponse = { value: string | null, };
|
||||||
|
|
||||||
|
export type Color = "custom" | "default" | "primary" | "secondary" | "info" | "success" | "notice" | "warning" | "danger";
|
||||||
|
|
||||||
export type CopyTextRequest = { text: string, };
|
export type CopyTextRequest = { text: string, };
|
||||||
|
|
||||||
export type ExportHttpRequestRequest = { httpRequest: HttpRequest, };
|
export type ExportHttpRequestRequest = { httpRequest: HttpRequest, };
|
||||||
@@ -52,6 +54,8 @@ export type GetTemplateFunctionsResponse = { functions: Array<TemplateFunction>,
|
|||||||
|
|
||||||
export type HttpRequestAction = { key: string, label: string, icon: string | null, };
|
export type HttpRequestAction = { key: string, label: string, icon: string | null, };
|
||||||
|
|
||||||
|
export type Icon = "copy" | "info" | "check_circle" | "alert_triangle";
|
||||||
|
|
||||||
export type ImportRequest = { content: string, };
|
export type ImportRequest = { content: string, };
|
||||||
|
|
||||||
export type ImportResources = { workspaces: Array<Workspace>, environments: Array<Environment>, folders: Array<Folder>, httpRequests: Array<HttpRequest>, grpcRequests: Array<GrpcRequest>, };
|
export type ImportResources = { workspaces: Array<Workspace>, environments: Array<Environment>, folders: Array<Folder>, httpRequests: Array<HttpRequest>, grpcRequests: Array<GrpcRequest>, };
|
||||||
@@ -74,7 +78,7 @@ export type SendHttpRequestRequest = { httpRequest: HttpRequest, };
|
|||||||
|
|
||||||
export type SendHttpRequestResponse = { httpResponse: HttpResponse, };
|
export type SendHttpRequestResponse = { httpResponse: HttpResponse, };
|
||||||
|
|
||||||
export type ShowToastRequest = { message: string, variant: ToastVariant, };
|
export type ShowToastRequest = { message: string, color?: Color | null, icon?: Icon | null, };
|
||||||
|
|
||||||
export type TemplateFunction = { name: string, args: Array<TemplateFunctionArg>, };
|
export type TemplateFunction = { name: string, args: Array<TemplateFunctionArg>, };
|
||||||
|
|
||||||
@@ -91,5 +95,3 @@ export type TemplateFunctionSelectArg = { options: Array<TemplateFunctionSelectO
|
|||||||
export type TemplateFunctionSelectOption = { name: string, value: string, };
|
export type TemplateFunctionSelectOption = { name: string, value: string, };
|
||||||
|
|
||||||
export type TemplateFunctionTextArg = { placeholder?: string | null, name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };
|
export type TemplateFunctionTextArg = { placeholder?: string | null, name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };
|
||||||
|
|
||||||
export type ToastVariant = "custom" | "copied" | "success" | "info" | "warning" | "error";
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export type * from './plugins';
|
export type * from './plugins';
|
||||||
export type * from './themes';
|
export type * from './themes';
|
||||||
|
|
||||||
export * from './gen/models';
|
export * from './gen/model_util';
|
||||||
export * from './gen/events';
|
export * from './gen/events';
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { FindHttpResponsesRequest } from '../gen/FindHttpResponsesRequest';
|
import {
|
||||||
import { FindHttpResponsesResponse } from '../gen/FindHttpResponsesResponse';
|
FindHttpResponsesRequest,
|
||||||
import { GetHttpRequestByIdRequest } from '../gen/GetHttpRequestByIdRequest';
|
FindHttpResponsesResponse,
|
||||||
import { GetHttpRequestByIdResponse } from '../gen/GetHttpRequestByIdResponse';
|
GetHttpRequestByIdRequest,
|
||||||
import { RenderHttpRequestRequest } from '../gen/RenderHttpRequestRequest';
|
GetHttpRequestByIdResponse,
|
||||||
import { RenderHttpRequestResponse } from '../gen/RenderHttpRequestResponse';
|
RenderHttpRequestRequest,
|
||||||
import { SendHttpRequestRequest } from '../gen/SendHttpRequestRequest';
|
RenderHttpRequestResponse,
|
||||||
import { SendHttpRequestResponse } from '../gen/SendHttpRequestResponse';
|
SendHttpRequestRequest,
|
||||||
import { ShowToastRequest } from '../gen/ShowToastRequest';
|
SendHttpRequestResponse,
|
||||||
|
ShowToastRequest,
|
||||||
|
} from '../gen/events';
|
||||||
|
|
||||||
export type Context = {
|
export type Context = {
|
||||||
clipboard: {
|
clipboard: {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { CallHttpRequestActionArgs } from '../gen/CallHttpRequestActionArgs';
|
import { CallHttpRequestActionArgs, HttpRequestAction } from '../gen/events';
|
||||||
import { HttpRequestAction } from '../gen/HttpRequestAction';
|
|
||||||
import { Context } from './Context';
|
import { Context } from './Context';
|
||||||
|
|
||||||
export type HttpRequestActionPlugin = HttpRequestAction & {
|
export type HttpRequestActionPlugin = HttpRequestAction & {
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import { Environment } from '../gen/Environment';
|
import { Environment, Folder, HttpRequest, Workspace } from '../gen/model_util';
|
||||||
import { Folder } from '../gen/Folder';
|
|
||||||
import { HttpRequest } from '../gen/HttpRequest';
|
|
||||||
import { Workspace } from '../gen/Workspace';
|
|
||||||
import { AtLeast } from '../helpers';
|
import { AtLeast } from '../helpers';
|
||||||
import { Context } from './Context';
|
import { Context } from './Context';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { CallTemplateFunctionArgs } from '../gen/CallTemplateFunctionArgs';
|
import { CallTemplateFunctionArgs, TemplateFunction } from '../gen/events';
|
||||||
import { TemplateFunction } from '../gen/TemplateFunction';
|
|
||||||
import { Context } from './Context';
|
import { Context } from './Context';
|
||||||
|
|
||||||
export type TemplateFunctionPlugin = TemplateFunction & {
|
export type TemplateFunctionPlugin = TemplateFunction & {
|
||||||
|
|||||||
Binary file not shown.
@@ -10,8 +10,8 @@ use std::process::exit;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use base64::Engine;
|
|
||||||
use base64::prelude::BASE64_STANDARD;
|
use base64::prelude::BASE64_STANDARD;
|
||||||
|
use base64::Engine;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use fern::colors::ColoredLevelConfig;
|
use fern::colors::ColoredLevelConfig;
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
@@ -59,9 +59,9 @@ use yaak_models::queries::{
|
|||||||
};
|
};
|
||||||
use yaak_plugin_runtime::events::{
|
use yaak_plugin_runtime::events::{
|
||||||
BootResponse, CallHttpRequestActionRequest, FilterResponse, FindHttpResponsesResponse,
|
BootResponse, CallHttpRequestActionRequest, FilterResponse, FindHttpResponsesResponse,
|
||||||
GetHttpRequestActionsResponse, GetHttpRequestByIdResponse, GetTemplateFunctionsResponse,
|
GetHttpRequestActionsResponse, GetHttpRequestByIdResponse, GetTemplateFunctionsResponse, Icon,
|
||||||
InternalEvent, InternalEventPayload, RenderHttpRequestResponse, SendHttpRequestResponse,
|
InternalEvent, InternalEventPayload, RenderHttpRequestResponse, SendHttpRequestResponse,
|
||||||
ShowToastRequest, ToastVariant,
|
ShowToastRequest,
|
||||||
};
|
};
|
||||||
use yaak_plugin_runtime::plugin_handle::PluginHandle;
|
use yaak_plugin_runtime::plugin_handle::PluginHandle;
|
||||||
use yaak_templates::{Parser, Tokens};
|
use yaak_templates::{Parser, Tokens};
|
||||||
@@ -2146,7 +2146,8 @@ async fn handle_plugin_event<R: Runtime>(
|
|||||||
let toast_event = plugin_handle.build_event_to_send(
|
let toast_event = plugin_handle.build_event_to_send(
|
||||||
&InternalEventPayload::ShowToastRequest(ShowToastRequest {
|
&InternalEventPayload::ShowToastRequest(ShowToastRequest {
|
||||||
message: format!("Reloaded plugin {}", plugin_handle.dir),
|
message: format!("Reloaded plugin {}", plugin_handle.dir),
|
||||||
variant: ToastVariant::Info,
|
icon: Some(Icon::Info),
|
||||||
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@@ -2223,9 +2224,9 @@ fn get_focused_window_no_lock<R: Runtime>(app_handle: &AppHandle<R>) -> Option<W
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<WebviewWindow<R>>>();
|
.collect::<Vec<WebviewWindow<R>>>();
|
||||||
|
|
||||||
if main_windows.len() == 1 {
|
if main_windows.len() == 1 {
|
||||||
return main_windows.iter().next().map(|w| w.clone())
|
return main_windows.iter().next().map(|w| w.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
main_windows
|
main_windows
|
||||||
|
|||||||
@@ -169,27 +169,43 @@ pub struct RenderHttpRequestResponse {
|
|||||||
#[ts(export, export_to="events.ts")]
|
#[ts(export, export_to="events.ts")]
|
||||||
pub struct ShowToastRequest {
|
pub struct ShowToastRequest {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub variant: ToastVariant,
|
#[ts(optional = nullable)]
|
||||||
|
pub color: Option<Color>,
|
||||||
|
#[ts(optional = nullable)]
|
||||||
|
pub icon: Option<Icon>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[ts(export, export_to="events.ts")]
|
#[ts(export, export_to="events.ts")]
|
||||||
pub enum ToastVariant {
|
pub enum Color {
|
||||||
Custom,
|
Custom,
|
||||||
Copied,
|
Default,
|
||||||
Success,
|
Primary,
|
||||||
|
Secondary,
|
||||||
Info,
|
Info,
|
||||||
|
Success,
|
||||||
|
Notice,
|
||||||
Warning,
|
Warning,
|
||||||
Error,
|
Danger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ToastVariant {
|
impl Default for Color {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ToastVariant::Info
|
Color::Default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
#[ts(export, export_to="events.ts")]
|
||||||
|
pub enum Icon {
|
||||||
|
Copy,
|
||||||
|
Info,
|
||||||
|
CheckCircle,
|
||||||
|
AlertTriangle,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||||
#[serde(default, rename_all = "camelCase")]
|
#[serde(default, rename_all = "camelCase")]
|
||||||
#[ts(export, export_to="events.ts")]
|
#[ts(export, export_to="events.ts")]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { Cookie } from '@yaakapp/api';
|
import type { Cookie } from '@yaakapp/api';
|
||||||
import { useCookieJars } from '../hooks/useCookieJars';
|
import { useCookieJars } from '../hooks/useCookieJars';
|
||||||
import { useUpdateCookieJar } from '../hooks/useUpdateCookieJar';
|
import { useUpdateCookieJar } from '../hooks/useUpdateCookieJar';
|
||||||
import { cookieDomain } from '../lib/models';
|
import { cookieDomain } from '../lib/model_util';
|
||||||
import { Banner } from './core/Banner';
|
import { Banner } from './core/Banner';
|
||||||
import { IconButton } from './core/IconButton';
|
import { IconButton } from './core/IconButton';
|
||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export const EnvironmentEditDialog = function ({ initialEnvironment }: Props) {
|
|||||||
iconSize="md"
|
iconSize="md"
|
||||||
color="custom"
|
color="custom"
|
||||||
title="Add sub environment"
|
title="Add sub environment"
|
||||||
icon="plusCircle"
|
icon="plus_circle"
|
||||||
iconClassName="text-text-subtlest group-hover:text-text-subtle"
|
iconClassName="text-text-subtlest group-hover:text-text-subtle"
|
||||||
className="group"
|
className="group"
|
||||||
onClick={handleCreateEnvironment}
|
onClick={handleCreateEnvironment}
|
||||||
@@ -177,7 +177,7 @@ const EnvironmentEditor = function ({
|
|||||||
<IconButton
|
<IconButton
|
||||||
iconClassName="text-text-subtlest"
|
iconClassName="text-text-subtlest"
|
||||||
size="sm"
|
size="sm"
|
||||||
icon={valueVisibility.value ? 'eye' : 'eyeClosed'}
|
icon={valueVisibility.value ? 'eye' : 'eye_closed'}
|
||||||
title={valueVisibility.value ? 'Hide Values' : 'Reveal Values'}
|
title={valueVisibility.value ? 'Hide Values' : 'Reveal Values'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
return valueVisibility.set((v) => !v);
|
return valueVisibility.set((v) => !v);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
|||||||
import { workspacesAtom } from '../hooks/useWorkspaces';
|
import { workspacesAtom } from '../hooks/useWorkspaces';
|
||||||
import { useZoom } from '../hooks/useZoom';
|
import { useZoom } from '../hooks/useZoom';
|
||||||
import { extractKeyValue } from '../lib/keyValueStore';
|
import { extractKeyValue } from '../lib/keyValueStore';
|
||||||
import { modelsEq } from '../lib/models';
|
import { modelsEq } from '../lib/model_util';
|
||||||
import { catppuccinMacchiato } from '../lib/theme/themes/catppuccin';
|
import { catppuccinMacchiato } from '../lib/theme/themes/catppuccin';
|
||||||
import { githubLight } from '../lib/theme/themes/github';
|
import { githubLight } from '../lib/theme/themes/github';
|
||||||
import { hotdogStandDefault } from '../lib/theme/themes/hotdog-stand';
|
import { hotdogStandDefault } from '../lib/theme/themes/hotdog-stand';
|
||||||
@@ -79,16 +79,16 @@ export function GlobalHooks() {
|
|||||||
model.model === 'http_response'
|
model.model === 'http_response'
|
||||||
? httpResponsesQueryKey(model)
|
? httpResponsesQueryKey(model)
|
||||||
: model.model === 'folder'
|
: model.model === 'folder'
|
||||||
? foldersQueryKey(model)
|
? foldersQueryKey(model)
|
||||||
: model.model === 'grpc_connection'
|
: model.model === 'grpc_connection'
|
||||||
? grpcConnectionsQueryKey(model)
|
? grpcConnectionsQueryKey(model)
|
||||||
: model.model === 'grpc_event'
|
: model.model === 'grpc_event'
|
||||||
? grpcEventsQueryKey(model)
|
? grpcEventsQueryKey(model)
|
||||||
: model.model === 'key_value'
|
: model.model === 'key_value'
|
||||||
? keyValueQueryKey(model)
|
? keyValueQueryKey(model)
|
||||||
: model.model === 'cookie_jar'
|
: model.model === 'cookie_jar'
|
||||||
? cookieJarsQueryKey(model)
|
? cookieJarsQueryKey(model)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (model.model === 'http_request' && windowLabel !== getCurrentWebviewWindow().label) {
|
if (model.model === 'http_request' && windowLabel !== getCurrentWebviewWindow().label) {
|
||||||
wasUpdatedExternally(model.id);
|
wasUpdatedExternally(model.id);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useGrpcEvents } from '../hooks/useGrpcEvents';
|
|||||||
import { usePinnedGrpcConnection } from '../hooks/usePinnedGrpcConnection';
|
import { usePinnedGrpcConnection } from '../hooks/usePinnedGrpcConnection';
|
||||||
import { useStateWithDeps } from '../hooks/useStateWithDeps';
|
import { useStateWithDeps } from '../hooks/useStateWithDeps';
|
||||||
import type { GrpcEvent, GrpcRequest } from '@yaakapp/api';
|
import type { GrpcEvent, GrpcRequest } from '@yaakapp/api';
|
||||||
import { isResponseLoading } from '../lib/models';
|
import { isResponseLoading } from '../lib/model_util';
|
||||||
import { Banner } from './core/Banner';
|
import { Banner } from './core/Banner';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
@@ -197,34 +197,34 @@ function EventRow({
|
|||||||
eventType === 'server_message'
|
eventType === 'server_message'
|
||||||
? 'text-info'
|
? 'text-info'
|
||||||
: eventType === 'client_message'
|
: eventType === 'client_message'
|
||||||
? 'text-primary'
|
? 'text-primary'
|
||||||
: eventType === 'error' || (status != null && status > 0)
|
: eventType === 'error' || (status != null && status > 0)
|
||||||
? 'text-danger'
|
? 'text-danger'
|
||||||
: eventType === 'connection_end'
|
: eventType === 'connection_end'
|
||||||
? 'text-success'
|
? 'text-success'
|
||||||
: 'text-text-subtle'
|
: 'text-text-subtle'
|
||||||
}
|
}
|
||||||
title={
|
title={
|
||||||
eventType === 'server_message'
|
eventType === 'server_message'
|
||||||
? 'Server message'
|
? 'Server message'
|
||||||
: eventType === 'client_message'
|
: eventType === 'client_message'
|
||||||
? 'Client message'
|
? 'Client message'
|
||||||
: eventType === 'error' || (status != null && status > 0)
|
: eventType === 'error' || (status != null && status > 0)
|
||||||
? 'Error'
|
? 'Error'
|
||||||
: eventType === 'connection_end'
|
: eventType === 'connection_end'
|
||||||
? 'Connection response'
|
? 'Connection response'
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
icon={
|
icon={
|
||||||
eventType === 'server_message'
|
eventType === 'server_message'
|
||||||
? 'arrowBigDownDash'
|
? 'arrow_big_down_dash'
|
||||||
: eventType === 'client_message'
|
: eventType === 'client_message'
|
||||||
? 'arrowBigUpDash'
|
? 'arrow_big_up_dash'
|
||||||
: eventType === 'error' || (status != null && status > 0)
|
: eventType === 'error' || (status != null && status > 0)
|
||||||
? 'alert'
|
? 'alert_triangle'
|
||||||
: eventType === 'connection_end'
|
: eventType === 'connection_end'
|
||||||
? 'check'
|
? 'check'
|
||||||
: 'info'
|
: 'info'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className={classNames('w-full truncate text-xs')}>
|
<div className={classNames('w-full truncate text-xs')}>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type { ReflectResponseService } from '../hooks/useGrpc';
|
|||||||
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
||||||
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
||||||
import type { GrpcMetadataEntry, GrpcRequest } from '@yaakapp/api';
|
import type { GrpcMetadataEntry, GrpcRequest } from '@yaakapp/api';
|
||||||
import { AUTH_TYPE_BASIC, AUTH_TYPE_BEARER, AUTH_TYPE_NONE } from '../lib/models';
|
import { AUTH_TYPE_BASIC, AUTH_TYPE_BEARER, AUTH_TYPE_NONE } from '../lib/model_util';
|
||||||
import { BasicAuth } from './BasicAuth';
|
import { BasicAuth } from './BasicAuth';
|
||||||
import { BearerAuth } from './BearerAuth';
|
import { BearerAuth } from './BearerAuth';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
@@ -218,7 +218,7 @@ export function GrpcConnectionSetupPane({
|
|||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="border"
|
variant="border"
|
||||||
rightSlot={<Icon className="text-text-subtlest" size="sm" icon="chevronDown" />}
|
rightSlot={<Icon className="text-text-subtlest" size="sm" icon="chevron_down" />}
|
||||||
disabled={isStreaming || services == null}
|
disabled={isStreaming || services == null}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'font-mono text-editor min-w-[5rem] !ring-0',
|
'font-mono text-editor min-w-[5rem] !ring-0',
|
||||||
@@ -254,7 +254,7 @@ export function GrpcConnectionSetupPane({
|
|||||||
title={isStreaming ? 'Connect' : 'Send'}
|
title={isStreaming ? 'Connect' : 'Send'}
|
||||||
hotkeyAction="grpc_request.send"
|
hotkeyAction="grpc_request.send"
|
||||||
onClick={isStreaming ? handleSend : handleConnect}
|
onClick={isStreaming ? handleSend : handleConnect}
|
||||||
icon={isStreaming ? 'sendHorizontal' : 'arrowUpDown'}
|
icon={isStreaming ? 'send_horizontal' : 'arrow_up_down'}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@@ -269,8 +269,8 @@ export function GrpcConnectionSetupPane({
|
|||||||
isStreaming
|
isStreaming
|
||||||
? 'x'
|
? 'x'
|
||||||
: methodType.includes('streaming')
|
: methodType.includes('streaming')
|
||||||
? 'arrowUpDown'
|
? 'arrow_up_down'
|
||||||
: 'sendHorizontal'
|
: 'send_horizontal'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function OpenWorkspaceDialog({ hide, workspace }: Props) {
|
|||||||
<Button
|
<Button
|
||||||
className="focus"
|
className="focus"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
rightSlot={<Icon icon="externalLink" />}
|
rightSlot={<Icon icon="external_link" />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
hide();
|
hide();
|
||||||
openWorkspace.mutate({ workspaceId: workspace.id, inNewWindow: true });
|
openWorkspace.mutate({ workspaceId: workspace.id, inNewWindow: true });
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export function RecentConnectionsDropdown({
|
|||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
title="Show connection history"
|
title="Show connection history"
|
||||||
icon={activeConnection?.id === latestConnectionId ? 'chevronDown' : 'pin'}
|
icon={activeConnection?.id === latestConnectionId ? 'chevron_down' : 'pin'}
|
||||||
className="ml-auto"
|
className="ml-auto"
|
||||||
size="sm"
|
size="sm"
|
||||||
iconSize="md"
|
iconSize="md"
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export const RecentResponsesDropdown = function ResponsePane({
|
|||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
title="Show response history"
|
title="Show response history"
|
||||||
icon={activeResponse?.id === latestResponseId ? 'chevronDown' : 'pin'}
|
icon={activeResponse?.id === latestResponseId ? 'chevron_down' : 'pin'}
|
||||||
className="m-0.5"
|
className="m-0.5"
|
||||||
size="sm"
|
size="sm"
|
||||||
iconSize="md"
|
iconSize="md"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
BODY_TYPE_NONE,
|
BODY_TYPE_NONE,
|
||||||
BODY_TYPE_OTHER,
|
BODY_TYPE_OTHER,
|
||||||
BODY_TYPE_XML,
|
BODY_TYPE_XML,
|
||||||
} from '../lib/models';
|
} from '../lib/model_util';
|
||||||
import { BasicAuth } from './BasicAuth';
|
import { BasicAuth } from './BasicAuth';
|
||||||
import { BearerAuth } from './BearerAuth';
|
import { BearerAuth } from './BearerAuth';
|
||||||
import { BinaryFileEditor } from './BinaryFileEditor';
|
import { BinaryFileEditor } from './BinaryFileEditor';
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export function ResponseInfo({ response }: Props) {
|
|||||||
<IconButton
|
<IconButton
|
||||||
iconSize="sm"
|
iconSize="sm"
|
||||||
className="inline-block w-auto ml-1 !h-auto opacity-50 hover:opacity-100"
|
className="inline-block w-auto ml-1 !h-auto opacity-50 hover:opacity-100"
|
||||||
icon="externalLink"
|
icon="external_link"
|
||||||
onClick={() => open(response.url)}
|
onClick={() => open(response.url)}
|
||||||
title="Open in browser"
|
title="Open in browser"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { createGlobalState } from 'react-use';
|
|||||||
import { useContentTypeFromHeaders } from '../hooks/useContentTypeFromHeaders';
|
import { useContentTypeFromHeaders } from '../hooks/useContentTypeFromHeaders';
|
||||||
import { usePinnedHttpResponse } from '../hooks/usePinnedHttpResponse';
|
import { usePinnedHttpResponse } from '../hooks/usePinnedHttpResponse';
|
||||||
import { useResponseViewMode } from '../hooks/useResponseViewMode';
|
import { useResponseViewMode } from '../hooks/useResponseViewMode';
|
||||||
import { isResponseLoading } from '../lib/models';
|
import { isResponseLoading } from '../lib/model_util';
|
||||||
import { Banner } from './core/Banner';
|
import { Banner } from './core/Banner';
|
||||||
import { CountBadge } from './core/CountBadge';
|
import { CountBadge } from './core/CountBadge';
|
||||||
import { DurationTag } from './core/DurationTag';
|
import { DurationTag } from './core/DurationTag';
|
||||||
|
|||||||
@@ -38,18 +38,18 @@ const icons: IconProps['icon'][] = [
|
|||||||
'info',
|
'info',
|
||||||
'box',
|
'box',
|
||||||
'update',
|
'update',
|
||||||
'alert',
|
'alert_triangle',
|
||||||
'arrowBigRightDash',
|
'arrow_big_right_dash',
|
||||||
'download',
|
'download',
|
||||||
'copy',
|
'copy',
|
||||||
'magicWand',
|
'magic_wand',
|
||||||
'settings',
|
'settings',
|
||||||
'trash',
|
'trash',
|
||||||
'sparkles',
|
'sparkles',
|
||||||
'pencil',
|
'pencil',
|
||||||
'paste',
|
'paste',
|
||||||
'search',
|
'search',
|
||||||
'sendHorizontal',
|
'send_horizontal',
|
||||||
];
|
];
|
||||||
|
|
||||||
export function SettingsAppearance() {
|
export function SettingsAppearance() {
|
||||||
|
|||||||
@@ -31,18 +31,18 @@ const icons: IconProps['icon'][] = [
|
|||||||
'info',
|
'info',
|
||||||
'box',
|
'box',
|
||||||
'update',
|
'update',
|
||||||
'alert',
|
'alert_triangle',
|
||||||
'arrowBigRightDash',
|
'arrow_big_right_dash',
|
||||||
'download',
|
'download',
|
||||||
'copy',
|
'copy',
|
||||||
'magicWand',
|
'magic_wand',
|
||||||
'settings',
|
'settings',
|
||||||
'trash',
|
'trash',
|
||||||
'sparkles',
|
'sparkles',
|
||||||
'pencil',
|
'pencil',
|
||||||
'paste',
|
'paste',
|
||||||
'search',
|
'search',
|
||||||
'sendHorizontal',
|
'send_horizontal',
|
||||||
];
|
];
|
||||||
|
|
||||||
export function SettingsDesign() {
|
export function SettingsDesign() {
|
||||||
|
|||||||
@@ -64,13 +64,13 @@ export function SettingsDropdown() {
|
|||||||
{
|
{
|
||||||
key: 'import-data',
|
key: 'import-data',
|
||||||
label: 'Import Data',
|
label: 'Import Data',
|
||||||
leftSlot: <Icon icon="folderInput" />,
|
leftSlot: <Icon icon="folder_input" />,
|
||||||
onSelect: () => importData.mutate(),
|
onSelect: () => importData.mutate(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'export-data',
|
key: 'export-data',
|
||||||
label: 'Export Data',
|
label: 'Export Data',
|
||||||
leftSlot: <Icon icon="folderOutput" />,
|
leftSlot: <Icon icon="folder_output" />,
|
||||||
onSelect: () => exportData.mutate(),
|
onSelect: () => exportData.mutate(),
|
||||||
},
|
},
|
||||||
{ type: 'separator', label: `Yaak v${appInfo.version}` },
|
{ type: 'separator', label: `Yaak v${appInfo.version}` },
|
||||||
@@ -84,14 +84,14 @@ export function SettingsDropdown() {
|
|||||||
key: 'feedback',
|
key: 'feedback',
|
||||||
label: 'Feedback',
|
label: 'Feedback',
|
||||||
leftSlot: <Icon icon="chat" />,
|
leftSlot: <Icon icon="chat" />,
|
||||||
rightSlot: <Icon icon="externalLink" />,
|
rightSlot: <Icon icon="external_link" />,
|
||||||
onSelect: () => open('https://yaak.app/roadmap'),
|
onSelect: () => open('https://yaak.app/roadmap'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'changelog',
|
key: 'changelog',
|
||||||
label: 'Changelog',
|
label: 'Changelog',
|
||||||
leftSlot: <Icon icon="cake" />,
|
leftSlot: <Icon icon="cake" />,
|
||||||
rightSlot: <Icon icon="externalLink" />,
|
rightSlot: <Icon icon="external_link" />,
|
||||||
onSelect: () => open(`https://yaak.app/changelog/${appInfo.version}`),
|
onSelect: () => open(`https://yaak.app/changelog/${appInfo.version}`),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
|||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { isResponseLoading } from '../lib/models';
|
import { isResponseLoading } from '../lib/model_util';
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
import type { DropdownItem } from './core/Dropdown';
|
import type { DropdownItem } from './core/Dropdown';
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
@@ -433,32 +433,31 @@ export function Sidebar({ className }: Props) {
|
|||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
tabIndex={hidden ? -1 : 0}
|
tabIndex={hidden ? -1 : 0}
|
||||||
onContextMenu={handleMainContextMenu}
|
onContextMenu={handleMainContextMenu}
|
||||||
className={classNames(
|
className={classNames(className, 'h-full grid grid-rows-[minmax(0,1fr)_auto]')}
|
||||||
className,
|
|
||||||
'h-full pb-3 overflow-y-scroll overflow-x-visible hide-scrollbars pt-2',
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<ContextMenu
|
<div className="pb-3 overflow-x-visible overflow-y-scroll pt-2">
|
||||||
triggerPosition={showMainContextMenu}
|
<ContextMenu
|
||||||
items={mainContextMenuItems}
|
triggerPosition={showMainContextMenu}
|
||||||
onClose={() => setShowMainContextMenu(null)}
|
items={mainContextMenuItems}
|
||||||
/>
|
onClose={() => setShowMainContextMenu(null)}
|
||||||
<SidebarItems
|
/>
|
||||||
treeParentMap={treeParentMap}
|
<SidebarItems
|
||||||
activeId={activeRequest?.id ?? null}
|
treeParentMap={treeParentMap}
|
||||||
selectedId={selectedId}
|
activeId={activeRequest?.id ?? null}
|
||||||
selectedTree={selectedTree}
|
selectedId={selectedId}
|
||||||
isCollapsed={isCollapsed}
|
selectedTree={selectedTree}
|
||||||
tree={tree}
|
isCollapsed={isCollapsed}
|
||||||
focused={hasFocus}
|
tree={tree}
|
||||||
draggingId={draggingId}
|
focused={hasFocus}
|
||||||
onSelect={handleSelect}
|
draggingId={draggingId}
|
||||||
hoveredIndex={hoveredIndex}
|
onSelect={handleSelect}
|
||||||
hoveredTree={hoveredTree}
|
hoveredIndex={hoveredIndex}
|
||||||
handleMove={handleMove}
|
hoveredTree={hoveredTree}
|
||||||
handleEnd={handleEnd}
|
handleMove={handleMove}
|
||||||
handleDragStart={handleDragStart}
|
handleEnd={handleEnd}
|
||||||
/>
|
handleDragStart={handleDragStart}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -741,7 +740,7 @@ function SidebarItem({
|
|||||||
{
|
{
|
||||||
key: 'sendAll',
|
key: 'sendAll',
|
||||||
label: 'Send All',
|
label: 'Send All',
|
||||||
leftSlot: <Icon icon="sendHorizontal" />,
|
leftSlot: <Icon icon="send_horizontal" />,
|
||||||
onSelect: () => sendManyRequests.mutate(child.children.map((c) => c.item.id)),
|
onSelect: () => sendManyRequests.mutate(child.children.map((c) => c.item.id)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -784,7 +783,7 @@ function SidebarItem({
|
|||||||
label: 'Send',
|
label: 'Send',
|
||||||
hotKeyAction: 'http_request.send',
|
hotKeyAction: 'http_request.send',
|
||||||
hotKeyLabelOnly: true, // Already bound in URL bar
|
hotKeyLabelOnly: true, // Already bound in URL bar
|
||||||
leftSlot: <Icon icon="sendHorizontal" />,
|
leftSlot: <Icon icon="send_horizontal" />,
|
||||||
onSelect: () => sendRequest.mutate(itemId),
|
onSelect: () => sendRequest.mutate(itemId),
|
||||||
},
|
},
|
||||||
...httpRequestActions.map((a) => ({
|
...httpRequestActions.map((a) => ({
|
||||||
@@ -822,7 +821,7 @@ function SidebarItem({
|
|||||||
{
|
{
|
||||||
key: 'moveWorkspace',
|
key: 'moveWorkspace',
|
||||||
label: 'Move',
|
label: 'Move',
|
||||||
leftSlot: <Icon icon="arrowRightCircle" />,
|
leftSlot: <Icon icon="arrow_right_circle" />,
|
||||||
hidden: workspaces.length <= 1,
|
hidden: workspaces.length <= 1,
|
||||||
onSelect: moveToWorkspace.mutate,
|
onSelect: moveToWorkspace.mutate,
|
||||||
},
|
},
|
||||||
@@ -882,7 +881,7 @@ function SidebarItem({
|
|||||||
{itemModel === 'folder' && (
|
{itemModel === 'folder' && (
|
||||||
<Icon
|
<Icon
|
||||||
size="sm"
|
size="sm"
|
||||||
icon="chevronRight"
|
icon="chevron_right"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'text-text-subtlest',
|
'text-text-subtlest',
|
||||||
'transition-transform',
|
'transition-transform',
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ export function SidebarActions() {
|
|||||||
className="pointer-events-auto"
|
className="pointer-events-auto"
|
||||||
size="sm"
|
size="sm"
|
||||||
title="Show sidebar"
|
title="Show sidebar"
|
||||||
icon={hidden ? 'leftPanelHidden' : 'leftPanelVisible'}
|
icon={hidden ? 'left_panel_hidden' : 'left_panel_visible'}
|
||||||
/>
|
/>
|
||||||
<CreateDropdown hotKeyAction="http_request.create">
|
<CreateDropdown hotKeyAction="http_request.create">
|
||||||
<IconButton size="sm" icon="plusCircle" title="Add Resource" />
|
<IconButton size="sm" icon="plus_circle" title="Add Resource" />
|
||||||
</CreateDropdown>
|
</CreateDropdown>
|
||||||
</HStack>
|
</HStack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import React, { createContext, useContext, useMemo, useRef, useState } from 'react';
|
import React, { createContext, useContext, useMemo, useRef, useState } from 'react';
|
||||||
import type { ShowToastRequest } from '../../plugin-runtime-types/src';
|
import type { ShowToastRequest } from '@yaakapp/api';
|
||||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||||
|
import { generateId } from '../lib/generateId';
|
||||||
import type { ToastProps } from './core/Toast';
|
import type { ToastProps } from './core/Toast';
|
||||||
import { Toast } from './core/Toast';
|
import { Toast } from './core/Toast';
|
||||||
import { generateId } from '../lib/generateId';
|
|
||||||
import { Portal } from './Portal';
|
import { Portal } from './Portal';
|
||||||
import { AnimatePresence } from 'framer-motion';
|
|
||||||
|
|
||||||
type ToastEntry = {
|
type ToastEntry = {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -93,7 +93,7 @@ export const Toasts = () => {
|
|||||||
const { toasts } = useContext(ToastContext);
|
const { toasts } = useContext(ToastContext);
|
||||||
return (
|
return (
|
||||||
<Portal name="toasts">
|
<Portal name="toasts">
|
||||||
<div className="absolute right-0 bottom-0 z-10">
|
<div className="absolute right-0 bottom-0 z-20">
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{toasts.map((props: PrivateToastEntry) => (
|
{toasts.map((props: PrivateToastEntry) => (
|
||||||
<ToastInstance key={props.id} {...props} />
|
<ToastInstance key={props.id} {...props} />
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const UrlBar = memo(function UrlBar({
|
|||||||
onCancel,
|
onCancel,
|
||||||
onMethodChange,
|
onMethodChange,
|
||||||
onPaste,
|
onPaste,
|
||||||
submitIcon = 'sendHorizontal',
|
submitIcon = 'send_horizontal',
|
||||||
autocomplete,
|
autocomplete,
|
||||||
rightSlot,
|
rightSlot,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
|
|||||||
<CookieDropdown />
|
<CookieDropdown />
|
||||||
<HStack>
|
<HStack>
|
||||||
<WorkspaceActionsDropdown />
|
<WorkspaceActionsDropdown />
|
||||||
<Icon icon="chevronRight" className="text-text-subtle" />
|
<Icon icon="chevron_right" className="text-text-subtle" />
|
||||||
<EnvironmentActionsDropdown className="w-auto pointer-events-auto" />
|
<EnvironmentActionsDropdown className="w-auto pointer-events-auto" />
|
||||||
</HStack>
|
</HStack>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function Banner({ children, className, color = 'secondary' }: Props) {
|
|||||||
className={classNames(
|
className={classNames(
|
||||||
className,
|
className,
|
||||||
`x-theme-banner--${color}`,
|
`x-theme-banner--${color}`,
|
||||||
'border border-dashed border-border-subtle bg-surface-highlight',
|
'border border-dashed border-border-subtle bg-surface',
|
||||||
'italic px-3 py-2 rounded select-auto cursor-text',
|
'italic px-3 py-2 rounded select-auto cursor-text',
|
||||||
'overflow-x-auto text-text',
|
'overflow-x-auto text-text',
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -108,6 +108,11 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
|
|||||||
className={classes}
|
className={classes}
|
||||||
disabled={disabled || isLoading}
|
disabled={disabled || isLoading}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
onDoubleClick={(e) => {
|
||||||
|
// Kind of a hack? This prevents double-clicks from going through buttons. For example, when
|
||||||
|
// double-clicking the workspace header to toggle window maximization
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
title={fullTitle}
|
title={fullTitle}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -126,7 +131,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
|
|||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
{rightSlot && <div className="ml-1">{rightSlot}</div>}
|
{rightSlot && <div className="ml-1">{rightSlot}</div>}
|
||||||
{forDropdown && <Icon icon="chevronDown" size={size} className="ml-1 -mr-1" />}
|
{forDropdown && <Icon icon="chevron_down" size={size} className="ml-1 -mr-1" />}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ export const ContextMenu = forwardRef<DropdownRef, ContextMenuProps>(function Co
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu
|
<Menu
|
||||||
isOpen // Always open because we return null if not
|
isOpen={true} // Always open because we return null if not
|
||||||
className={className}
|
className={className}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
items={items}
|
items={items}
|
||||||
@@ -361,29 +361,38 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
}>(() => {
|
}>(() => {
|
||||||
if (triggerShape == null) return { containerStyles: {}, triangleStyles: null };
|
if (triggerShape == null) return { containerStyles: {}, triangleStyles: null };
|
||||||
|
|
||||||
|
const menuMarginY = 5;
|
||||||
const docRect = document.documentElement.getBoundingClientRect();
|
const docRect = document.documentElement.getBoundingClientRect();
|
||||||
const width = triggerShape.right - triggerShape.left;
|
const width = triggerShape.right - triggerShape.left;
|
||||||
const heightAbove = triggerShape.top;
|
const heightAbove = triggerShape.top;
|
||||||
const heightBelow = docRect.height - triggerShape.bottom;
|
const heightBelow = docRect.height - triggerShape.bottom;
|
||||||
const hSpaceRemaining = docRect.width - triggerShape.left;
|
const horizontalSpaceRemaining = docRect.width - triggerShape.left;
|
||||||
const top = triggerShape.bottom + 5;
|
const top = triggerShape.bottom;
|
||||||
const onRight = hSpaceRemaining < 200;
|
const onRight = horizontalSpaceRemaining < 200;
|
||||||
const upsideDown = heightAbove > heightBelow && heightBelow < 200;
|
const upsideDown = heightBelow < heightAbove && heightBelow < items.length * 25 + 20 + 200;
|
||||||
const triggerWidth = triggerShape.right - triggerShape.left;
|
const triggerWidth = triggerShape.right - triggerShape.left;
|
||||||
const containerStyles = {
|
const containerStyles = {
|
||||||
top: !upsideDown ? top : undefined,
|
top: !upsideDown ? top + menuMarginY : undefined,
|
||||||
bottom: upsideDown ? docRect.height - top : undefined,
|
bottom: upsideDown
|
||||||
|
? docRect.height - top - (triggerShape.top - triggerShape.bottom) + menuMarginY
|
||||||
|
: undefined,
|
||||||
right: onRight ? docRect.width - triggerShape.right : undefined,
|
right: onRight ? docRect.width - triggerShape.right : undefined,
|
||||||
left: !onRight ? triggerShape.left : undefined,
|
left: !onRight ? triggerShape.left : undefined,
|
||||||
minWidth: fullWidth ? triggerWidth : undefined,
|
minWidth: fullWidth ? triggerWidth : undefined,
|
||||||
maxWidth: '40rem',
|
maxWidth: '40rem',
|
||||||
};
|
};
|
||||||
const size = { top: '-0.2rem', width: '0.4rem', height: '0.4rem' };
|
const triangleStyles: CSSProperties = {
|
||||||
const triangleStyles = onRight
|
width: '0.4rem',
|
||||||
? { right: width / 2, marginRight: '-0.2rem', ...size }
|
height: '0.4rem',
|
||||||
: { left: width / 2, marginLeft: '-0.2rem', ...size };
|
...(onRight
|
||||||
|
? { right: width / 2, marginRight: '-0.2rem' }
|
||||||
|
: { left: width / 2, marginLeft: '-0.2rem' }),
|
||||||
|
...(upsideDown
|
||||||
|
? { bottom: '-0.2rem', rotate: '225deg' }
|
||||||
|
: { top: '-0.2rem', rotate: '45deg' }),
|
||||||
|
};
|
||||||
return { containerStyles, triangleStyles };
|
return { containerStyles, triangleStyles };
|
||||||
}, [fullWidth, triggerShape]);
|
}, [fullWidth, items.length, triggerShape]);
|
||||||
|
|
||||||
const filteredItems = useMemo(
|
const filteredItems = useMemo(
|
||||||
() => items.filter((i) => getNodeText(i.label).toLowerCase().includes(filter.toLowerCase())),
|
() => items.filter((i) => getNodeText(i.label).toLowerCase().includes(filter.toLowerCase())),
|
||||||
@@ -415,7 +424,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<Overlay open variant="transparent" portalName="dropdown" zIndex={50}>
|
<Overlay open={true} variant="transparent" portalName="dropdown" zIndex={50}>
|
||||||
<div className="x-theme-menu">
|
<div className="x-theme-menu">
|
||||||
<div tabIndex={-1} aria-hidden className="fixed inset-0 z-30" onClick={handleClose} />
|
<div tabIndex={-1} aria-hidden className="fixed inset-0 z-30" onClick={handleClose} />
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -433,7 +442,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
<span
|
<span
|
||||||
aria-hidden
|
aria-hidden
|
||||||
style={triangleStyles}
|
style={triangleStyles}
|
||||||
className="bg-surface absolute rotate-45 border-border-subtle border-t border-l"
|
className="bg-surface absolute border-border-subtle border-t border-l"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{containerStyles && (
|
{containerStyles && (
|
||||||
@@ -443,7 +452,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
|||||||
className={classNames(
|
className={classNames(
|
||||||
className,
|
className,
|
||||||
'h-auto bg-surface rounded-md shadow-lg py-1.5 border',
|
'h-auto bg-surface rounded-md shadow-lg py-1.5 border',
|
||||||
'border-border-subtle overflow-auto mb-1 mx-0.5',
|
'border-border-subtle overflow-auto mx-0.5',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{filter && (
|
{filter && (
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
|||||||
key="format"
|
key="format"
|
||||||
size="sm"
|
size="sm"
|
||||||
title="Reformat contents"
|
title="Reformat contents"
|
||||||
icon="magicWand"
|
icon="magic_wand"
|
||||||
variant="border"
|
variant="border"
|
||||||
className={classNames(actionClassName)}
|
className={classNames(actionClassName)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -4,62 +4,69 @@ import type { HTMLAttributes } from 'react';
|
|||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
alert: lucide.AlertTriangleIcon,
|
alert_triangle: lucide.AlertTriangleIcon,
|
||||||
archive: lucide.ArchiveIcon,
|
archive: lucide.ArchiveIcon,
|
||||||
arrowBigDownDash: lucide.ArrowBigDownDashIcon,
|
arrow_big_down_dash: lucide.ArrowBigDownDashIcon,
|
||||||
arrowRightCircle: lucide.ArrowRightCircleIcon,
|
arrow_right_circle: lucide.ArrowRightCircleIcon,
|
||||||
arrowBigLeftDash: lucide.ArrowBigLeftDashIcon,
|
arrow_big_left_dash: lucide.ArrowBigLeftDashIcon,
|
||||||
arrowBigRight: lucide.ArrowBigRightIcon,
|
arrow_big_right: lucide.ArrowBigRightIcon,
|
||||||
arrowBigRightDash: lucide.ArrowBigRightDashIcon,
|
arrow_big_right_dash: lucide.ArrowBigRightDashIcon,
|
||||||
arrowBigUpDash: lucide.ArrowBigUpDashIcon,
|
arrow_big_up_dash: lucide.ArrowBigUpDashIcon,
|
||||||
arrowDown: lucide.ArrowDownIcon,
|
arrow_down: lucide.ArrowDownIcon,
|
||||||
arrowDownToDot: lucide.ArrowDownToDotIcon,
|
arrow_down_to_dot: lucide.ArrowDownToDotIcon,
|
||||||
arrowUp: lucide.ArrowUpIcon,
|
arrow_up: lucide.ArrowUpIcon,
|
||||||
arrowUpDown: lucide.ArrowUpDownIcon,
|
arrow_up_down: lucide.ArrowUpDownIcon,
|
||||||
arrowUpFromDot: lucide.ArrowUpFromDotIcon,
|
arrow_up_from_dot: lucide.ArrowUpFromDotIcon,
|
||||||
|
badge_check: lucide.BadgeCheckIcon,
|
||||||
box: lucide.BoxIcon,
|
box: lucide.BoxIcon,
|
||||||
cake: lucide.CakeIcon,
|
cake: lucide.CakeIcon,
|
||||||
chat: lucide.MessageSquare,
|
chat: lucide.MessageSquare,
|
||||||
check: lucide.CheckIcon,
|
check: lucide.CheckIcon,
|
||||||
checkCircle: lucide.CheckCircleIcon,
|
check_circle: lucide.CheckCircleIcon,
|
||||||
chevronDown: lucide.ChevronDownIcon,
|
chevron_down: lucide.ChevronDownIcon,
|
||||||
chevronRight: lucide.ChevronRightIcon,
|
chevron_right: lucide.ChevronRightIcon,
|
||||||
|
circle_alert: lucide.CircleAlertIcon,
|
||||||
|
cloud: lucide.CloudIcon,
|
||||||
code: lucide.CodeIcon,
|
code: lucide.CodeIcon,
|
||||||
cookie: lucide.CookieIcon,
|
cookie: lucide.CookieIcon,
|
||||||
copy: lucide.CopyIcon,
|
copy: lucide.CopyIcon,
|
||||||
copyCheck: lucide.CopyCheck,
|
copy_check: lucide.CopyCheck,
|
||||||
download: lucide.DownloadIcon,
|
download: lucide.DownloadIcon,
|
||||||
externalLink: lucide.ExternalLinkIcon,
|
external_link: lucide.ExternalLinkIcon,
|
||||||
eye: lucide.EyeIcon,
|
eye: lucide.EyeIcon,
|
||||||
eyeClosed: lucide.EyeOffIcon,
|
eye_closed: lucide.EyeOffIcon,
|
||||||
fileCode: lucide.FileCodeIcon,
|
file_code: lucide.FileCodeIcon,
|
||||||
filter: lucide.FilterIcon,
|
filter: lucide.FilterIcon,
|
||||||
flask: lucide.FlaskConicalIcon,
|
flask: lucide.FlaskConicalIcon,
|
||||||
folderInput: lucide.FolderInputIcon,
|
folder_input: lucide.FolderInputIcon,
|
||||||
folderOutput: lucide.FolderOutputIcon,
|
folder_output: lucide.FolderOutputIcon,
|
||||||
gripVertical: lucide.GripVerticalIcon,
|
git_branch: lucide.GitBranchIcon,
|
||||||
|
git_commit: lucide.GitCommitIcon,
|
||||||
|
git_commit_vertical: lucide.GitCommitVerticalIcon,
|
||||||
|
git_pull_request: lucide.GitPullRequestIcon,
|
||||||
|
git_fork: lucide.GitForkIcon,
|
||||||
|
grip_vertical: lucide.GripVerticalIcon,
|
||||||
hand: lucide.HandIcon,
|
hand: lucide.HandIcon,
|
||||||
help: lucide.CircleHelpIcon,
|
help: lucide.CircleHelpIcon,
|
||||||
house: lucide.HomeIcon,
|
house: lucide.HomeIcon,
|
||||||
info: lucide.InfoIcon,
|
info: lucide.InfoIcon,
|
||||||
keyboard: lucide.KeyboardIcon,
|
keyboard: lucide.KeyboardIcon,
|
||||||
leftPanelHidden: lucide.PanelLeftOpenIcon,
|
left_panel_hidden: lucide.PanelLeftOpenIcon,
|
||||||
leftPanelVisible: lucide.PanelLeftCloseIcon,
|
left_panel_visible: lucide.PanelLeftCloseIcon,
|
||||||
magicWand: lucide.Wand2Icon,
|
magic_wand: lucide.Wand2Icon,
|
||||||
minus: lucide.MinusIcon,
|
minus: lucide.MinusIcon,
|
||||||
moon: lucide.MoonIcon,
|
moon: lucide.MoonIcon,
|
||||||
moreVertical: lucide.MoreVerticalIcon,
|
more_vertical: lucide.MoreVerticalIcon,
|
||||||
paste: lucide.ClipboardPasteIcon,
|
paste: lucide.ClipboardPasteIcon,
|
||||||
pencil: lucide.PencilIcon,
|
pencil: lucide.PencilIcon,
|
||||||
pin: lucide.PinIcon,
|
pin: lucide.PinIcon,
|
||||||
plug: lucide.Plug,
|
plug: lucide.Plug,
|
||||||
plus: lucide.PlusIcon,
|
plus: lucide.PlusIcon,
|
||||||
plusCircle: lucide.PlusCircleIcon,
|
plus_circle: lucide.PlusCircleIcon,
|
||||||
refresh: lucide.RefreshCwIcon,
|
refresh: lucide.RefreshCwIcon,
|
||||||
save: lucide.SaveIcon,
|
save: lucide.SaveIcon,
|
||||||
search: lucide.SearchIcon,
|
search: lucide.SearchIcon,
|
||||||
sendHorizontal: lucide.SendHorizonalIcon,
|
send_horizontal: lucide.SendHorizonalIcon,
|
||||||
settings2: lucide.Settings2Icon,
|
|
||||||
settings: lucide.SettingsIcon,
|
settings: lucide.SettingsIcon,
|
||||||
sparkles: lucide.SparklesIcon,
|
sparkles: lucide.SparklesIcon,
|
||||||
sun: lucide.SunIcon,
|
sun: lucide.SunIcon,
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
|
|||||||
className="mr-0.5 group/obscure !h-auto my-0.5"
|
className="mr-0.5 group/obscure !h-auto my-0.5"
|
||||||
iconClassName="text-text-subtle group-hover/obscure:text"
|
iconClassName="text-text-subtle group-hover/obscure:text"
|
||||||
iconSize="sm"
|
iconSize="sm"
|
||||||
icon={obscured ? 'eye' : 'eyeClosed'}
|
icon={obscured ? 'eye' : 'eye_closed'}
|
||||||
onClick={() => setObscured((o) => !o)}
|
onClick={() => setObscured((o) => !o)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export const JsonAttributeTree = ({
|
|||||||
<button className="group relative flex items-center pl-4 w-full" onClick={toggleExpanded}>
|
<button className="group relative flex items-center pl-4 w-full" onClick={toggleExpanded}>
|
||||||
<Icon
|
<Icon
|
||||||
size="xs"
|
size="xs"
|
||||||
icon="chevronRight"
|
icon="chevron_right"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'left-0 absolute transition-transform flex items-center',
|
'left-0 absolute transition-transform flex items-center',
|
||||||
'text-text-subtlest group-hover:text-text-subtle',
|
'text-text-subtlest group-hover:text-text-subtle',
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export function Link({ href, children, className, ...other }: Props) {
|
|||||||
{...other}
|
{...other}
|
||||||
>
|
>
|
||||||
<span className="underline">{children}</span>
|
<span className="underline">{children}</span>
|
||||||
<Icon className="inline absolute right-0.5 top-0.5" size="xs" icon="externalLink" />
|
<Icon className="inline absolute right-0.5 top-0.5" size="xs" icon="external_link" />
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ function PairEditorRow({
|
|||||||
'justify-center opacity-0 group-hover:opacity-70',
|
'justify-center opacity-0 group-hover:opacity-70',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Icon size="sm" icon="gripVertical" className="pointer-events-none" />
|
<Icon size="sm" icon="grip_vertical" className="pointer-events-none" />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span className="w-3" />
|
<span className="w-3" />
|
||||||
@@ -545,7 +545,7 @@ function PairEditorRow({
|
|||||||
<IconButton
|
<IconButton
|
||||||
iconSize="sm"
|
iconSize="sm"
|
||||||
size="xs"
|
size="xs"
|
||||||
icon={isLast ? 'empty' : 'chevronDown'}
|
icon={isLast ? 'empty' : 'chevron_down'}
|
||||||
title="Select form data type"
|
title="Select form data type"
|
||||||
/>
|
/>
|
||||||
</RadioDropdown>
|
</RadioDropdown>
|
||||||
@@ -563,7 +563,7 @@ function PairEditorRow({
|
|||||||
<IconButton
|
<IconButton
|
||||||
iconSize="sm"
|
iconSize="sm"
|
||||||
size="xs"
|
size="xs"
|
||||||
icon={isLast ? 'empty' : 'chevronDown'}
|
icon={isLast ? 'empty' : 'chevron_down'}
|
||||||
title="Select form data type"
|
title="Select form data type"
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export const PairOrBulkEditor = forwardRef<PairEditorRef, Props>(function PairOr
|
|||||||
'bg-surface text-text-subtle hover:text group-hover/wrapper:opacity-100',
|
'bg-surface text-text-subtle hover:text group-hover/wrapper:opacity-100',
|
||||||
)}
|
)}
|
||||||
onClick={() => setUseBulk((b) => !b)}
|
onClick={() => setUseBulk((b) => !b)}
|
||||||
icon={useBulk ? 'table' : 'fileCode'}
|
icon={useBulk ? 'table' : 'file_code'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function
|
|||||||
className="mr-0.5 group/obscure !h-auto my-0.5"
|
className="mr-0.5 group/obscure !h-auto my-0.5"
|
||||||
iconClassName="text-text-subtle group-hover/obscure:text"
|
iconClassName="text-text-subtle group-hover/obscure:text"
|
||||||
iconSize="sm"
|
iconSize="sm"
|
||||||
icon={obscured ? 'eye' : 'eyeClosed'}
|
icon={obscured ? 'eye' : 'eye_closed'}
|
||||||
onClick={() => setObscured((o) => !o)}
|
onClick={() => setObscured((o) => !o)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -100,10 +100,10 @@ export function Tabs({
|
|||||||
>
|
>
|
||||||
{option && 'shortLabel' in option
|
{option && 'shortLabel' in option
|
||||||
? option.shortLabel
|
? option.shortLabel
|
||||||
: option?.label ?? 'Unknown'}
|
: (option?.label ?? 'Unknown')}
|
||||||
<Icon
|
<Icon
|
||||||
size="sm"
|
size="sm"
|
||||||
icon="chevronDown"
|
icon="chevron_down"
|
||||||
className={classNames('ml-1', isActive ? 'text-text-subtle' : 'opacity-50')}
|
className={classNames('ml-1', isActive ? 'text-text-subtle' : 'opacity-50')}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { ShowToastRequest } from '@yaakapp/api';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
@@ -15,27 +16,23 @@ export interface ToastProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
timeout: number | null;
|
timeout: number | null;
|
||||||
action?: ReactNode;
|
action?: ReactNode;
|
||||||
variant?: 'custom' | 'copied' | 'success' | 'info' | 'warning' | 'error';
|
icon?: ShowToastRequest['icon'];
|
||||||
|
color?: ShowToastRequest['color'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ICONS: Record<NonNullable<ToastProps['variant']>, IconProps['icon'] | null> = {
|
const ICONS: Record<NonNullable<ToastProps['color']>, IconProps['icon'] | null> = {
|
||||||
custom: null,
|
custom: null,
|
||||||
copied: 'copyCheck',
|
default: 'info',
|
||||||
warning: 'alert',
|
danger: 'alert_triangle',
|
||||||
error: 'alert',
|
|
||||||
info: 'info',
|
info: 'info',
|
||||||
success: 'checkCircle',
|
notice: 'alert_triangle',
|
||||||
|
primary: 'info',
|
||||||
|
secondary: 'info',
|
||||||
|
success: 'check_circle',
|
||||||
|
warning: 'alert_triangle',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Toast({
|
export function Toast({ children, open, onClose, timeout, action, icon, color }: ToastProps) {
|
||||||
children,
|
|
||||||
className,
|
|
||||||
open,
|
|
||||||
onClose,
|
|
||||||
timeout,
|
|
||||||
action,
|
|
||||||
variant = 'info',
|
|
||||||
}: ToastProps) {
|
|
||||||
useKey(
|
useKey(
|
||||||
'Escape',
|
'Escape',
|
||||||
() => {
|
() => {
|
||||||
@@ -45,8 +42,9 @@ export function Toast({
|
|||||||
{},
|
{},
|
||||||
[open],
|
[open],
|
||||||
);
|
);
|
||||||
|
color = color ?? 'default';
|
||||||
|
|
||||||
const icon = variant in ICONS && ICONS[variant];
|
const toastIcon = icon ?? (color in ICONS && ICONS[color]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -54,55 +52,46 @@ export function Toast({
|
|||||||
animate={{ opacity: 100, right: 0 }}
|
animate={{ opacity: 100, right: 0 }}
|
||||||
exit={{ opacity: 0, right: '-100%' }}
|
exit={{ opacity: 0, right: '-100%' }}
|
||||||
transition={{ duration: 0.2 }}
|
transition={{ duration: 0.2 }}
|
||||||
className={classNames(
|
className={classNames('bg-surface m-2 rounded-lg')}
|
||||||
className,
|
|
||||||
'x-theme-toast',
|
|
||||||
'pointer-events-auto',
|
|
||||||
'relative bg-surface pointer-events-auto',
|
|
||||||
'rounded-lg',
|
|
||||||
'border border-border-subtle shadow-lg',
|
|
||||||
'max-w-[calc(100vw-5rem)] max-h-[calc(100vh-6rem)]',
|
|
||||||
'w-[22rem] max-h-[80vh]',
|
|
||||||
'm-2 grid grid-cols-[1fr_auto]',
|
|
||||||
'text',
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<div className="px-3 py-3 flex items-center gap-2">
|
<div
|
||||||
{icon && (
|
className={classNames(
|
||||||
<Icon
|
`x-theme-toast x-theme-toast--${color}`,
|
||||||
icon={icon}
|
'pointer-events-auto overflow-hidden',
|
||||||
className={classNames(
|
'relative pointer-events-auto bg-surface text-text rounded-lg',
|
||||||
variant === 'success' && 'text-success',
|
'border border-border shadow-lg',
|
||||||
variant === 'warning' && 'text-warning',
|
'grid grid-cols-[1fr_auto]',
|
||||||
variant === 'error' && 'text-danger',
|
'text',
|
||||||
variant === 'copied' && 'text-primary',
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<VStack space={2}>
|
>
|
||||||
<div>{children}</div>
|
<div className="px-3 py-3 flex items-center gap-2">
|
||||||
{action}
|
{toastIcon && <Icon icon={toastIcon} className="text-text-subtle" />}
|
||||||
</VStack>
|
<VStack space={2}>
|
||||||
</div>
|
<div>{children}</div>
|
||||||
|
{action}
|
||||||
<IconButton
|
</VStack>
|
||||||
color="custom"
|
|
||||||
className="opacity-60"
|
|
||||||
title="Dismiss"
|
|
||||||
icon="x"
|
|
||||||
onClick={onClose}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{timeout != null && (
|
|
||||||
<div className="w-full absolute bottom-0 left-0 right-0">
|
|
||||||
<motion.div
|
|
||||||
className="bg-surface-highlight h-0.5"
|
|
||||||
initial={{ width: '100%' }}
|
|
||||||
animate={{ width: '0%', opacity: 0.2 }}
|
|
||||||
transition={{ duration: timeout / 1000, ease: 'linear' }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
<IconButton
|
||||||
|
color={color}
|
||||||
|
variant="border"
|
||||||
|
className="opacity-60 border-0"
|
||||||
|
title="Dismiss"
|
||||||
|
icon="x"
|
||||||
|
onClick={onClose}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{timeout != null && (
|
||||||
|
<div className="w-full absolute bottom-0 left-0 right-0">
|
||||||
|
<motion.div
|
||||||
|
className="bg-surface-highlight h-[3px]"
|
||||||
|
initial={{ width: '100%' }}
|
||||||
|
animate={{ width: '0%', opacity: 0.2 }}
|
||||||
|
transition={{ duration: timeout / 1000, ease: 'linear' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useSaveResponse } from '../../hooks/useSaveResponse';
|
import { useSaveResponse } from '../../hooks/useSaveResponse';
|
||||||
import type { HttpResponse } from '@yaakapp/api';
|
import type { HttpResponse } from '@yaakapp/api';
|
||||||
import { getContentTypeHeader } from '../../lib/models';
|
import { getContentTypeHeader } from '../../lib/model_util';
|
||||||
import { Banner } from '../core/Banner';
|
import { Banner } from '../core/Banner';
|
||||||
import { Button } from '../core/Button';
|
import { Button } from '../core/Button';
|
||||||
import { InlineCode } from '../core/InlineCode';
|
import { InlineCode } from '../core/InlineCode';
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ export function useCopy({ disableToast }: { disableToast?: boolean } = {}) {
|
|||||||
if (text != '' && !disableToast) {
|
if (text != '' && !disableToast) {
|
||||||
toast.show({
|
toast.show({
|
||||||
id: 'copied',
|
id: 'copied',
|
||||||
variant: 'copied',
|
color: 'secondary',
|
||||||
|
icon: 'copy',
|
||||||
message: 'Copied to clipboard',
|
message: 'Copied to clipboard',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import type { DropdownItem } from '../components/core/Dropdown';
|
import type { DropdownItem } from '../components/core/Dropdown';
|
||||||
import { Icon } from '../components/core/Icon';
|
import { Icon } from '../components/core/Icon';
|
||||||
import { BODY_TYPE_GRAPHQL } from '../lib/models';
|
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
|
||||||
import { useCreateFolder } from './useCreateFolder';
|
import { useCreateFolder } from './useCreateFolder';
|
||||||
import { useCreateGrpcRequest } from './useCreateGrpcRequest';
|
import { useCreateGrpcRequest } from './useCreateGrpcRequest';
|
||||||
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export function useExportData() {
|
|||||||
activeWorkspace={activeWorkspace}
|
activeWorkspace={activeWorkspace}
|
||||||
onSuccess={() => {
|
onSuccess={() => {
|
||||||
toast.show({
|
toast.show({
|
||||||
variant: 'success',
|
color: 'success',
|
||||||
message: 'Data export successful',
|
message: 'Data export successful',
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export function useImportCurl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toast.show({
|
toast.show({
|
||||||
variant: 'success',
|
color: 'success',
|
||||||
message: `${verb} request from Curl`,
|
message: `${verb} request from Curl`,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function useImportQuerystring(requestId: string) {
|
|||||||
if (additionalUrlParameters.length > 0) {
|
if (additionalUrlParameters.length > 0) {
|
||||||
toast.show({
|
toast.show({
|
||||||
id: 'querystring-imported',
|
id: 'querystring-imported',
|
||||||
variant: 'info',
|
color: 'info',
|
||||||
message: `Imported ${additionalUrlParameters.length} ${pluralize('param', additionalUrlParameters.length)} from URL`,
|
message: `Imported ${additionalUrlParameters.length} ${pluralize('param', additionalUrlParameters.length)} from URL`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { isResponseLoading } from '../lib/models';
|
import { isResponseLoading } from '../lib/model_util';
|
||||||
import { useLatestHttpResponse } from './useLatestHttpResponse';
|
import { useLatestHttpResponse } from './useLatestHttpResponse';
|
||||||
|
|
||||||
export function useIsResponseLoading(requestId: string | null): boolean {
|
export function useIsResponseLoading(requestId: string | null): boolean {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function useNotificationToast() {
|
|||||||
id: payload.id,
|
id: payload.id,
|
||||||
timeout: null,
|
timeout: null,
|
||||||
message: payload.message,
|
message: payload.message,
|
||||||
variant: 'custom',
|
color: 'custom',
|
||||||
onClose: () => markRead(payload.id),
|
onClose: () => markRead(payload.id),
|
||||||
action:
|
action:
|
||||||
actionLabel && actionUrl ? (
|
actionLabel && actionUrl ? (
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import slugify from 'slugify';
|
|||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from '../components/ToastContext';
|
||||||
import type { HttpResponse } from '@yaakapp/api';
|
import type { HttpResponse } from '@yaakapp/api';
|
||||||
import { getContentTypeHeader } from '../lib/models';
|
import { getContentTypeHeader } from '../lib/model_util';
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { readFile } from '@tauri-apps/plugin-fs';
|
import { readFile } from '@tauri-apps/plugin-fs';
|
||||||
import type { HttpResponse } from '@yaakapp/api';
|
import type { HttpResponse } from '@yaakapp/api';
|
||||||
import { getCharsetFromContentType } from './models';
|
import { getCharsetFromContentType } from './model_util';
|
||||||
|
|
||||||
export async function getResponseBodyText(response: HttpResponse): Promise<string | null> {
|
export async function getResponseBodyText(response: HttpResponse): Promise<string | null> {
|
||||||
if (response.bodyPath) {
|
if (response.bodyPath) {
|
||||||
|
|||||||
@@ -98,14 +98,23 @@ function templateTagColorVariables(color: YaakColor): Partial<CSSVariables> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toastColorVariables(color: YaakColor): Partial<CSSVariables> {
|
||||||
|
return {
|
||||||
|
text: color.lift(0.8),
|
||||||
|
textSubtle: color,
|
||||||
|
surface: color.translucify(0.9),
|
||||||
|
surfaceHighlight: color.translucify(0.8),
|
||||||
|
border: color.lift(0.3).translucify(0.6),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function bannerColorVariables(color: YaakColor): Partial<CSSVariables> {
|
function bannerColorVariables(color: YaakColor): Partial<CSSVariables> {
|
||||||
return {
|
return {
|
||||||
text: color.lift(0.8),
|
text: color.lift(0.8),
|
||||||
textSubtle: color.translucify(0.3),
|
textSubtle: color.translucify(0.3),
|
||||||
textSubtlest: color,
|
textSubtlest: color,
|
||||||
surface: color,
|
surface: color.translucify(0.9),
|
||||||
border: color.lift(0.3).translucify(0.4),
|
border: color.lift(0.3).translucify(0.4),
|
||||||
surfaceHighlight: color.translucify(0.9),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +210,15 @@ function bannerCSS(color: YaakColorKey, colors?: Partial<YaakColors>): string |
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toastCSS(color: YaakColorKey, colors?: Partial<YaakColors>): string | null {
|
||||||
|
const yaakColor = colors?.[color];
|
||||||
|
if (yaakColor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [variablesToCSS(`.x-theme-toast--${color}`, toastColorVariables(yaakColor))].join('\n\n');
|
||||||
|
}
|
||||||
|
|
||||||
function templateTagCSS(color: YaakColorKey, colors?: Partial<YaakColors>): string | null {
|
function templateTagCSS(color: YaakColorKey, colors?: Partial<YaakColors>): string | null {
|
||||||
const yaakColor = colors?.[color];
|
const yaakColor = colors?.[color];
|
||||||
if (yaakColor == null) {
|
if (yaakColor == null) {
|
||||||
@@ -253,6 +271,9 @@ export function getThemeCSS(theme: YaakTheme): string {
|
|||||||
...Object.keys(colors ?? {}).map((key) =>
|
...Object.keys(colors ?? {}).map((key) =>
|
||||||
bannerCSS(key as YaakColorKey, theme.components?.banner ?? colors),
|
bannerCSS(key as YaakColorKey, theme.components?.banner ?? colors),
|
||||||
),
|
),
|
||||||
|
...Object.keys(colors ?? {}).map((key) =>
|
||||||
|
toastCSS(key as YaakColorKey, theme.components?.banner ?? colors),
|
||||||
|
),
|
||||||
...Object.keys(colors ?? {}).map((key) =>
|
...Object.keys(colors ?? {}).map((key) =>
|
||||||
templateTagCSS(key as YaakColorKey, theme.components?.templateTag ?? colors),
|
templateTagCSS(key as YaakColorKey, theme.components?.templateTag ?? colors),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user