diff --git a/zero/Metadata/Metadata.cs b/zero/Metadata/Metadata.cs new file mode 100644 index 00000000..246e9a57 --- /dev/null +++ b/zero/Metadata/Metadata.cs @@ -0,0 +1,24 @@ +namespace zero.Metadata; + +public class Metadata +{ + public string AppVersion { get; set; } + + public string Title { get; set; } + + public string PageName { get; set; } + + public string Description { get; set; } + + public string Image { get; set; } + + public string Robots { get; set; } + + public string Icon { get; set; } + + public string Url { get; set; } + + public string Author { get; set; } + + //public string Schema { get; set; } +} diff --git a/zero/Metadata/MetadataModule.cs b/zero/Metadata/MetadataModule.cs new file mode 100644 index 00000000..9c6d8484 --- /dev/null +++ b/zero/Metadata/MetadataModule.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace zero.Metadata; + +public class ZeroMetadataModule : ZeroModule +{ + public override void ConfigureServices(IServiceCollection services, IConfiguration configuration) + { + services.AddScoped(); + } +} \ No newline at end of file diff --git a/zero/Metadata/MetadataOptions.cs b/zero/Metadata/MetadataOptions.cs new file mode 100644 index 00000000..7c2305b7 --- /dev/null +++ b/zero/Metadata/MetadataOptions.cs @@ -0,0 +1,27 @@ +namespace zero.Metadata; + +public class MetadataOptions +{ + public List TitleFragments { get; set; } = []; + + public bool? NoIndex { get; set; } + + public bool? NoFollow { get; set; } + + public string Description { get; set; } + + public string Icon { get; set; } + + public string Image { get; set; } + + public string Author { get; set; } + + //public Schema Schema { get; set; } + + public MetadataOptions() { } + + public MetadataOptions(params string[] titleFragments) + { + TitleFragments.AddRange(titleFragments); + } +} diff --git a/zero/Metadata/MetadataService.cs b/zero/Metadata/MetadataService.cs new file mode 100644 index 00000000..b5249a98 --- /dev/null +++ b/zero/Metadata/MetadataService.cs @@ -0,0 +1,59 @@ +using Microsoft.Extensions.Logging; +using System.Reflection; + +namespace zero.Metadata; + +public class MetadataService : IMetadataService +{ + protected ILogger Logger { get; private set; } + + protected ILocalizer Localizer { get; private set; } + + + public MetadataService(ILogger logger, ILocalizer localizer) + { + Logger = logger; + Localizer = localizer; + } + + + /// + public Metadata Generate(string pageName, MetadataOptions options) + { + Metadata model = new() + { + Description = options.Description, + Icon = options.Icon, + Image = options.Image, + Author = options.Author, + PageName = pageName, + AppVersion = Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion + }; + + // generate robots + bool noIndex = options.NoIndex ?? false; + bool noFollow = options.NoFollow ?? false; + model.Robots = String.Format("{0},{1}", noIndex ? "noindex" : "index", noFollow ? "nofollow" : "follow"); + + // title + HashSet fragments = options.TitleFragments.Where(x => !x.IsNullOrWhiteSpace()).Reverse().ToHashSet(); + model.Title = !fragments.Any() ? pageName : (String.Join(" / ", fragments.Select(fragment => Localizer.Maybe(fragment))) + " / " + pageName); + + // add schema + //if (options.Schema != null) + //{ + // model.Schema = options.Schema.ToJson(); + //} + + return model; + } +} + + +public interface IMetadataService +{ + /// + /// Generates metadata. + /// + Metadata Generate(string pageName, MetadataOptions options); +} diff --git a/zero/Metadata/Schema.cs b/zero/Metadata/Schema.cs new file mode 100644 index 00000000..2046b170 --- /dev/null +++ b/zero/Metadata/Schema.cs @@ -0,0 +1,53 @@ +//using Microsoft.AspNetCore.Mvc; +//using System.Dynamic; + +//namespace zero.Metadata; + +//public class Schema +//{ +// public dynamic Model { get; private set; } + +// static JsonOptions Settings; + +// static Schema() +// { +// Settings = new JsonOptions() +// { +// Formatting = Formatting.None, +// TypeNameHandling = TypeNameHandling.None +// }; +// Settings.Converters.Add(new SchemaConverter()); +// } + + +// public Schema(string type, Action set) : this(type, false, set) { } + +// public Schema(string type, bool isRoot, Action set) +// { +// Model = new ExpandoObject(); +// var dict = Model as IDictionary; +// if (isRoot) +// { +// dict["@context"] = "https://schema.org"; +// } +// dict["@type"] = type; +// set(Model); +// } + + +// public string ToJson() => JsonConvert.SerializeObject(Model, Settings); + + +// class SchemaConverter : JsonConverter +// { +// public override void WriteJson(JsonWriter writer, Schema value, JsonSerializer serializer) +// { +// serializer.Serialize(writer, value.Model); +// } + +// public override Schema ReadJson(JsonReader reader, Type objectType, Schema existingValue, bool hasExistingValue, JsonSerializer serializer) +// { +// throw new NotImplementedException(); +// } +// } +//} \ No newline at end of file diff --git a/zero/Mvc/ZeroPageModel.cs b/zero/Mvc/ZeroPageModel.cs index 30ec39bb..20a5df52 100644 --- a/zero/Mvc/ZeroPageModel.cs +++ b/zero/Mvc/ZeroPageModel.cs @@ -1,6 +1,6 @@ -using System.Net.Mime; -using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.DependencyInjection; +using zero.Metadata; namespace zero.Mvc; @@ -17,4 +17,9 @@ public abstract class ZeroPageModel : PageModel /// public ILocalizer Localizer => _localizer ?? (_localizer = HttpContext?.RequestServices?.GetService()); ILocalizer _localizer; + + /// + /// Set metadata for this page + /// + public MetadataOptions Metadata { get; protected set; } = new(); } \ No newline at end of file diff --git a/zero/ZeroBuilder.cs b/zero/ZeroBuilder.cs index c7447631..4ff8173c 100644 --- a/zero/ZeroBuilder.cs +++ b/zero/ZeroBuilder.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using zero.Mails; +using zero.Metadata; using zero.Mvc; using zero.Numbers; using zero.Routing; @@ -60,6 +61,7 @@ public class ZeroBuilder Modules.Add(); Modules.Add(); Modules.Add(); + Modules.Add(); Modules.ConfigureServices(services, configuration);