Skip to content
Open
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
184 changes: 184 additions & 0 deletions NativeScriptWindowsDemo/App/core/ui.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
const delegateKeepAlive = [];

export function resolveType(typeName) {
const parts = String(typeName).split(".");
let current = globalThis;
for (let i = 0; i < parts.length; i += 1) {
current = current && current[parts[i]];
}
return current;
}

export function text(value, size) {
const control = new Windows.UI.Xaml.Controls.TextBlock();
control.Text = String(value);
if (size) {
control.FontSize = size;
}
return control;
}

export function createTypedDelegate(typeName, callback) {
const TypeCtor = resolveType(typeName);
if (typeof TypeCtor !== "function") {
return null;
}

try {
const delegate = new TypeCtor({
Invoke: function () {
return callback.apply(null, arguments);
},
});
delegateKeepAlive.push(delegate);
return delegate;
} catch (_error) {
return null;
}
}

export function bindClick(button, onClick) {
const callback = typeof onClick === "function" ? onClick : function () {};
const delegate = createTypedDelegate("Windows.UI.Xaml.RoutedEventHandler", callback);

if (delegate && typeof button.add_Click === "function") {
button.add_Click(delegate);
return;
}

button.Click = delegate || callback;
}

export function createButton(label, onClick) {
const button = new Windows.UI.Xaml.Controls.Button();
button.Height = 42;
button.Content = String(label);
bindClick(button, onClick);
return button;
}

export function createCard(titleValue, bodyValue) {
const border = new Windows.UI.Xaml.Controls.Border();

const stack = new Windows.UI.Xaml.Controls.StackPanel();
stack.Spacing = 8;

const titleText = text(titleValue, 19);
const bodyText = text(bodyValue, 14);
bodyText.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;

stack.Children.Append(titleText);
stack.Children.Append(bodyText);

border.Child = stack;
return border;
}

export function withContentPadding(content) {
const outer = new Windows.UI.Xaml.Controls.StackPanel();

const topSpacer = new Windows.UI.Xaml.Controls.Border();
topSpacer.Height = 18;
outer.Children.Append(topSpacer);

const row = new Windows.UI.Xaml.Controls.StackPanel();
row.Orientation = Windows.UI.Xaml.Controls.Orientation.Horizontal;

const leftSpacer = new Windows.UI.Xaml.Controls.Border();
leftSpacer.Width = 24;

row.Children.Append(leftSpacer);
row.Children.Append(content);
outer.Children.Append(row);

return outer;
}

export function safeGetChildrenSize(element) {
try {
const children = element && element.Children;
if (children && typeof children.Size === "number") {
return children.Size;
}
} catch (_error) {
}

return -1;
}

export function createBrandImage(width, height) {
const host = new Windows.UI.Xaml.Controls.StackPanel();
host.Spacing = 0;

const image = new Windows.UI.Xaml.Controls.Image();
image.Width = width || 280;
image.Height = height || 120;
image.Stretch = Windows.UI.Xaml.Media.Stretch.Uniform;

const fallback = text("NativeScript", 44);
fallback.Visibility = Windows.UI.Xaml.Visibility.Collapsed;

host.Children.Append(image);
host.Children.Append(fallback);

const candidateUris = [
"ms-appx:///Assets/Wide310x150Logo.scale-200.png",
"ms-appx:///Assets/Square150x150Logo.scale-200.png",
"ms-appx:///Assets/StoreLogo.png",
"ms-appx:///Assets/cover.png",
"https://raw.githubusercontent.com/NativeScript/NativeScript/main/tools/graphics/cover.png",
].filter(function (value) {
return typeof value === "string" && value.length > 0;
});

let assigned = false;

const tryAssignImageSource = function () {
for (let i = 0; i < candidateUris.length; i += 1) {
const uriValue = candidateUris[i];
console.log("NativeScriptWindowsDemo: trying image URI", uriValue);

try {
const uri = new Windows.Foundation.Uri(uriValue);
const bitmap = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
bitmap.UriSource = uri;
image.Source = bitmap;
console.log("NativeScriptWindowsDemo: image source assigned", uriValue);
assigned = true;
return true;
} catch (error) {
console.log("NativeScriptWindowsDemo: invalid image URI", uriValue, error && error.message ? error.message : error);
}
}

return false;
};

const showTextFallback = function () {
image.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
fallback.Visibility = Windows.UI.Xaml.Visibility.Visible;
};

if (!tryAssignImageSource()) {
showTextFallback();
}

if (!assigned) {
showTextFallback();
}

return host;
}

export function openExternalUrl(url) {
try {
const launchOp = Windows.System.Launcher.LaunchUriAsync(new Windows.Foundation.Uri(String(url)));
if (launchOp && typeof NSWinRT !== "undefined" && typeof NSWinRT.onCompleted === "function") {
NSWinRT.onCompleted(launchOp, function (_asyncInfo, status) {
console.log("NativeScriptWindowsDemo: launch status", status, url);
}, { timeoutMs: 12000 });
}
} catch (error) {
console.log("NativeScriptWindowsDemo: failed to open URL", url, error && error.message ? error.message : error);
}
}
59 changes: 59 additions & 0 deletions NativeScriptWindowsDemo/App/features/components.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
createButton,
createCard,
safeGetChildrenSize,
text,
} from "../core/ui.js";

export function createComponentsPage() {
const root = new Windows.UI.Xaml.Controls.StackPanel();
root.Spacing = 12;

root.Children.Append(text("Components Lab", 34));

const description = text(
"This tab demonstrates real WinRT controls manipulated from JavaScript event handlers.",
14,
);
description.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;
root.Children.Append(description);

const toggle = new Windows.UI.Xaml.Controls.ToggleSwitch();
toggle.Header = "Enable runtime polish";
toggle.IsOn = true;

const slider = new Windows.UI.Xaml.Controls.Slider();
slider.Minimum = 0;
slider.Maximum = 100;
slider.Value = 40;
slider.Width = 360;

const progress = new Windows.UI.Xaml.Controls.ProgressBar();
progress.Minimum = 0;
progress.Maximum = 100;
progress.Value = 40;
progress.Width = 360;

const status = text("State: polish enabled at 40%", 13);

const applyButton = createButton("Apply Slider To Progress", function () {
progress.Value = slider.Value;
status.Text = "State: " + (toggle.IsOn ? "polish enabled" : "polish disabled") + " at " + Math.round(slider.Value) + "%";
});

root.Children.Append(toggle);
root.Children.Append(slider);
root.Children.Append(progress);
root.Children.Append(applyButton);
root.Children.Append(status);

root.Children.Append(
createCard(
"Copyable Pattern",
"Instantiate controls, keep references, and update state on click handlers.",
),
);

console.log("NativeScriptWindowsDemo: components children", safeGetChildrenSize(root));
return root;
}
70 changes: 70 additions & 0 deletions NativeScriptWindowsDemo/App/features/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
createBrandImage,
createButton,
createCard,
openExternalUrl,
safeGetChildrenSize,
text,
} from "../core/ui.js";

export function createDashboardPage(onNavigate) {
const root = new Windows.UI.Xaml.Controls.StackPanel();
root.Spacing = 14;

root.Children.Append(text("NativeScript for Windows", 42));

const subtitle = text(
"Build native desktop apps with JavaScript, first-class WinRT interop, and a runtime that feels fast and direct.",
16,
);
subtitle.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap;
root.Children.Append(subtitle);

root.Children.Append(createBrandImage(380, 200));

root.Children.Append(
createCard(
"Single JavaScript Runtime",
"Use one language across startup, UI composition, interop calls, and event binding.",
),
);
root.Children.Append(
createCard(
"Real Native Controls",
"NavigationView, ToggleSwitch, SplitView, and every WinRT type are available directly from JavaScript.",
),
);
root.Children.Append(
createCard(
"Production-minded Tooling",
"Build from Rust crates, test with sample apps, and iterate quickly without leaving native APIs behind.",
),
);

const ctaRow = new Windows.UI.Xaml.Controls.StackPanel();
ctaRow.Orientation = Windows.UI.Xaml.Controls.Orientation.Horizontal;
ctaRow.Spacing = 8;

ctaRow.Children.Append(
createButton("Explore Components Demo", function () {
if (typeof onNavigate === "function") {
onNavigate("components");
}
}),
);

ctaRow.Children.Append(
createButton("Visit NativeScript.org", function () {
openExternalUrl("https://nativescript.org");
}),
);

root.Children.Append(ctaRow);

root.Children.Append(
text("Copy the patterns from each tab to build your own native app shell.", 13),
);

console.log("NativeScriptWindowsDemo: dashboard children", safeGetChildrenSize(root));
return root;
}
Loading