Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/components/BottomPanel/Terminal/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Component, createSignal, Show } from 'solid-js'
import { Component, createSignal } from 'solid-js'
import { useTranslations } from '../../Composables/useTranslations'
import { SolidIcon } from '../../Solid/Icon/SolidIcon'
import { SolidButton } from '../../Solid/Inputs/Button/SolidButton'
import { SolidIconButton } from '../../Solid/Inputs/IconButton/IconButton'
import { TextField } from '../../Solid/Inputs/TextField/TextField'
import { toSignal } from '../../Solid/toSignal'
Expand Down
6 changes: 2 additions & 4 deletions src/components/Notifications/Errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { InformationWindow } from '../Windows/Common/Information/InformationWindow'
import { openErrorWindow } from '../Windows/Error/ErrorWindow'
import { App } from '/@/App'
import { createNotification } from '/@/components/Notifications/create'
import { IDisposable } from '/@/types/disposable'
Expand Down Expand Up @@ -29,10 +30,7 @@ export function createErrorNotification(error: Error): IDisposable {
textColor: 'white',
disposeOnMiddleClick: true,
onClick: () => {
new InformationWindow({
name: `[ERROR: ${short}]`,
description: `[${error.message} (${getStackTrace(error)})]`,
})
openErrorWindow({ error })
notification.dispose()
},
})
Expand Down
17 changes: 13 additions & 4 deletions src/components/Solid/Inputs/Button/SolidButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { JSX } from 'solid-js/types'
import { useRipple } from '../../Directives/Ripple/Ripple'

interface SolidButtonProps {
class?: string
children: JSX.Element | string
color?: string
disabled?: boolean
onClick: () => void
}

Expand All @@ -14,23 +16,30 @@ export function SolidButton(props: SolidButtonProps) {
<button
use:ripple
class="
text-white
p-2
py-1
overflow-hidden
bg-primary
rounded-lg
shadow-lg
active:scale-[.95]
focus:outline-none
focus:-translate-y-[0.1rem]
focus:shadow-2xl
focus:scale-105
focus:shadow-xl
hover:-translate-y-[0.1rem]
hover:shadow-xl
transition-transform
ease-in-out
duration-200
"
classList={{
[props.class!]: !!props.class,
[`text-white`]: props.color === 'primary',
}}
style={{
'background-color': `var(--v-${props.color ?? 'toolbar'}-base)`,
}}
onClick={props.onClick}
disabled={props.disabled}
>
<span class="flex items-center">{props.children}</span>
</button>
Expand Down
20 changes: 15 additions & 5 deletions src/components/Solid/Inputs/IconButton/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,21 @@ export const SolidIconButton: Component<IconButtonProps> = (props) => {
return (
<button
use:ripple={!isDisabled()}
class="w-10 h-10 rounded-full focus:outline-none hover:scale-110 transition-transform ease-in-out duration-200"
classList={{
'opacity-50 cursor-default': isDisabled(),
'active:scale-[.95]': !isDisabled(),
}}
class="
w-10
h-10
rounded-full
focus:outline-none
transition-transform
ease-in-out
duration-200
disabled:opacity-50
disabled:cursor-default
enabled:active:scale-[.95]
enabled:focus:scale-110
enabled:hover:scale-110
"
disabled={isDisabled()}
onClick={() => (props.disabled ? undefined : props.onClick())}
>
<span class="flex items-center justify-center">
Expand Down
6 changes: 3 additions & 3 deletions src/components/Solid/Window/Manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { toVue } from '../toVue'
import { SolidWindow } from './Window'

export class SolidWindowManager {
protected readState: () => SolidWindow[]
protected writeState: (val: SolidWindow[]) => void
protected readState: () => SolidWindow<any>[]
protected writeState: (val: SolidWindow<any>[]) => void

constructor() {
;[this.readState, this.writeState] = createSignal([])
}

addWindow(window: SolidWindow) {
addWindow(window: SolidWindow<any>) {
this.writeState([...this.readState(), window])

return {
Expand Down
11 changes: 7 additions & 4 deletions src/components/Solid/Window/Window.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { App } from '/@/App'

export const WindowComponent: Component<{
children: JSX.Element
currentWindow: SolidWindow
currentWindow: SolidWindow<any>
}> = (props) => {
const window = () => props.currentWindow
let dialog: HTMLDialogElement | undefined = undefined
Expand Down Expand Up @@ -97,20 +97,23 @@ export const WindowComponent: Component<{
)
}

export class SolidWindow {
export class SolidWindow<T = {}> {
public readonly isOpen = createRef(true)
public openEvent = new Signal<void>()
public closeEvent = new Signal<void>()
protected _disposeSelf: (() => void) | null = null

constructor(protected component: Component) {
constructor(
protected component: Component<T>,
protected props: T = {} as T
) {
this.open()
}

get windowComponent(): Component {
return () => (
<WindowComponent currentWindow={this}>
{this.component({})}
{this.component(this.props)}
</WindowComponent>
)
}
Expand Down
76 changes: 76 additions & 0 deletions src/components/Windows/Error/ErrorWindow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Component, For } from 'solid-js'
import { useTranslations } from '../../Composables/useTranslations'
import { SolidIcon } from '../../Solid/Icon/SolidIcon'
import { SolidButton } from '../../Solid/Inputs/Button/SolidButton'
import { SolidSpacer } from '../../Solid/SolidSpacer'
import { SolidWindow } from '../../Solid/Window/Window'
import { App } from '/@/App'
import { version } from '/@/utils/app/version'

const ErrorWindow: Component<{
error: Error
}> = (props) => {
const { t } = useTranslations()

const prettyError = () =>
`Error: ${props.error.message}\n${props.error.stack ?? ''}`

const onCopyError = () => {
navigator.clipboard.writeText(prettyError())
}
const onReportBug = () => {
App.openUrl(
`https://github.com/bridge-core/editor/issues/new?assignees=&labels=bug&template=bug_report.md&title=${prettyError()}`
)
}

return (
<div class="p-2 w-96 h-72 flex flex-col items-center justify-center">
<div class="flex grow-0 items-center">
<SolidIcon
size={3}
color="error"
icon="mdi-alert-circle-outline"
class="mr-2"
/>
<h1 class="text-3xl font-bold">{t('general.error')}</h1>
</div>

<p class="grow-0 text-lg text-center">
{t('windows.error.explanation')}
</p>

<div class="text-sm opacity-60 text-center">
{props.error.message}
</div>

<SolidSpacer />

<div class="flex grow-0 w-full h-min items-start">
<SolidSpacer />

{/* Report bug on GitHub */}
<SolidButton class="mr-1" onClick={onReportBug}>
<SolidIcon class="mr-1" icon="mdi-github" />
<span>{t('general.reportBug')}</span>
</SolidButton>

{/* Copy error message button */}
<SolidButton color="primary" onClick={onCopyError}>
<SolidIcon class="mr-1" icon="mdi-content-copy" />
<span>
{t('actions.copy.name')} {t('general.error')}
</span>
</SolidButton>
</div>
</div>
)
}

interface IErrorWindowOpts {
error: Error
}

export function openErrorWindow({ error }: IErrorWindowOpts) {
new SolidWindow(ErrorWindow, { error })
}
7 changes: 6 additions & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@
"warnBeforeClosing": {
"title": "Unsaved Changes",
"description": "Are you sure you want to close this window? Any unsaved changes will be lost."
}
},
"error": "Error",
"reportBug": "Report Bug"
},
"openWith": {
"snowstorm": "Snowstorm",
Expand Down Expand Up @@ -612,6 +614,9 @@
"sidebar": {
"disabledItem": "This item is disabled"
},
"error": {
"explanation": "bridge. encountered the following error:"
},
"changelogWindow": {
"title": "What's new?"
},
Expand Down