diff --git a/.changeset/admin-buttons.md b/.changeset/admin-buttons.md
new file mode 100644
index 00000000..fd3cb98f
--- /dev/null
+++ b/.changeset/admin-buttons.md
@@ -0,0 +1,5 @@
+---
+"@empirica/core": patch
+---
+
+Make admin buttons look right again.
diff --git a/.changeset/menu-positions.md b/.changeset/menu-positions.md
new file mode 100644
index 00000000..f85df58c
--- /dev/null
+++ b/.changeset/menu-positions.md
@@ -0,0 +1,6 @@
+---
+"@empirica/core": patch
+---
+
+`EmpiricaMenu` component improvements. Add `top` and `bottom` positions. Improve
+styling and readability. Use Lucide icons.
diff --git a/.changeset/reliable-subprocs.md b/.changeset/reliable-subprocs.md
new file mode 100644
index 00000000..c1f5d257
--- /dev/null
+++ b/.changeset/reliable-subprocs.md
@@ -0,0 +1,5 @@
+---
+"@empirica/core": patch
+---
+
+Make subprocs terminate more reliably.
diff --git a/cmds/empirica/cmd/export.go b/cmds/empirica/cmd/export.go
index b44481b2..e5375ad6 100644
--- a/cmds/empirica/cmd/export.go
+++ b/cmds/empirica/cmd/export.go
@@ -7,6 +7,7 @@ import (
"os/exec"
"path"
"strings"
+ "syscall"
"time"
"github.com/empiricaly/empirica/internal/build"
@@ -145,6 +146,9 @@ func addExportCommand(parent *cobra.Command) error {
Msg("exporting data")
c := exec.CommandContext(ctx, "empirica", exportArgs...)
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGKILL,
+ }
c.Stderr = os.Stderr
c.Stdout = os.Stdout
diff --git a/cmds/proxy/cmd/root.go b/cmds/proxy/cmd/root.go
index 893e9ef8..b61fb29c 100644
--- a/cmds/proxy/cmd/root.go
+++ b/cmds/proxy/cmd/root.go
@@ -60,6 +60,9 @@ func root(args []string) error {
Msg("proxy: chosen binary path")
c := exec.CommandContext(ctx, path, args...)
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGKILL,
+ }
c.Stderr = os.Stderr
c.Stdout = os.Stdout
diff --git a/internal/bundle/serve.go b/internal/bundle/serve.go
index ac53de61..3f40ac91 100644
--- a/internal/bundle/serve.go
+++ b/internal/bundle/serve.go
@@ -8,6 +8,7 @@ import (
"path"
"path/filepath"
"strings"
+ "syscall"
"github.com/empiricaly/empirica"
"github.com/empiricaly/empirica/internal/server"
@@ -76,6 +77,9 @@ func Serve(ctx context.Context, config *empirica.Config, in string, clean, devMo
Msg("serve: start server command")
c := exec.CommandContext(ctx, cmd, args...)
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGKILL,
+ }
p := path.Join(dir, "callbacks")
diff --git a/internal/callbacks/callbacks.go b/internal/callbacks/callbacks.go
index efa9a4d7..32ee4026 100644
--- a/internal/callbacks/callbacks.go
+++ b/internal/callbacks/callbacks.go
@@ -50,6 +50,10 @@ func Build(ctx context.Context, config *Config) error {
}
c := exec.CommandContext(ctx, parts[0], args...)
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Setpgid: true,
+ Pdeathsig: syscall.SIGKILL,
+ }
c.Stderr = os.Stderr
c.Stdout = os.Stdout
@@ -116,6 +120,14 @@ const (
)
func (cb *Callbacks) sigint() {
+ if cb.c == nil {
+ log.Debug().Msg("callback: no process to send signal to")
+
+ return
+ }
+
+ log.Debug().Msg("callback: cancelling process")
+
pgid, err := syscall.Getpgid(cb.c.Process.Pid)
if err != nil {
log.Debug().Err(err).Msg("callback: failed to send signal")
@@ -127,9 +139,9 @@ func (cb *Callbacks) sigint() {
log.Debug().Err(err).Msg("callback: failed to send signal")
}
- // if err := cb.c.Process.Signal(os.Interrupt); err != nil {
- // log.Debug().Err(err).Msg("callback: failed to send signal")
- // }
+ if err := cb.c.Process.Signal(os.Interrupt); err != nil {
+ log.Debug().Err(err).Msg("callback: failed to send signal")
+ }
cb.c = nil
}
@@ -271,7 +283,9 @@ func (cb *Callbacks) run(ctx context.Context) {
select {
case <-ctx.Done():
+ cb.Lock()
cb.sigint()
+ cb.Unlock()
return
case err = <-waiting:
@@ -282,7 +296,9 @@ func (cb *Callbacks) run(ctx context.Context) {
var exitError *exec.ExitError
if errors.As(err, &exitError) {
+ cb.Lock()
cb.c = nil
+ cb.Unlock()
if hardExits, shouldExit = checkHardExit(lastHardExit, hardExits, err); shouldExit {
return
@@ -354,7 +370,10 @@ func (cb *Callbacks) runOnce(ctx context.Context) (*exec.Cmd, error) {
}
c := exec.CommandContext(ctx, parts[0], remainder...) // #nosec G204
- c.SysProcAttr = &syscall.SysProcAttr{Setpgid: true, Pgid: 0}
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Setpgid: true,
+ Pdeathsig: syscall.SIGKILL,
+ }
c.Stderr = cb.stderr
c.Stdout = cb.stdout
diff --git a/internal/experiment/utils.go b/internal/experiment/utils.go
index fc3507e4..41d19c0f 100644
--- a/internal/experiment/utils.go
+++ b/internal/experiment/utils.go
@@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"strings"
+ "syscall"
"time"
"github.com/briandowns/spinner"
@@ -35,6 +36,9 @@ func RunCmdSilent(ctx context.Context, dir, command string, args ...string) erro
func runCmdSilence(ctx context.Context, dir string, silent bool, command string, args ...string) error {
c := exec.CommandContext(ctx, command, args...)
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGKILL,
+ }
if !silent {
c.Stderr = os.Stderr
diff --git a/internal/player/player.go b/internal/player/player.go
index 04600d10..9a5c1b3c 100644
--- a/internal/player/player.go
+++ b/internal/player/player.go
@@ -8,6 +8,7 @@ import (
"os/exec"
"path"
"strings"
+ "syscall"
"time"
"github.com/empiricaly/empirica/internal/term"
@@ -37,6 +38,9 @@ func Build(ctx context.Context, config *Config) error {
}
c := exec.CommandContext(ctx, parts[0], args...)
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGKILL,
+ }
c.Stderr = os.Stderr
c.Stdout = os.Stdout
@@ -164,6 +168,9 @@ func (p *Player) runDevCmd(ctx context.Context) (*exec.Cmd, error) {
log.Trace().Str("cmd", strings.Join(parts, " ")).Msg("player: run player dev command")
c := exec.CommandContext(ctx, parts[0], args...)
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGKILL,
+ }
c.Stderr = os.Stderr
c.Stdout = p.stdout
diff --git a/internal/settings/shared.go b/internal/settings/shared.go
index 23be9484..82182631 100644
--- a/internal/settings/shared.go
+++ b/internal/settings/shared.go
@@ -6,6 +6,7 @@ import (
"os/exec"
"path"
"strings"
+ "syscall"
"github.com/adrg/xdg"
"github.com/pkg/errors"
@@ -84,6 +85,9 @@ func InstallVolta(ctx context.Context) error {
func runCmd(ctx context.Context, dir, command string, args ...string) error {
c := exec.CommandContext(ctx, command, args...)
+ c.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGKILL,
+ }
c.Stderr = os.Stderr
c.Stdout = os.Stdout
diff --git a/lib/@empirica/core/src/player/react/EmpiricaMenu.tsx b/lib/@empirica/core/src/player/react/EmpiricaMenu.tsx
index de8faa6b..4d6aacfe 100644
--- a/lib/@empirica/core/src/player/react/EmpiricaMenu.tsx
+++ b/lib/@empirica/core/src/player/react/EmpiricaMenu.tsx
@@ -4,7 +4,13 @@ import { Logo } from "./Logo";
import { useParticipantContext } from "./hooks";
export type EmpiricaMenuProps = {
- position: "top-left" | "top-right" | "bottom-left" | "bottom-right";
+ position:
+ | "top"
+ | "top-left"
+ | "top-right"
+ | "bottom"
+ | "bottom-left"
+ | "bottom-right";
};
export function EmpiricaMenu({ position = "bottom-left" }: EmpiricaMenuProps) {
@@ -20,14 +26,20 @@ export function EmpiricaMenu({ position = "bottom-left" }: EmpiricaMenuProps) {
}
let className =
- "backdrop-blur-md bg-gray-200 rounded fixed z-20 flex space-x-1 text-gray-500";
+ "backdrop-blur-md bg-gray-200/50 rounded fixed z-20 flex space-x-1 text-gray-500";
switch (position) {
+ case "top":
+ className += " top-0 mt-2 ml-1/2 -translate-x-1/2";
+ break;
case "top-left":
className += " top-0 left-0 mt-2 ml-2";
break;
case "top-right":
className += " top-0 right-0 mt-2 mr-2";
break;
+ case "bottom":
+ className += " bottom-0 mb-2 ml-1/2 -translate-x-1/2";
+ break;
case "bottom-right":
className += " bottom-0 right-0 mb-2 mr-2";
break;
@@ -50,10 +62,17 @@ export function EmpiricaMenu({ position = "bottom-left" }: EmpiricaMenuProps) {
icon: (
),
inDevOnly: true,
@@ -64,10 +83,15 @@ export function EmpiricaMenu({ position = "bottom-left" }: EmpiricaMenuProps) {
icon: (
),
inDevOnly: true,
@@ -80,10 +104,14 @@ export function EmpiricaMenu({ position = "bottom-left" }: EmpiricaMenuProps) {
icon: (
),
inDevOnly: true,
@@ -96,10 +124,15 @@ export function EmpiricaMenu({ position = "bottom-left" }: EmpiricaMenuProps) {
icon: (
),
inDevOnly: true,
diff --git a/lib/admin-ui/src/style.css b/lib/admin-ui/src/style.css
index 21445023..bb139e5c 100644
--- a/lib/admin-ui/src/style.css
+++ b/lib/admin-ui/src/style.css
@@ -1,3 +1,10 @@
+@layer base {
+ button {
+ -webkit-appearance: none !important;
+ background-color: transparent;
+ }
+}
+
@layer utilities {
/* Chrome, Safari, Edge, Opera */
input.number-arrows-none::-webkit-outer-spin-button,
diff --git a/lib/admin-ui/uno.config.ts b/lib/admin-ui/uno.config.ts
index 97aed5a3..568b0734 100644
--- a/lib/admin-ui/uno.config.ts
+++ b/lib/admin-ui/uno.config.ts
@@ -1,3 +1,4 @@
+import { presetForms } from "@julr/unocss-preset-forms";
import {
defineConfig,
presetAttributify,
@@ -8,9 +9,18 @@ import {
transformerDirectives,
transformerVariantGroup,
} from "unocss";
-import { presetForms } from "@julr/unocss-preset-forms";
export default defineConfig({
+ safelist: [
+ ...["blue", "green", "yellow", "grey"]
+ .map((color) => [
+ `border-${color}-600`,
+ `text-${color}-600`,
+ `bg-${color}-600`,
+ `hover:bg-${color}-700`,
+ ])
+ .flat(),
+ ],
theme: {
colors: {
empirica: {
@@ -30,14 +40,14 @@ export default defineConfig({
presets: [
presetUno(),
presetForms(),
- presetAttributify(),
- presetIcons(),
+ // presetAttributify(),
+ // presetIcons(),
presetTypography(),
- presetWebFonts({
- fonts: {
- // ...
- },
- }),
+ // presetWebFonts({
+ // fonts: {
+ // // ...
+ // },
+ // }),
],
transformers: [transformerDirectives(), transformerVariantGroup()],
});