feat(settings): Extensions tab — "watch this space" notice (T-456)

Built-in extensions are always on and there's no third-party install path yet,
so the Extensions tab is a notice rather than a toggle list — a toggle list
would let users brick the app by disabling load-bearing builtins. It explains
that installing/enabling/disabling arrives with third-party (Lua) extensions
and points at the records that pick it up (D-16 / T-8).

Fleshes out the builtin.extensions-ui stub via the custom-control hatch. Adds
two renderer guards — empty section/field labels render no chrome — so a
notice-only category shows just its card.

Tests: contributes the Extensions category + notice control; the notice renders.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-17 13:45:01 +02:00
co-authored by Claude Opus 4.8
parent 757d6f71fa
commit 79c5294d44
9 changed files with 134 additions and 11 deletions
@@ -0,0 +1,56 @@
import 'package:clide/kernel/kernel.dart';
import 'package:clide/widgets/widgets.dart';
import 'package:flutter/widgets.dart';
/// The Extensions settings tab's "watch this space" notice (T-456).
///
/// Built-in extensions are always on and there's no third-party install path
/// yet, so there's nothing to manage. Rather than ship a toggle list that could
/// brick the app, the tab explains that extension management arrives with
/// third-party (Lua) extensions and points at the records that track it.
/// Rendered inside the section card (no own surface) via the custom-control
/// registry.
class ExtensionsNotice extends StatelessWidget {
const ExtensionsNotice({super.key});
static const ns = 'builtin.extensions-ui';
@override
Widget build(BuildContext context) {
final tokens = ClideTheme.of(context).surface;
final i = ClideKernel.of(context).i18n;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
ClideIcon(PhosphorIcons.byName('puzzle-piece'), size: 18, color: tokens.globalTextMuted),
const SizedBox(width: 8),
ClideText(
i.string('notice.title', namespace: ns, placeholder: 'Extension management is coming'),
fontSize: 14,
fontWeight: FontWeight.w600,
),
],
),
const SizedBox(height: 10),
ClideText(
i.string(
'notice.body',
namespace: ns,
placeholder:
'Installing, enabling, and disabling extensions arrives with third-party (Lua) extension support. For now the built-in extensions are always on.',
),
color: tokens.globalTextMuted,
),
const SizedBox(height: 10),
ClideText(
i.string('notice.tracked', namespace: ns, placeholder: 'Tracked in T-8 (Tier 6) · D-16'),
color: tokens.globalTextMuted,
fontSize: clideFontCaption,
fontFamily: clideMonoFamily,
),
],
);
}
}