Skip to content

Commit 38578e5

Browse files
committed
feat(installer): NixOS install from nixpkgs and structured step blocks
- NixOS package manager now uses nixpkgs-unstable fcitx5-lotus (3.4.0), source method keeps flake build-from-source instructions - Render installer steps as alternating text/code blocks instead of a single mono code blob (NixOS install/server/env steps) - Show non-systemd manual steps (user creation, udev reload, uinput modprobe) only when init is not systemd
1 parent 0f82aab commit 38578e5

3 files changed

Lines changed: 233 additions & 56 deletions

File tree

src/components/InteractiveInstaller.vue

Lines changed: 145 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
userCreationCmd,
1616
udevReloadCmd,
1717
uinputModprobeCmd,
18+
type StepBlock,
1819
} from '@/data/installer';
1920
2021
const selectedDistro = ref(distros[0]?.name || '');
@@ -36,23 +37,97 @@ const needsUinputModprobe = computed(() => {
3637
return selectedMethod.value === 'Source';
3738
});
3839
39-
const activateServerCode = computed(() => {
40-
if (selectedDistro.value === 'NixOS')
41-
return '# Bước này đã được cấu hình trong flake.nix ở trên.';
40+
const nixosServerBlocks: StepBlock[] = [
41+
{
42+
type: 'text',
43+
content:
44+
'Thêm vào configuration.nix để bật server daemon (thay your_username bằng tên user của bạn):',
45+
},
46+
{
47+
type: 'code',
48+
content:
49+
'{\n pkgs,\n ...\n}: {\n systemd.packages = [ pkgs.fcitx5-lotus ];\n systemd.services."fcitx5-lotus-server@your_username" = {\n wantedBy = [ "multi-user.target" ];\n overrideStrategy = "asDropin";\n };\n}',
50+
},
51+
];
52+
53+
const nixosEnvBlocks: StepBlock[] = [
54+
{
55+
type: 'text',
56+
content:
57+
'Nếu cài qua i18n.inputMethod (Cách 1), NixOS tự set các biến này.\nNếu cần khai báo thủ công, thêm vào configuration.nix:',
58+
},
59+
{
60+
type: 'code',
61+
content:
62+
'environment.sessionVariables = {\n GTK_IM_MODULE = "fcitx";\n QT_IM_MODULE = "fcitx";\n XMODIFIERS = "@im=fcitx";\n SDL_IM_MODULE = "fcitx";\n GLFW_IM_MODULE = "ibus";\n};',
63+
},
64+
];
65+
66+
const toBlocks = (value: string | StepBlock[]): StepBlock[] => {
67+
if (Array.isArray(value)) return value;
68+
return [{ type: 'code', content: value }];
69+
};
70+
71+
const installStepBlocks = computed<StepBlock[]>(() => {
72+
const distroInfo =
73+
logic.steps.install[
74+
selectedDistro.value as keyof typeof logic.steps.install
75+
];
76+
if (!distroInfo) return [{ type: 'text', content: 'Cấu hình chưa sẵn sàng.' }];
77+
const methodData = (distroInfo as any)[selectedMethod.value];
78+
if (!methodData) {
79+
return [{ type: 'text', content: 'Phương thức chưa sẵn sàng.' }];
80+
}
81+
if (Array.isArray(methodData)) {
82+
return toBlocks(methodData);
83+
}
84+
if (methodData && typeof methodData === 'object') {
85+
return toBlocks(
86+
methodData[selectedShell.value] ||
87+
methodData.Bash ||
88+
'Cấu hình chưa sẵn sàng.',
89+
);
90+
}
91+
return toBlocks(methodData);
92+
});
93+
94+
const activateServerBlocks = computed<StepBlock[]>(() => {
95+
if (selectedDistro.value === 'NixOS') {
96+
if (selectedMethod.value === 'Package Manager') return nixosServerBlocks;
97+
return [
98+
{
99+
type: 'text',
100+
content: 'Bước này đã được cấu hình trong flake.nix ở trên.',
101+
},
102+
];
103+
}
42104
if (
43105
isAutoHandled.value &&
44106
selectedInit.value !== 'OpenRC' &&
45107
selectedInit.value !== 'runit'
46108
) {
47-
return '# Gói .deb sẽ tự động thực hiện bước này.\n' + serverCmd.value;
109+
return [
110+
{
111+
type: 'text',
112+
content: 'Gói .deb sẽ tự động thực hiện bước này. Có thể chạy thủ công:',
113+
},
114+
{ type: 'code', content: serverCmd.value },
115+
];
48116
}
49-
return serverCmd.value;
117+
return toBlocks(serverCmd.value);
50118
});
51119
52-
const shellConfigCode = computed(() => {
53-
if (selectedDistro.value === 'NixOS')
54-
return '# Bước này đã được cấu hình trong flake.nix ở trên.';
55-
return envCmd.value;
120+
const shellConfigBlocks = computed<StepBlock[]>(() => {
121+
if (selectedDistro.value === 'NixOS') {
122+
if (selectedMethod.value === 'Package Manager') return nixosEnvBlocks;
123+
return [
124+
{
125+
type: 'text',
126+
content: 'Bước này đã được cấu hình trong flake.nix ở trên.',
127+
},
128+
];
129+
}
130+
return toBlocks(envCmd.value);
56131
});
57132
58133
const serverCmd = computed(() => {
@@ -129,20 +204,6 @@ const copyToClipboard = async (text: string) => {
129204
}
130205
};
131206
132-
const installStepCode = computed(() => {
133-
const distroInfo =
134-
logic.steps.install[
135-
selectedDistro.value as keyof typeof logic.steps.install
136-
];
137-
if (!distroInfo) return 'Cấu hình chưa sẵn sàng.';
138-
const methodData = (distroInfo as any)[selectedMethod.value];
139-
if (!methodData) return 'Phương thức chưa sẵn sàng.';
140-
if (typeof methodData === 'object' && methodData !== null) {
141-
return methodData[selectedShell.value] || methodData.Bash || 'Cấu hình chưa sẵn sàng.';
142-
}
143-
return methodData;
144-
});
145-
146207
const autostartText = computed(
147208
() =>
148209
logic.steps.autostart[
@@ -268,14 +329,21 @@ const chromiumWaylandFlags = computed(() =>
268329
<div class="step-badge">1</div>
269330
<div class="step-content">
270331
<h4>Cài đặt gói</h4>
271-
<div class="code-container">
272-
<pre><code>{{ installStepCode }}</code></pre>
273-
<el-button
274-
class="copy-float"
275-
circle
276-
:icon="DocumentCopy"
277-
@click="copyToClipboard(installStepCode)"
278-
/>
332+
<div class="step-blocks">
333+
<template v-for="(block, idx) in installStepBlocks" :key="idx">
334+
<p v-if="block.type === 'text'" class="instruction">
335+
{{ block.content }}
336+
</p>
337+
<div v-else class="code-container">
338+
<pre><code>{{ block.content }}</code></pre>
339+
<el-button
340+
class="copy-float"
341+
circle
342+
:icon="DocumentCopy"
343+
@click="copyToClipboard(block.content)"
344+
/>
345+
</div>
346+
</template>
279347
</div>
280348
</div>
281349
</div>
@@ -338,14 +406,21 @@ const chromiumWaylandFlags = computed(() =>
338406
:closable="false"
339407
/>
340408
</div>
341-
<div class="code-container">
342-
<pre><code>{{ activateServerCode }}</code></pre>
343-
<el-button
344-
class="copy-float"
345-
circle
346-
:icon="DocumentCopy"
347-
@click="copyToClipboard(activateServerCode)"
348-
/>
409+
<div class="step-blocks">
410+
<template v-for="(block, idx) in activateServerBlocks" :key="idx">
411+
<p v-if="block.type === 'text'" class="instruction">
412+
{{ block.content }}
413+
</p>
414+
<div v-else class="code-container">
415+
<pre><code>{{ block.content }}</code></pre>
416+
<el-button
417+
class="copy-float"
418+
circle
419+
:icon="DocumentCopy"
420+
@click="copyToClipboard(block.content)"
421+
/>
422+
</div>
423+
</template>
349424
</div>
350425
</div>
351426
</div>
@@ -406,14 +481,21 @@ const chromiumWaylandFlags = computed(() =>
406481
<div class="step-badge">4</div>
407482
<div class="step-content">
408483
<h4>Thiết lập biến môi trường (Shell)</h4>
409-
<div class="code-container">
410-
<pre><code>{{ shellConfigCode }}</code></pre>
411-
<el-button
412-
class="copy-float"
413-
circle
414-
:icon="DocumentCopy"
415-
@click="copyToClipboard(shellConfigCode)"
416-
/>
484+
<div class="step-blocks">
485+
<template v-for="(block, idx) in shellConfigBlocks" :key="idx">
486+
<p v-if="block.type === 'text'" class="instruction">
487+
{{ block.content }}
488+
</p>
489+
<div v-else class="code-container">
490+
<pre><code>{{ block.content }}</code></pre>
491+
<el-button
492+
class="copy-float"
493+
circle
494+
:icon="DocumentCopy"
495+
@click="copyToClipboard(block.content)"
496+
/>
497+
</div>
498+
</template>
417499
</div>
418500
<el-alert
419501
title="Lưu ý: Bạn cần Đăng xuất và Đăng nhập lại sau bước này để cấu hình Shell có hiệu lực."
@@ -778,6 +860,22 @@ const chromiumWaylandFlags = computed(() =>
778860
overflow-x: auto;
779861
}
780862
863+
.step-blocks {
864+
display: flex;
865+
flex-direction: column;
866+
gap: 0.75rem;
867+
width: 100%;
868+
}
869+
870+
.step-blocks .code-container {
871+
margin-bottom: 0;
872+
}
873+
874+
.step-blocks .instruction {
875+
margin: 0;
876+
line-height: 1.6;
877+
}
878+
781879
.code-container.mini {
782880
padding: 0.75rem 1rem;
783881
margin-top: 0.5rem;

src/data/installer.ts

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export const distros = [
88
{ name: 'Void Linux', icon: 'co-linux' },
99
];
1010

11+
export type StepBlock =
12+
| { type: 'text'; content: string }
13+
| { type: 'code'; content: string };
14+
1115
export const methods = ['Package Manager', 'Binary', 'Source'];
1216
export const shells = ['Bash', 'Zsh', 'Fish'];
1317
export const deWms = [
@@ -71,10 +75,65 @@ export const logic = {
7175
'sudo zypper install acl cmake extra-cmake-modules fcitx5-devel libinput-devel systemd-devel gcc-c++ go hicolor-icon-theme systemd-devel libX11-devel udev python3\ngit clone https://github.com/LotusInputMethod/fcitx5-lotus.git\ncd fcitx5-lotus\ncmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=/usr/lib .\nmake\nsudo make install',
7276
},
7377
NixOS: {
74-
'Package Manager':
75-
'# Thêm input của fcitx5-lotus vào flake.nix:\n{\n inputs = {\n nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";\n\n fcitx5-lotus = {\n url = "github:LotusInputMethod/fcitx5-lotus";\n inputs.nixpkgs.follows = "nixpkgs";\n };\n };\n\n outputs = { self, ... }:\n # ...\n}\n\n# Bật fcitx5-lotus service trong configuration.nix:\n\n{\n inputs,\n ...\n}: {\n imports = [\n inputs.fcitx5-lotus.nixosModules.fcitx5-lotus\n ];\n\n services.fcitx5-lotus = {\n enable = true;\n users = [ "your_username" ]; # Sửa thành list tên user của bạn\n };\n}\n\n# Rebuild lại system để cài đặt.',
76-
Binary: 'NixOS ưu tiên cấu hình thông qua flake hoặc module.',
77-
Source: 'NixOS ưu tiên sử dụng nix-shell.',
78+
'Package Manager': [
79+
{
80+
type: 'text',
81+
content: 'Fcitx5-lotus 3.4.0 đã có trên nixpkgs-unstable.',
82+
},
83+
{
84+
type: 'text',
85+
content:
86+
'Lưu ý: cần dùng nixpkgs-unstable (gói chưa có ở nhánh stable).',
87+
},
88+
{
89+
type: 'text',
90+
content:
91+
'Cách 1 — configuration.nix: thêm engine vào fcitx5(NixOS sẽ tự set các biến môi trường cần thiết):',
92+
},
93+
{
94+
type: 'code',
95+
content:
96+
'{\n pkgs,\n ...\n}: {\n i18n.inputMethod = {\n enable = true;\n type = "fcitx5";\n fcitx5.addons = [ pkgs.fcitx5-lotus ];\n };\n}',
97+
},
98+
{ type: 'text', content: 'Cách 2 — Home Manager (home.nix):' },
99+
{
100+
type: 'code',
101+
content:
102+
'{\n pkgs,\n ...\n}: {\n home.packages = [ pkgs.fcitx5-lotus ];\n}',
103+
},
104+
{
105+
type: 'text',
106+
content: 'Cách 3 — thử nghiệm nhanh, không khai báo:',
107+
},
108+
{
109+
type: 'code',
110+
content:
111+
'nix profile install nixpkgs#fcitx5-lotus\nnix shell nixpkgs#fcitx5-lotus',
112+
},
113+
],
114+
Binary:
115+
'NixOS ưu tiên cấu hình thông qua nixpkgs hoặc build from source',
116+
Source: [
117+
{
118+
type: 'text',
119+
content: 'Thêm input của fcitx5-lotus vào flake.nix:',
120+
},
121+
{
122+
type: 'code',
123+
content:
124+
'{\n inputs = {\n nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";\n\n fcitx5-lotus = {\n url = "github:LotusInputMethod/fcitx5-lotus";\n inputs.nixpkgs.follows = "nixpkgs";\n };\n };\n\n outputs = { self, ... }:\n # ...\n}',
125+
},
126+
{
127+
type: 'text',
128+
content: 'Bật fcitx5-lotus service trong configuration.nix:',
129+
},
130+
{
131+
type: 'code',
132+
content:
133+
'{\n inputs,\n ...\n}: {\n imports = [\n inputs.fcitx5-lotus.nixosModules.fcitx5-lotus\n ];\n\n services.fcitx5-lotus = {\n enable = true;\n users = [ "your_username" ]; # Sửa thành list tên user của bạn\n };\n}',
134+
},
135+
{ type: 'text', content: 'Rebuild lại system để cài đặt.' },
136+
],
78137
},
79138
'Void Linux': {
80139
'Package Manager':

src/views/Home.vue

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,12 +1034,32 @@ sudo zypper removerepo fcitx5-lotus</code></pre>
10341034
</div>
10351035
</summary>
10361036
<div class="details-content">
1037-
<p class="instruction">
1038-
Xóa (hoặc comment) dòng
1039-
<code>services.fcitx5-lotus</code> và
1040-
<code>inputs</code> trong file config, sau đó rebuild lại
1041-
system. NixOS sẽ tự dọn dẹp.
1037+
<p class="instruction mb-3">
1038+
Gỡ tùy theo cách bạn đã cài:
10421039
</p>
1040+
<div class="code-container">
1041+
<pre><code># Nếu cài từ nixpkgs (package manager):
1042+
# - Xóa/comment dòng pkgs.fcitx5-lotus trong home.packages
1043+
# hoặc environment.systemPackages / i18n.inputMethod.fcitx5.addons
1044+
# - nixos-rebuild switch (hoặc home-manager switch)
1045+
1046+
# Nếu build từ source qua flake repo:
1047+
# - Xóa dòng services.fcitx5-lotus và inputs trong config
1048+
# - nixos-rebuild switch
1049+
1050+
# NixOS sẽ tự dọn dẹp.</code></pre>
1051+
<el-button
1052+
class="copy-float"
1053+
circle
1054+
:icon="DocumentCopy"
1055+
size="small"
1056+
@click="
1057+
copyToClipboard(
1058+
'# Nếu cài từ nixpkgs (package manager):\n# - Xóa/comment dòng pkgs.fcitx5-lotus trong home.packages\n# hoặc environment.systemPackages / i18n.inputMethod.fcitx5.addons\n# - nixos-rebuild switch (hoặc home-manager switch)\n\n# Nếu build từ source qua flake repo:\n# - Xóa dòng services.fcitx5-lotus và inputs trong config\n# - nixos-rebuild switch\n\n# NixOS sẽ tự dọn dẹp.',
1059+
)
1060+
"
1061+
/>
1062+
</div>
10431063
</div>
10441064
</details>
10451065

0 commit comments

Comments
 (0)