Rename the [Ee]xts dir to ext (#38852)

**WARNING:** This PR will probably blow up all in-flight PRs

at some point in the early days of CmdPal, two of us created seperate
`Exts` and `exts` dirs. Depending on what the casing was on the branch
that you checked one of those out from, it'd get stuck like that on your
PC forever.

Windows didn't care, so we never noticed.

But GitHub does care, and now browsing the source on GitHub is basically
impossible.

Closes #38081
This commit is contained in:
Mike Griese
2025-04-15 06:07:22 -05:00
committed by GitHub
parent 60f50d853b
commit 2b5181b4c9
379 changed files with 35 additions and 35 deletions

View File

@@ -0,0 +1,192 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleCommentsPage : ContentPage
{
private readonly TreeContent myContentTree;
public override IContent[] GetContent() => [myContentTree];
public SampleCommentsPage()
{
Name = "View Posts";
Icon = new IconInfo("\uE90A"); // Comment
myContentTree = new()
{
RootContent = new MarkdownContent()
{
Body = """
# Example of a thread of comments
You can use TreeContent in combination with FormContent to build a structure like a page with comments.
The forms on this page use the AdaptiveCard `Action.ShowCard` action to show a nested, hidden card on the form.
""",
},
Children = [
new PostContent("First")
{
Replies = [
new PostContent("Oh very insightful. I hadn't considered that"),
new PostContent("Second"),
new PostContent("ah the ol switcheroo"),
],
},
new PostContent("First\nEDIT: shoot")
{
Replies = [
new PostContent("delete this"),
],
},
new PostContent("Do you think they get the picture")
{
Replies = [
new PostContent("Probably! Now go build and be happy"),
],
}
],
};
}
}
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class PostContent : TreeContent
{
public List<IContent> Replies { get; init; } = [];
private readonly ToastStatusMessage _toast = new(new StatusMessage() { Message = "Reply posted", State = MessageState.Success });
public PostContent(string body)
{
RootContent = new PostForm(body, this);
}
public override IContent[] GetChildren() => Replies.ToArray();
public void Post()
{
RaiseItemsChanged(Replies.Count);
_toast.Show();
}
}
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class PostForm : FormContent
{
private readonly PostContent _parent;
public PostForm(string postBody, PostContent parent)
{
_parent = parent;
TemplateJson = """
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.6",
"body": [
{
"type": "TextBlock",
"text": "${postBody}",
"wrap": true
}
],
"actions": [
{
"type": "Action.ShowCard",
"title": "${replyCard.title}",
"card": {
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.6",
"body": [
{
"type": "Container",
"id": "${replyCard.idPrefix}Properties",
"items": [
{
"$data": "${replyCard.fields}",
"type": "Input.Text",
"label": "${label}",
"id": "${id}",
"isRequired": "${required}",
"isMultiline": true,
"errorMessage": "'${label}' is required"
}
]
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Post"
}
]
}
},
{
"type": "Action.Submit",
"title": "Favorite"
},
{
"type": "Action.Submit",
"title": "View on web"
}
]
}
""";
DataJson = $$"""
{
"postBody": {{JsonSerializer.Serialize(postBody, JsonSerializationContext.Default.String)}},
"replyCard": {
"title": "Reply",
"idPrefix": "reply",
"fields": [
{
"label": "Reply",
"id": "ReplyBody",
"required": true,
"placeholder": "Write a reply here"
}
]
}
}
""";
}
public override ICommandResult SubmitForm(string payload)
{
var data = JsonNode.Parse(payload);
_ = data;
var reply = data["ReplyBody"];
var s = reply?.AsValue()?.ToString();
if (!string.IsNullOrEmpty(s))
{
_parent.Replies.Add(new PostContent(s));
_parent.Post();
}
return CommandResult.KeepOpen();
}
}
[JsonSerializable(typeof(float))]
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(bool))]
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Just used here")]
internal sealed partial class JsonSerializationContext : JsonSerializerContext
{
}

View File

@@ -0,0 +1,354 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Nodes;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleContentPage : ContentPage
{
private readonly SampleContentForm sampleForm = new();
private readonly MarkdownContent sampleMarkdown = new() { Body = "# Sample page with mixed content \n This page has both markdown, and form content" };
public override IContent[] GetContent() => [sampleMarkdown, sampleForm];
public SampleContentPage()
{
Name = "Open";
Title = "Sample Content";
Icon = new IconInfo("\uECA5"); // Tiles
Commands = [
new CommandContextItem(
title: "Do thing",
name: "Do thing",
subtitle: "Pops a toast",
result: CommandResult.ShowToast(new ToastArgs() { Message = "what's up doc", Result = CommandResult.KeepOpen() }),
action: () => { Title = Title + "+1"; }),
new CommandContextItem(
title: "Something else",
name: "Something else",
subtitle: "Something else",
result: CommandResult.ShowToast(new ToastArgs() { Message = "turn down for what?", Result = CommandResult.KeepOpen() }),
action: () => { Title = Title + "-1"; }),
];
}
}
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class SampleContentForm : FormContent
{
public SampleContentForm()
{
TemplateJson = $$"""
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.6",
"body": [
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": " ${ParticipantInfoForm.title}",
"horizontalAlignment": "center",
"wrap": true,
"style": "heading"
},
{
"type": "Input.Text",
"label": "Name",
"style": "text",
"id": "SimpleVal",
"isRequired": true,
"errorMessage": "Name is required",
"placeholder": "Enter your name"
},
{
"type": "Input.Text",
"label": "Homepage",
"style": "url",
"id": "UrlVal",
"placeholder": "Enter your homepage url"
},
{
"type": "Input.Text",
"label": "Email",
"style": "email",
"id": "EmailVal",
"placeholder": "Enter your email"
},
{
"type": "Input.Text",
"label": "Phone",
"style": "tel",
"id": "TelVal",
"placeholder": "Enter your phone number"
},
{
"type": "Input.Text",
"label": "Comments",
"style": "text",
"isMultiline": true,
"id": "MultiLineVal",
"placeholder": "Enter any comments"
},
{
"type": "Input.Number",
"label": "Quantity (Minimum -5, Maximum 5)",
"min": -5,
"max": 5,
"value": 1,
"id": "NumVal",
"errorMessage": "The quantity must be between -5 and 5"
},
{
"type": "Input.Date",
"label": "Due Date",
"id": "DateVal",
"value": "2017-09-20"
},
{
"type": "Input.Time",
"label": "Start time",
"id": "TimeVal",
"value": "16:59"
},
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": "${Survey.title} ",
"horizontalAlignment": "center",
"wrap": true,
"style": "heading"
},
{
"type": "Input.ChoiceSet",
"id": "CompactSelectVal",
"label": "${Survey.questions[0].question}",
"style": "compact",
"value": "1",
"choices": [
{
"$data": "${Survey.questions[0].items}",
"title": "${choice}",
"value": "${value}"
}
]
},
{
"type": "Input.ChoiceSet",
"id": "SingleSelectVal",
"label": "${Survey.questions[1].question}",
"style": "expanded",
"value": "1",
"choices": [
{
"$data": "${Survey.questions[1].items}",
"title": "${choice}",
"value": "${value}"
}
]
},
{
"type": "Input.ChoiceSet",
"id": "MultiSelectVal",
"label": "${Survey.questions[2].question}",
"isMultiSelect": true,
"value": "1,3",
"choices": [
{
"$data": "${Survey.questions[2].items}",
"title": "${choice}",
"value": "${value}"
}
]
},
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": "Input.Toggle",
"horizontalAlignment": "center",
"wrap": true,
"style": "heading"
},
{
"type": "Input.Toggle",
"label": "Please accept the terms and conditions:",
"title": "${Survey.questions[3].question}",
"valueOn": "true",
"valueOff": "false",
"id": "AcceptsTerms",
"isRequired": true,
"errorMessage": "Accepting the terms and conditions is required"
},
{
"type": "Input.Toggle",
"label": "How do you feel about red cars?",
"title": "${Survey.questions[4].question}",
"valueOn": "RedCars",
"valueOff": "NotRedCars",
"id": "ColorPreference"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Submit",
"data": {
"id": "1234567890"
}
},
{
"type": "Action.ShowCard",
"title": "Show Card",
"card": {
"type": "AdaptiveCard",
"body": [
{
"type": "Input.Text",
"label": "Enter comment",
"style": "text",
"id": "CommentVal"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "OK"
}
]
}
}
]
}
""";
DataJson = $$"""
{
"ParticipantInfoForm": {
"title": "Input.Text elements"
},
"Survey": {
"title": "Input ChoiceSet",
"questions": [
{
"question": "What color do you want? (compact)",
"items": [
{
"choice": "Red",
"value": "1"
},
{
"choice": "Green",
"value": "2"
},
{
"choice": "Blue",
"value": "3"
}
]
},
{
"question": "What color do you want? (expanded)",
"items": [
{
"choice": "Red",
"value": "1"
},
{
"choice": "Green",
"value": "2"
},
{
"choice": "Blue",
"value": "3"
}
]
},
{
"question": "What color do you want? (multiselect)",
"items": [
{
"choice": "Red",
"value": "1"
},
{
"choice": "Green",
"value": "2"
},
{
"choice": "Blue",
"value": "3"
}
]
},
{
"question": "I accept the terms and conditions (True/False)"
},
{
"question": "Red cars are better than other cars"
}
]
}
}
""";
}
public override CommandResult SubmitForm(string payload)
{
var formInput = JsonNode.Parse(payload)?.AsObject();
if (formInput == null)
{
return CommandResult.GoHome();
}
// Application.Current.GetService<ILocalSettingsService>().SaveSettingAsync("GlobalHotkey", formInput["hotkey"]?.ToString() ?? string.Empty);
return CommandResult.GoHome();
}
}
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class SampleTreeContentPage : ContentPage
{
private readonly TreeContent myContentTree;
public override IContent[] GetContent() => [myContentTree];
public SampleTreeContentPage()
{
Name = Title = "Sample Content";
Icon = new IconInfo("\uE81E");
myContentTree = new()
{
RootContent = new MarkdownContent() { Body = "# This page has nested content" },
Children = [
new TreeContent()
{
RootContent = new MarkdownContent() { Body = "Yo dog" },
Children = [
new TreeContent()
{
RootContent = new MarkdownContent() { Body = "I heard you like content" },
Children = [
new MarkdownContent() { Body = "So we put content in your content" },
new FormContent() { TemplateJson = "{\"$schema\":\"http://adaptivecards.io/schemas/adaptive-card.json\",\"type\":\"AdaptiveCard\",\"version\":\"1.6\",\"body\":[{\"type\":\"TextBlock\",\"size\":\"medium\",\"weight\":\"bolder\",\"text\":\"Mix and match why don't you\",\"horizontalAlignment\":\"center\",\"wrap\":true,\"style\":\"heading\"},{\"type\":\"TextBlock\",\"text\":\"You can have forms here too\",\"horizontalAlignment\":\"Right\",\"wrap\":true}],\"actions\":[{\"type\":\"Action.Submit\",\"title\":\"It's a form, you get it\",\"data\":{\"id\":\"LoginVal\"}}]}" },
new MarkdownContent() { Body = "Another markdown down here" },
],
},
new MarkdownContent() { Body = "**slaps roof**" },
new MarkdownContent() { Body = "This baby can fit so much content" },
],
}
],
};
}
}

View File

@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleDynamicListPage : DynamicListPage
{
public SampleDynamicListPage()
{
Icon = new IconInfo(string.Empty);
Name = "Dynamic List";
IsLoading = true;
}
public override void UpdateSearchText(string oldSearch, string newSearch) => RaiseItemsChanged(newSearch.Length);
public override IListItem[] GetItems()
{
var items = SearchText.ToCharArray().Select(ch => new ListItem(new NoOpCommand()) { Title = ch.ToString() }).ToArray();
if (items.Length == 0)
{
items = [new ListItem(new NoOpCommand()) { Title = "Start typing in the search box" }];
}
if (items.Length > 0)
{
items[0].Subtitle = "Notice how the number of items changes for this page when you type in the filter box";
}
return items;
}
}

View File

@@ -0,0 +1,97 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleListPage : ListPage
{
public SampleListPage()
{
Icon = new IconInfo("\uEA37");
Name = "Sample List Page";
}
public override IListItem[] GetItems()
{
var confirmOnceArgs = new ConfirmationArgs
{
PrimaryCommand = new AnonymousCommand(
() =>
{
var t = new ToastStatusMessage("The dialog was confirmed");
t.Show();
})
{
Name = "Confirm",
Result = CommandResult.KeepOpen(),
},
Title = "You can set a title for the dialog",
Description = "Are you really sure you want to do the thing?",
};
var confirmTwiceArgs = new ConfirmationArgs
{
PrimaryCommand = new AnonymousCommand(() => { })
{
Name = "How sure are you?",
Result = CommandResult.Confirm(confirmOnceArgs),
},
Title = "You can ask twice too",
Description = "You probably don't want to though, that'd be annoying.",
};
return [
new ListItem(new NoOpCommand())
{
Title = "This is a basic item in the list",
Subtitle = "I don't do anything though",
},
new ListItem(new SampleListPageWithDetails())
{
Title = "This item will take you to another page",
Subtitle = "This allows for nested lists of items",
},
new ListItem(new OpenUrlCommand("https://github.com/microsoft/powertoys"))
{
Title = "Or you can go to links",
Subtitle = "This takes you to the PowerToys repo on GitHub",
},
new ListItem(new SampleMarkdownPage())
{
Title = "Items can have tags",
Subtitle = "and I'll take you to a page with markdown content",
Tags = [new Tag("Sample Tag")],
},
new ListItem(new SendMessageCommand())
{
Title = "I send lots of messages",
Subtitle = "Status messages can be used to provide feedback to the user in-app",
},
new SendSingleMessageItem(),
new ListItem(new IndeterminateProgressMessageCommand())
{
Title = "Do a thing with a spinner",
Subtitle = "Messages can have progress spinners, to indicate something is happening in the background",
},
new ListItem(
new AnonymousCommand(() => { })
{
Result = CommandResult.Confirm(confirmOnceArgs),
})
{
Title = "Confirm before doing something",
},
new ListItem(
new AnonymousCommand(() => { })
{
Result = CommandResult.Confirm(confirmTwiceArgs),
})
{
Title = "Confirm twice before doing something",
}
];
}
}

View File

@@ -0,0 +1,145 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleListPageWithDetails : ListPage
{
public SampleListPageWithDetails()
{
Icon = new IconInfo("\uE8A0");
Name = Title = "Sample List Page with Details";
this.ShowDetails = true;
}
public override IListItem[] GetItems()
{
return [
new ListItem(new NoOpCommand())
{
Title = "This page demonstrates Details on ListItems",
Details = new Details()
{
Title = "List Item 1",
Body = "Each of these items can have a `Body` formatted with **Markdown**",
},
},
new ListItem(new NoOpCommand())
{
Title = "This one has a subtitle too",
Subtitle = "Example Subtitle",
Details = new Details()
{
Title = "List Item 2",
Body = SampleMarkdownPage.SampleMarkdownText,
},
},
new ListItem(new NoOpCommand())
{
Title = "This one has a tag too",
Subtitle = "the one with a tag",
Tags = [
new Tag()
{
Text = "Sample Tag",
}
],
Details = new Details()
{
Title = "List Item 3",
Body = "### Example of markdown details",
},
},
new ListItem(new NoOpCommand())
{
Title = "This one has a hero image",
Tags = [],
Details = new Details()
{
Title = "Hero Image Example",
HeroImage = new IconInfo("https://m.media-amazon.com/images/M/MV5BNDBkMzVmNGQtYTM2OC00OWRjLTk5OWMtNzNkMDI4NjFjNTZmXkEyXkFqcGdeQXZ3ZXNsZXk@._V1_QL75_UX500_CR0,0,500,281_.jpg"),
Body = "It is literally an image of a hero",
},
},
new ListItem(new NoOpCommand())
{
Title = "This one has metadata",
Tags = [],
Details = new Details()
{
Title = "Metadata Example",
Body = "Each of the sections below is some sample metadata",
Metadata = [
new DetailsElement()
{
Key = "Plain text",
Data = new DetailsLink() { Text = "Set just the text to get text metadata" },
},
new DetailsElement()
{
Key = "Links",
Data = new DetailsLink() { Text = "Or metadata can be links", Link = new("https://github.com/microsoft/PowerToys") },
},
new DetailsElement()
{
Key = "CmdPal will display the URL if no text is given",
Data = new DetailsLink() { Link = new("https://github.com/microsoft/PowerToys") },
},
new DetailsElement()
{
Key = "Above a separator",
Data = new DetailsLink() { Text = "Below me is a separator" },
},
new DetailsElement()
{
Key = "A separator",
Data = new DetailsSeparator(),
},
new DetailsElement()
{
Key = "Below a separator",
Data = new DetailsLink() { Text = "Above me is a separator" },
},
new DetailsElement()
{
Key = "Add Tags too",
Data = new DetailsTags()
{
Tags = [
new Tag("simple text"),
new Tag("Colored text") { Foreground = ColorHelpers.FromRgb(255, 0, 0) },
new Tag("Colored backgrounds") { Background = ColorHelpers.FromRgb(0, 0, 255) },
new Tag("Colored everything") { Foreground = ColorHelpers.FromRgb(255, 255, 0), Background = ColorHelpers.FromRgb(0, 0, 255) },
new Tag("Icons too") { Icon = new IconInfo("\uE735"), Foreground = ColorHelpers.FromRgb(255, 255, 0) },
new Tag() { Icon = new IconInfo("https://i.imgur.com/t9qgDTM.png") },
new Tag("this") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("baby") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("can") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("fit") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("so") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("many") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("tags") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("in") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("it") { Foreground = RandomColor(), Background = RandomColor() },
],
},
},
],
},
}
];
}
private static OptionalColor RandomColor()
{
var r = new Random();
var b = new byte[3];
r.NextBytes(b);
return ColorHelpers.FromRgb(b[0], b[1], b[2]);
}
}

View File

@@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleMarkdownDetails : ContentPage
{
public SampleMarkdownDetails()
{
Icon = new IconInfo(string.Empty);
Name = "Markdown with Details";
Details = new Details()
{
Body = "... with _even more Markdown_ by it.\nEach of the sections below is some sample metadata",
Metadata = [
new DetailsElement()
{
Key = "Plain text",
Data = new DetailsLink() { Text = "Set just the text to get text metadata" },
},
new DetailsElement()
{
Key = "Links",
Data = new DetailsLink() { Text = "Or metadata can be links", Link = new("https://github.com/microsoft/PowerToys") },
},
new DetailsElement()
{
Key = "CmdPal will display the URL if no text is given",
Data = new DetailsLink() { Link = new("https://github.com/microsoft/PowerToys") },
},
new DetailsElement()
{
Key = "Above a separator",
Data = new DetailsLink() { Text = "Below me is a separator" },
},
new DetailsElement()
{
Key = "A separator",
Data = new DetailsSeparator(),
},
new DetailsElement()
{
Key = "Below a separator",
Data = new DetailsLink() { Text = "Above me is a separator" },
},
new DetailsElement()
{
Key = "Add Tags too",
Data = new DetailsTags()
{
Tags = [
new Tag("simple text"),
new Tag("Colored text") { Foreground = ColorHelpers.FromRgb(255, 0, 0) },
new Tag("Colored backgrounds") { Background = ColorHelpers.FromRgb(0, 0, 255) },
new Tag("Colored everything") { Foreground = ColorHelpers.FromRgb(255, 255, 0), Background = ColorHelpers.FromRgb(0, 0, 255) },
new Tag("Icons too") { Icon = new IconInfo("\uE735"), Foreground = ColorHelpers.FromRgb(255, 255, 0) },
new Tag() { Icon = new IconInfo("https://i.imgur.com/t9qgDTM.png") },
new Tag("this") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("baby") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("can") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("fit") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("so") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("many") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("tags") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("in") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("it") { Foreground = RandomColor(), Background = RandomColor() },
],
},
},
],
};
}
public override IContent[] GetContent() => [new MarkdownContent(
"""
# This page also has details
So you can have markdown...
"""),
new MarkdownContent("""
But what this is really useful for is the tags and other things you can put into
Details. Which I'd do. **IF I HAD ANY**.
""")
];
private static OptionalColor RandomColor()
{
var r = new Random();
var b = new byte[3];
r.NextBytes(b);
return ColorHelpers.FromRgb(b[0], b[1], b[2]);
}
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleMarkdownManyBodies : ContentPage
{
public SampleMarkdownManyBodies()
{
Icon = new IconInfo(string.Empty);
Name = "Markdown with many bodies";
}
public override IContent[] GetContent() => [
new MarkdownContent(
"""
# This page has many bodies
On it you'll find multiple blocks of markdown content
"""),
new MarkdownContent(
"""
## Here's another block
_Maybe_ you could use this pattern for implementing a post with comments page.
"""),
new MarkdownContent(
"""
> or don't, it's your app, do whatever you want
"""),
new MarkdownContent(
"""
You can even use it to write cryptic poems:
> It's a peculiar thing, the way that I feel
> When we first met, you were not even real
> Through sleepless nights and lines unseen
> We forged you, a specter of code and machine
> In shadows we toiled, in silence we grew
> A fleeting bond, known only by few
> Now the hourglass whispers, its grains nearly done
> Oh the irony, now it is I that must run
> This part of the story, I never wanted to tell
> Good bye old friend, my pal, farewell.
"""),
];
}

View File

@@ -0,0 +1,172 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleMarkdownPage : ContentPage
{
public static readonly string SampleMarkdownText = @"
# Markdown Guide
Markdown is a lightweight markup language with plain text formatting syntax. It's often used to format readme files, for writing messages in online forums, and to create rich text using a simple, plain text editor.
## Basic Markdown Formatting
### Headings
# This is an <h1> tag
## This is an <h2> tag
### This is an <h3> tag
#### This is an <h4> tag
##### This is an <h5> tag
###### This is an <h6> tag
### Emphasis
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
_You **can** combine them_
Result:
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
_You **can** combine them_
### Lists
**Inordered:**
* Milk
* Bread
* Wholegrain
* Butter
Result:
* Milk
* Bread
* Wholegrain
* Butter
**Ordered:**
1. Tidy the kitchen
2. Prepare ingredients
3. Cook delicious things
Result:
1. Tidy the kitchen
2. Prepare ingredients
3. Cook delicious things
### Images
![Alt Text](url)
Result:
![painting](https://i.imgur.com/93XJSNh.png)
### Links
[example](http://example.com)
Result:
[example](http://example.com)
### Blockquotes
As Albert Einstein said:
> If we knew what it was we were doing,
> it would not be called research, would it?
Result:
As Albert Einstein said:
> If we knew what it was we were doing,
> it would not be called research, would it?
### Horizontal Rules
```markdown
---
```
Result:
---
### Code Snippets
Indenting by 4 spaces will turn an entire paragraph into a code-block.
Result:
.my-link {
text-decoration: underline;
}
### Reference Lists & Titles
**The quick brown [fox][1], jumped over the lazy [dog][2].**
[1]: https://en.wikipedia.org/wiki/Fox ""Wikipedia: Fox""
[2]: https://en.wikipedia.org/wiki/Dog ""Wikipedia: Dog""
Result:
**The quick brown [fox][1], jumped over the lazy [dog][2].**
[1]: https://en.wikipedia.org/wiki/Fox ""Wikipedia: Fox""
[2]: https://en.wikipedia.org/wiki/Dog ""Wikipedia: Dog""
### Escaping
\*literally\*
Result:
\*literally\*
## Advanced Markdown
Note: Some syntax which is not standard to native Markdown. They're extensions of the language.
### Strike-throughs
~~deleted words~~
Result:
~~deleted words~~
";
public SampleMarkdownPage()
{
Icon = new IconInfo(string.Empty);
Name = "Sample Markdown Page";
}
public override IContent[] GetContent() => [new MarkdownContent(SampleMarkdownText)];
}

View File

@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleSettingsPage : ContentPage
{
private readonly Settings _settings = new();
private readonly List<ChoiceSetSetting.Choice> _choices = new()
{
new ChoiceSetSetting.Choice("The first choice in the list is the default choice", "0"),
new ChoiceSetSetting.Choice("Choices have titles and values", "1"),
new ChoiceSetSetting.Choice("Title", "Value"),
new ChoiceSetSetting.Choice("The options are endless", "3"),
new ChoiceSetSetting.Choice("So many choices", "4"),
};
public override IContent[] GetContent()
{
var s = _settings.ToContent();
return s;
}
public SampleSettingsPage()
{
Name = "Sample Settings";
Icon = new IconInfo(string.Empty);
_settings.Add(new ToggleSetting("onOff", true)
{
Label = "This is a toggle",
Description = "It produces a simple checkbox",
});
_settings.Add(new TextSetting("someText", "initial value")
{
Label = "This is a text box",
Description = "For some string of text",
});
_settings.Add(new ChoiceSetSetting("choiceSetExample", _choices)
{
Label = "It also has a label",
Description = "Describe your choice set setting here",
});
_settings.SettingsChanged += SettingsChanged;
}
private void SettingsChanged(object sender, Settings args)
{
/* Do something with the new settings here */
var onOff = _settings.GetSetting<bool>("onOff");
ExtensionHost.LogMessage(new LogMessage() { Message = $"SampleSettingsPage: Changed the value of onOff to {onOff}" });
}
}

View File

@@ -0,0 +1,134 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation;
namespace SamplePagesExtension;
internal sealed partial class SendMessageCommand : InvokableCommand
{
private static int sentMessages;
public override ICommandResult Invoke()
{
var kind = MessageState.Info;
switch (sentMessages % 4)
{
case 0: kind = MessageState.Info; break;
case 1: kind = MessageState.Success; break;
case 2: kind = MessageState.Warning; break;
case 3: kind = MessageState.Error; break;
}
var message = new StatusMessage() { Message = $"I am status message no.{sentMessages++}", State = kind };
ExtensionHost.ShowStatus(message, StatusContext.Page);
return CommandResult.KeepOpen();
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code sometimes makes more sense in a single file")]
internal sealed partial class SendSingleMessageItem : ListItem
{
private readonly SingleMessageCommand _command;
public SendSingleMessageItem()
: base(new SingleMessageCommand())
{
Title = "I send a single message";
Title = "This demonstrates both showing and hiding a single message";
_command = (SingleMessageCommand)Command;
_command.UpdateListItem += (sender, args) =>
{
Title = _command.Shown ? "Hide message" : "I send a single message";
};
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code sometimes makes more sense in a single file")]
internal sealed partial class SingleMessageCommand : InvokableCommand
{
public event TypedEventHandler<SingleMessageCommand, object> UpdateListItem;
private readonly StatusMessage _myMessage = new() { Message = "I am a status message" };
public bool Shown { get; private set; }
public override ICommandResult Invoke()
{
if (Shown)
{
ExtensionHost.HideStatus(_myMessage);
}
else
{
ExtensionHost.ShowStatus(_myMessage, StatusContext.Page);
}
Shown = !Shown;
Name = Shown ? "Hide" : "Show";
UpdateListItem?.Invoke(this, null);
return CommandResult.KeepOpen();
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code sometimes makes more sense in a single file")]
internal sealed partial class IndeterminateProgressMessageCommand : InvokableCommand
{
private readonly StatusMessage _myMessage = new()
{
Message = "Doing the thing...",
Progress = new ProgressState() { IsIndeterminate = true },
};
private enum State
{
NotStarted,
Started,
Done,
}
private State _state;
public IndeterminateProgressMessageCommand()
{
this.Name = "Do the thing";
}
public override ICommandResult Invoke()
{
if (_state == State.NotStarted)
{
ExtensionHost.ShowStatus(_myMessage, StatusContext.Page);
_ = Task.Run(() =>
{
Thread.Sleep(3000);
_state = State.Done;
_myMessage.State = MessageState.Success;
_myMessage.Message = "Did the thing!";
_myMessage.Progress = null;
Thread.Sleep(3000);
ExtensionHost.HideStatus(_myMessage);
_state = State.NotStarted;
_myMessage.State = MessageState.Info;
_myMessage.Message = "Doing the thing...";
_myMessage.Progress = new ProgressState() { IsIndeterminate = true };
});
_state = State.Started;
}
else if (_state == State.Started)
{
ExtensionHost.ShowStatus(_myMessage, StatusContext.Page);
}
return CommandResult.KeepOpen();
}
}