@nexttylabs/echo 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @nexttylabs/echo
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - fc3d8f1: support light/dark theme
8
+ - cc04d9f: Use the organization member role uniformly.
9
+ - 5cfdeb7: feat: support editing user profile
10
+
11
+ ### Patch Changes
12
+
13
+ - 76fda4d: fix organizational setting i18n
14
+ - 7dba561: remove legacy changeset files
15
+ - 158b254: show current orgnization
16
+ - 1e798f1: remove unuse tables and published files
17
+ - e3c4e1c: fix workflow errors
18
+ - d315d85: Fix the theme display issue.
19
+ - daf9abb: first release
20
+
3
21
  ## 0.12.0
4
22
 
5
23
  ### Minor Changes
@@ -38,7 +38,7 @@ export default async function BrandingSettingsPage() {
38
38
  <p className="text-muted-foreground">{t("pageDescription")}</p>
39
39
  </div>
40
40
 
41
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
41
+ <Card>
42
42
  <CardHeader>
43
43
  <CardTitle>{t("themeTitle")}</CardTitle>
44
44
  <CardDescription>{t("themeDesc")}</CardDescription>
@@ -48,7 +48,7 @@ export default async function BrandingSettingsPage() {
48
48
  </CardContent>
49
49
  </Card>
50
50
 
51
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
51
+ <Card>
52
52
  <CardHeader>
53
53
  <CardTitle>{t("copyTitle")}</CardTitle>
54
54
  <CardDescription>{t("copyDesc")}</CardDescription>
@@ -35,13 +35,13 @@ export default async function ChangelogSettingsPage() {
35
35
  <p className="text-muted-foreground">{t("pageDescription")}</p>
36
36
  </div>
37
37
 
38
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
38
+ <Card>
39
39
  <CardHeader>
40
40
  <CardTitle>{t("settingsTitle")}</CardTitle>
41
41
  <CardDescription>{t("settingsDesc")}</CardDescription>
42
42
  </CardHeader>
43
43
  <CardContent>
44
- <div className="rounded-md border border-dashed border-slate-200 bg-slate-50/50 px-4 py-8 text-center text-sm text-muted-foreground">
44
+ <div className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">
45
45
  {t("settingsComingSoon")}
46
46
  </div>
47
47
  </CardContent>
@@ -35,25 +35,25 @@ export default async function FeedbackSettingsPage() {
35
35
  <p className="text-muted-foreground">{t("pageDescription")}</p>
36
36
  </div>
37
37
 
38
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
38
+ <Card>
39
39
  <CardHeader>
40
40
  <CardTitle>{t("settingsTitle")}</CardTitle>
41
41
  <CardDescription>{t("settingsDesc")}</CardDescription>
42
42
  </CardHeader>
43
43
  <CardContent>
44
- <div className="rounded-md border border-dashed border-slate-200 bg-slate-50/50 px-4 py-8 text-center text-sm text-muted-foreground">
44
+ <div className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">
45
45
  {t("settingsComingSoon")}
46
46
  </div>
47
47
  </CardContent>
48
48
  </Card>
49
49
 
50
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
50
+ <Card>
51
51
  <CardHeader>
52
52
  <CardTitle>{t("roadmapTitle")}</CardTitle>
53
53
  <CardDescription>{t("roadmapDesc")}</CardDescription>
54
54
  </CardHeader>
55
55
  <CardContent>
56
- <div className="rounded-md border border-dashed border-slate-200 bg-slate-50/50 px-4 py-8 text-center text-sm text-muted-foreground">
56
+ <div className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">
57
57
  {t("roadmapComingSoon")}
58
58
  </div>
59
59
  </CardContent>
@@ -35,16 +35,16 @@ export default async function IntegrationsSettingsPage() {
35
35
  <p className="text-muted-foreground">{t("pageDescription")}</p>
36
36
  </div>
37
37
 
38
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
38
+ <Card>
39
39
  <CardHeader>
40
40
  <CardTitle>{t("availableTitle")}</CardTitle>
41
41
  <CardDescription>{t("availableDesc")}</CardDescription>
42
42
  </CardHeader>
43
43
  <CardContent>
44
44
  <div className="grid gap-4 md:grid-cols-2">
45
- <div className="rounded-lg border border-slate-200 p-4">
45
+ <div className="rounded-lg border p-4">
46
46
  <div className="flex items-center gap-3">
47
- <div className="flex h-10 w-10 items-center justify-center rounded-md bg-slate-100">
47
+ <div className="flex h-10 w-10 items-center justify-center rounded-md bg-muted">
48
48
  <span className="text-lg">🔗</span>
49
49
  </div>
50
50
  <div>
@@ -53,9 +53,9 @@ export default async function IntegrationsSettingsPage() {
53
53
  </div>
54
54
  </div>
55
55
  </div>
56
- <div className="rounded-lg border border-slate-200 p-4">
56
+ <div className="rounded-lg border p-4">
57
57
  <div className="flex items-center gap-3">
58
- <div className="flex h-10 w-10 items-center justify-center rounded-md bg-slate-100">
58
+ <div className="flex h-10 w-10 items-center justify-center rounded-md bg-muted">
59
59
  <span className="text-lg">📋</span>
60
60
  </div>
61
61
  <div>
@@ -64,9 +64,9 @@ export default async function IntegrationsSettingsPage() {
64
64
  </div>
65
65
  </div>
66
66
  </div>
67
- <div className="rounded-lg border border-slate-200 p-4">
67
+ <div className="rounded-lg border p-4">
68
68
  <div className="flex items-center gap-3">
69
- <div className="flex h-10 w-10 items-center justify-center rounded-md bg-slate-100">
69
+ <div className="flex h-10 w-10 items-center justify-center rounded-md bg-muted">
70
70
  <span className="text-lg">📊</span>
71
71
  </div>
72
72
  <div>
@@ -75,9 +75,9 @@ export default async function IntegrationsSettingsPage() {
75
75
  </div>
76
76
  </div>
77
77
  </div>
78
- <div className="rounded-lg border border-slate-200 p-4">
78
+ <div className="rounded-lg border p-4">
79
79
  <div className="flex items-center gap-3">
80
- <div className="flex h-10 w-10 items-center justify-center rounded-md bg-slate-100">
80
+ <div className="flex h-10 w-10 items-center justify-center rounded-md bg-muted">
81
81
  <span className="text-lg">💬</span>
82
82
  </div>
83
83
  <div>
@@ -40,7 +40,7 @@ export default async function ModulesSettingsPage() {
40
40
  <p className="text-muted-foreground">{t("pageDescription")}</p>
41
41
  </div>
42
42
 
43
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
43
+ <Card>
44
44
  <CardHeader>
45
45
  <CardTitle>{t("configTitle")}</CardTitle>
46
46
  <CardDescription>{t("configDesc")}</CardDescription>
@@ -35,7 +35,7 @@ export default async function PortalAccessSettingsPage() {
35
35
  <p className="text-muted-foreground">控制 Portal 的公开访问与权限范围</p>
36
36
  </div>
37
37
 
38
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
38
+ <Card>
39
39
  <CardHeader>
40
40
  <CardTitle>可见性与权限</CardTitle>
41
41
  <CardDescription>设置公开访问、投票与索引策略</CardDescription>
@@ -35,7 +35,7 @@ export default async function PortalBrandingSettingsPage() {
35
35
  <p className="text-muted-foreground">{t("description")}</p>
36
36
  </div>
37
37
 
38
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
38
+ <Card>
39
39
  <CardHeader>
40
40
  <CardTitle>{t("theme.title")}</CardTitle>
41
41
  <CardDescription>{t("theme.description")}</CardDescription>
@@ -45,7 +45,7 @@ export default async function PortalBrandingSettingsPage() {
45
45
  </CardContent>
46
46
  </Card>
47
47
 
48
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
48
+ <Card>
49
49
  <CardHeader>
50
50
  <CardTitle>{t("copy.title")}</CardTitle>
51
51
  <CardDescription>{t("copy.description")}</CardDescription>
@@ -33,7 +33,7 @@ export default async function PortalGrowthSettingsPage() {
33
33
  <p className="text-muted-foreground">配置分享入口与 SEO 优化</p>
34
34
  </div>
35
35
 
36
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
36
+ <Card>
37
37
  <CardHeader>
38
38
  <CardTitle>分享设置</CardTitle>
39
39
  <CardDescription>配置社交分享与传播渠道</CardDescription>
@@ -43,7 +43,7 @@ export default async function PortalGrowthSettingsPage() {
43
43
  </CardContent>
44
44
  </Card>
45
45
 
46
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
46
+ <Card>
47
47
  <CardHeader>
48
48
  <CardTitle>SEO 设置</CardTitle>
49
49
  <CardDescription>搜索引擎与社交分享优化</CardDescription>
@@ -35,7 +35,7 @@ export default async function PortalModulesSettingsPage() {
35
35
  <p className="text-muted-foreground">自定义 Portal 的功能模块开关</p>
36
36
  </div>
37
37
 
38
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
38
+ <Card>
39
39
  <CardHeader>
40
40
  <CardTitle>模块配置</CardTitle>
41
41
  <CardDescription>按需启用反馈、路线图与更新日志</CardDescription>
@@ -37,7 +37,7 @@ export default async function PortalResourcesSettingsPage() {
37
37
  <p className="text-muted-foreground">门户入口与相关资源链接</p>
38
38
  </div>
39
39
 
40
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
40
+ <Card>
41
41
  <CardHeader className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
42
42
  <div>
43
43
  <CardTitle>Portal 链接</CardTitle>
@@ -48,8 +48,8 @@ export default async function PortalResourcesSettingsPage() {
48
48
  </Badge>
49
49
  </CardHeader>
50
50
  <CardContent className="space-y-4">
51
- <div className="text-sm text-slate-600">
52
- 门户链接:<span className="font-medium text-slate-900">{portalLink}</span>
51
+ <div className="text-sm text-muted-foreground">
52
+ 门户链接:<span className="font-medium text-foreground">{portalLink}</span>
53
53
  </div>
54
54
  <div className="flex flex-wrap gap-3">
55
55
  <Button asChild variant="outline" size="sm">
@@ -35,25 +35,25 @@ export default async function WidgetsSettingsPage() {
35
35
  <p className="text-muted-foreground">{t("pageDescription")}</p>
36
36
  </div>
37
37
 
38
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
38
+ <Card>
39
39
  <CardHeader>
40
40
  <CardTitle>{t("feedbackWidget")}</CardTitle>
41
41
  <CardDescription>{t("feedbackWidgetDesc")}</CardDescription>
42
42
  </CardHeader>
43
43
  <CardContent>
44
- <div className="rounded-md border border-dashed border-slate-200 bg-slate-50/50 px-4 py-8 text-center text-sm text-muted-foreground">
44
+ <div className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">
45
45
  {t("feedbackWidgetComingSoon")}
46
46
  </div>
47
47
  </CardContent>
48
48
  </Card>
49
49
 
50
- <Card className="border-slate-200/80 bg-white/80 shadow-sm">
50
+ <Card>
51
51
  <CardHeader>
52
52
  <CardTitle>{t("changelogWidget")}</CardTitle>
53
53
  <CardDescription>{t("changelogWidgetDesc")}</CardDescription>
54
54
  </CardHeader>
55
55
  <CardContent>
56
- <div className="rounded-md border border-dashed border-slate-200 bg-slate-50/50 px-4 py-8 text-center text-sm text-muted-foreground">
56
+ <div className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">
57
57
  {t("changelogWidgetComingSoon")}
58
58
  </div>
59
59
  </CardContent>
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import { useState, useEffect } from "react";
3
4
 
4
5
  /*
5
6
  * Copyright (c) 2026 Nexttylabs Team
@@ -66,6 +67,32 @@ function useLocaleSwitcher() {
66
67
 
67
68
  export function LanguageSwitcher({ variant = "text" }: LanguageSwitcherProps) {
68
69
  const { locale, t, isPending, handleSelect } = useLocaleSwitcher();
70
+ const [mounted, setMounted] = useState(false);
71
+
72
+ useEffect(() => {
73
+ setMounted(true);
74
+ }, []);
75
+
76
+ // Render a placeholder button during SSR to avoid hydration mismatch
77
+ // caused by Radix UI's dynamic ID generation
78
+ if (!mounted) {
79
+ return variant === "icon" ? (
80
+ <Button
81
+ variant="ghost"
82
+ size="icon"
83
+ disabled
84
+ aria-label={t("label")}
85
+ >
86
+ <Languages className="h-4 w-4" />
87
+ <span className="sr-only">{t("label")}</span>
88
+ </Button>
89
+ ) : (
90
+ <Button variant="ghost" size="sm" disabled>
91
+ <Languages className="h-4 w-4 mr-2" />
92
+ {t(locale)}
93
+ </Button>
94
+ );
95
+ }
69
96
 
70
97
  return (
71
98
  <DropdownMenu>
@@ -56,10 +56,10 @@ export function PortalModulesPanel({ organizationId, initialModules }: PortalMod
56
56
  };
57
57
 
58
58
  return (
59
- <div className="space-y-4 rounded-xl border bg-white/80 p-5 shadow-sm">
59
+ <div className="space-y-4 rounded-xl border bg-muted/50 p-5 shadow-sm">
60
60
  <div>
61
- <h3 className="text-sm font-semibold text-slate-900">{t("panelTitle")}</h3>
62
- <p className="mt-1 text-sm text-slate-600">
61
+ <h3 className="text-sm font-semibold text-foreground">{t("panelTitle")}</h3>
62
+ <p className="mt-1 text-sm text-muted-foreground">
63
63
  {t("panelDescription")}
64
64
  </p>
65
65
  </div>
@@ -89,7 +89,7 @@ export function PortalModulesPanel({ organizationId, initialModules }: PortalMod
89
89
  <Button onClick={onSave} disabled={saving}>
90
90
  {saving ? t("saving") : t("saveButton")}
91
91
  </Button>
92
- {message && <span className="text-sm text-slate-600">{message}</span>}
92
+ {message && <span className="text-sm text-muted-foreground">{message}</span>}
93
93
  </div>
94
94
  </div>
95
95
  );
@@ -107,10 +107,10 @@ function ModuleRow({
107
107
  onChange: (value: boolean) => void;
108
108
  }) {
109
109
  return (
110
- <div className="flex items-center justify-between gap-4 rounded-lg border border-slate-200 bg-white px-4 py-3">
110
+ <div className="flex items-center justify-between gap-4 rounded-lg border bg-background px-4 py-3">
111
111
  <div>
112
- <p className="text-sm font-medium text-slate-900">{label}</p>
113
- <p className="text-xs text-slate-500">{description}</p>
112
+ <p className="text-sm font-medium text-foreground">{label}</p>
113
+ <p className="text-xs text-muted-foreground">{description}</p>
114
114
  </div>
115
115
  <Switch checked={checked} onCheckedChange={onChange} />
116
116
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexttylabs/echo",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "license": "AGPL-3.0",
5
5
  "private": false,
6
6
  "publishConfig": {