├── 01 - Installation.md ├── 02 - Configuration.md ├── 03 - Template Usage.md ├── 04 - Patterns and Anti-patterns.md ├── 05 - Deserialize Archetype.md ├── 06 - Editing an Archetype in Code.md ├── README.md └── assets ├── archetype.png ├── config.png ├── cross-drag.gif ├── label-template.png ├── nuget.png ├── package.png └── sliders.png /01 - Installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Installation is a breeze, the preferred way to install Archetype is via Nuget (https://www.nuget.org/packages/Archetype/). 4 | 5 | Type: `install-package archetype` in your Visual Studio NuGet Package Manager. 6 | 7 | ![nuget](assets/nuget.png) 8 | 9 | The other way is to use the normal Umbraco Package install method with the download found here: https://our.umbraco.org/projects/backoffice-extensions/archetype 10 | 11 | ![package](assets/package.png) 12 | 13 | If you just want the binaries and none of the frontend stuff: 14 | 15 | Type: `install-package Archetype.Binaries` in your Visual Studio NuGet Package Manager. 16 | 17 | https://www.nuget.org/packages/Archetype.Binaries/ 18 | 19 | ## Courier 20 | @leekelleher has gratiously donated his time to make a Courier extension to use Archetype with Umbraco as a Service (UaaS). You can install it here: https://www.nuget.org/packages/archetype.courier 21 | -------------------------------------------------------------------------------- /02 - Configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | Configuration can seem daunting, but to create your first Archetype, do the the following: 4 | 5 | * Navigate to `Developer->Data Type` 6 | * Right click and create a new data type. 7 | * Select `Archetype` from the dropdown. 8 | * Name your fieldset 9 | * Give your fieldset an alias (or accept the default) 10 | * Add one or more properties 11 | * Each property needs a name, an alias and a data type 12 | 13 | That is all that is required. 14 | 15 | ![config](assets/config.png) 16 | 17 | Tick the `Toggle Advanced Options` box to expose advanced options. 18 | 19 | ## Add to a Document Type 20 | Once configured, navigate to `Settings->Document Types` and add the new data type to a document type. 21 | 22 | ## Multiple Fieldsets 23 | 24 | You can enable multiple fieldsets in a single Archetype by going into the advanced options and ticking `Enable Multiple Fieldsets?`. 25 | 26 | This will expose a hidden plus sign that allows that you'll need to click to add another fieldset type. It also allows you to choose an installed icon to separate the two types visually once added to a document type. 27 | 28 | ## Nested Archetypes 29 | 30 | You can nest Archetypes within Archetypes; they can even reference themselves (supposing you also start with the add button to avoid infinite nesting). 31 | 32 | ## Cross-Archetype Dragging 33 | 34 | To allow for Archetype fieldsets to be dragged between Umbraco properties and into/out of nested Archetypes, check the "Enabled Cross-Archetype Dragging" configuration option. 35 | 36 | Once enabled, you will be able to drag compatible Archetype fieldsets to other Archetypes, whether they are entirely different properties or they are nested Archetypes: 37 | 38 | ![Cross-Archetype Dragging Example Animation](assets/cross-drag.gif) 39 | 40 | ## Label Template 41 | 42 | You can configure Archetype to show a value from inside your Archetype to be shown on the collapsed fieldset title. 43 | 44 | Typically you would use this syntax in the `Label Template` box: `{{propertyName}}`. 45 | 46 | You can pass in a custom function into the label with the following syntax `{{myFunction(propertyName)}}`. 47 | 48 | You can pass args to your label template too, please keep reading thru the examples if interested. 49 | 50 | Make sure your function is available to Umbraco by adding your custom code to a package manifest. 51 | 52 | ### Promises and Dependency Injection in Label Templates 53 | 54 | Starting with Archetype 1.16.0, you can create label template functions that return promises and that support injection of AngularJS dependencies. This comes in handy for more advanced scenarios, such as when you need to perform asynchronous operations like getting data from the web server. 55 | 56 | In most instances where you would use a promise, you will also want to inject an AngularJS dependency that has a function that returns a promise. So, you'll first want to know how to have dependencies injected. You can do so like this: 57 | 58 | ```js 59 | function archetypeGetNodeUrl(value) { 60 | return function (contentResource) { 61 | /* Your code here. */ 62 | }; 63 | } 64 | ``` 65 | 66 | That will allow you to inject the `contentResource` service. All you need to do in order to have a dependency injected is return a function with that dependency as one of the parameters. 67 | 68 | Taking this example further, you could then return a promise from the function: 69 | 70 | ```js 71 | function archetypeGetNodeUrl(value) { 72 | return function (contentResource) { 73 | if (!value) { 74 | return "Unknown URL"; 75 | } 76 | return contentResource.getById(value) 77 | .then(function (response) { 78 | return response.urls[0] || "Unknown URL"; 79 | }); 80 | }; 81 | } 82 | ``` 83 | 84 | You will likely want to add some caching so subsequent requests to your function don't initiate server-side calls every time it is called. Here's an example of how you might go about that: 85 | 86 | ```js 87 | function archetypeGetNodeUrl(value) { 88 | return function (contentResource) { 89 | if (!value) { 90 | return "Unknown URL"; 91 | } 92 | archetypeGetNodeUrl.cache = archetypeGetNodeUrl.cache || {}; 93 | if (archetypeGetNodeUrl.cache[value]) { 94 | return archetypeGetNodeUrl.cache[value]; 95 | } 96 | return contentResource.getById(value) 97 | .then(function (response) { 98 | archetypeGetNodeUrl.cache[value] = response.urls[0] || "Unknown URL"; 99 | return archetypeGetNodeUrl.cache[value]; 100 | }); 101 | }; 102 | } 103 | ``` 104 | 105 | The above code can also be rewritten like so and it would function the same way, though perhaps slightly faster: 106 | 107 | ```js 108 | function archetypeGetNodeUrl(value) { 109 | if (!value) { 110 | return "Unknown URL"; 111 | } 112 | archetypeGetNodeUrl.cache = archetypeGetNodeUrl.cache || {}; 113 | if (archetypeGetNodeUrl.cache[value]) { 114 | return archetypeGetNodeUrl.cache[value]; 115 | } 116 | return function (contentResource) { 117 | return contentResource.getById(value) 118 | .then(function (response) { 119 | archetypeGetNodeUrl.cache[value] = response.urls[0] || "Unknown URL"; 120 | return archetypeGetNodeUrl.cache[value]; 121 | }); 122 | }; 123 | } 124 | ``` 125 | 126 | This demonstrates that you can return different types of objects from your function at different times. In the case of a cache hit, this will return a string. In the case of a cache miss, this will return a function that will return a promise that will resolve to a string. 127 | 128 | Here is a heavily commented version of the above function, which should help you to understand what each line is doing: 129 | 130 | ```js 131 | /** 132 | * This function will be called from an Archetype label template, and it will eventually 133 | * resolve to a string that is the URL of the supplied content node ID. 134 | * @param value The content node ID. 135 | * @returns {*} A string or a function. In the case of a function, it will be called and 136 | * will subsequently return a promise. That promise will then eventually resolve to 137 | * a string value. 138 | */ 139 | function archetypeGetNodeUrl(value) { 140 | 141 | // If the supplied value is falsy (e.g., null or undefined), return early. 142 | if (!value) { 143 | return "Unknown URL"; 144 | } 145 | 146 | // Ensure the cache has been initialized. 147 | archetypeGetNodeUrl.cache = archetypeGetNodeUrl.cache || {}; 148 | 149 | // If the node is already in the cache, return the URL from the cache. 150 | if (archetypeGetNodeUrl.cache[value]) { 151 | return archetypeGetNodeUrl.cache[value]; 152 | } 153 | 154 | // Return a function that will be called and have its dependencies injected. 155 | return function (contentResource) { 156 | 157 | // Call Umbraco's contentResource service. Specifically, the getById function, 158 | // which will return information about a content node by its ID. This will return 159 | // a JavaScript promise. 160 | return contentResource.getById(value) 161 | // Now that getById has returned a promise, we will process the result of that 162 | // promise and return yet another promise that will eventually resolve to a 163 | // string. 164 | .then(function (response) { 165 | 166 | // Store the URL to the cache, then return it. 167 | archetypeGetNodeUrl.cache[value] = response.urls[0] || "Unknown URL"; 168 | return archetypeGetNodeUrl.cache[value]; 169 | 170 | }); 171 | }; 172 | 173 | } 174 | ``` 175 | 176 | ### Addtional Samples 177 | ```js 178 | //create a namespace (optional) 179 | var ArchetypeSampleLabelHelpers = {}; 180 | 181 | //create a function 182 | //you will add it to your label template field as `{{ArchetypeSampleLabelHelpers.testPromise(someArchetypePropertyAlias)}}` 183 | ArchetypeSampleLabelHelpers.testPromise = function(value) { 184 | //you can inject services 185 | return function ($timeout, archetypeCacheService) { 186 | //best to return a promise 187 | //NOTE: $timeout returns a promise 188 | return $timeout(function () { 189 | return "As Promised: " + value; 190 | }, 1000); 191 | } 192 | } 193 | 194 | ArchetypeSampleLabelHelpers.testEntityPromise = function(value, scope, args) { 195 | //hey look, args! 196 | //{{ArchetypeSampleLabelHelpers.testEntityPromise(someArchetypePropertyAlias, {foo: 1})}} 197 | console.log(args); 198 | 199 | return function ($q, entityResource) { 200 | var deferred = $q.defer(); 201 | 202 | entityResource.getById(args.foo, 'document').then(function(entity) { 203 | console.log("Hello from testEntityPromise"); 204 | console.log(entity); 205 | deferred.resolve(entity.name); 206 | }); 207 | 208 | return deferred.promise; 209 | } 210 | } 211 | 212 | ArchetypeSampleLabelHelpers.testEntityPromise2 = function(value, scope, args) { 213 | //hey look, args but we're also using the built-in archetypeCacheService 214 | //{{ArchetypeSampleLabelHelpers.testEntityPromise(someArchetypePropertyAlias, {foo: 1234})}} 215 | console.log(args); 216 | 217 | return function ($q, archetypeCacheService) { 218 | var deferred = $q.defer(); 219 | 220 | archetypeCacheService.getEntityById(args.foo, 'document').then(function(entity) { 221 | console.log("Hello from testEntityPromise2"); 222 | console.log(entity); 223 | deferred.resolve(entity.name); 224 | }); 225 | 226 | return deferred.promise; 227 | } 228 | } 229 | ``` 230 | 231 | ## Change the Style of Archetype in the Backoffice 232 | Archetype allows you to do the following to customize the backoffice experience for your editors: 233 | 234 | * Modify the view globally 235 | * Modify the view per Archetype data type instance 236 | * Modify the CSS globally 237 | * Modify the CSS per Archetype data type instance 238 | * Add a JS script globally 239 | * Add a class name to an Archetype 240 | 241 | ### Global Changes 242 | To make global changes, simply edit any of these files: 243 | 244 | * Any file located in: `~/App_Plugins/Archetype/views/` 245 | * `~/App_Plugins/Archetype/css/archetype.css` 246 | 247 | >Modifying these files will alter the look and feel of Archetype globally, however this is the same as modifying the core of Archetype and you'll have to make these changes after each upgrade to the next version of Archetype. 248 | 249 | ### Per Data Type Instance 250 | Archetype will allow you to also change the look and feel on a per data type basis as defined below: 251 | 252 | * You can completely swap out the default view with another one. Navigate to `Developer>Data Types` and select your Archetype. Update the configuration property `View File` with a path to your new view file. v7.3+ users will find this under the `Custom Style/Script Options`. It's easiest to start with a copy of the `~/App_Plugins/Archetype/Views/archetype.default.html` file, make your changes and save it as a new view. Just remember to point your Archetype to the new view. 253 | * Next you can add CSS and JS conditionally to a page. Since Umbraco is a pretty much a single page app, you can inject a CSS and/or a JS file by simply specifying a path to a CSS or JS file in the Archetype configuration. Again v7.3+ users will find this under the `Custom Style/Script Options`. 254 | * Lastly, you can also quickly add a class to an Archetype for styling or JS purposes by specifying the `Custom Wrapper Class` field in the configuration. This can be used in conjunction with either the JS or CSS file options. 255 | 256 | >Note that these changes are resistant to upgrades of Archetype and will be kept without any worries unlike the global changes in the previous section. 257 | -------------------------------------------------------------------------------- /03 - Template Usage.md: -------------------------------------------------------------------------------- 1 | # Template Usage 2 | 3 | Getting the data out of Archetype is easy. Consider the following: 4 | 5 | ``` 6 | @inherits Umbraco.Web.Mvc.UmbracoTemplatePage 7 | @using Archetype.Models; 8 | @using Archetype.Extensions; 9 | @{ 10 | Layout = null; 11 | } 12 | 13 | //use case #1 - Covers a single Archetype 14 | @foreach (var fieldset in Model.Content.GetPropertyValue("a1")) 15 | { 16 | 17 |
@fieldset.GetValue("mntp")
18 | 19 | 20 | 21 | 22 |
@fieldset.GetValue>("mntp")
23 | } 24 | 25 | //use case #2 - Covers nested Archetypes 26 | @foreach (var fieldset in Model.Content.GetPropertyValue("a1")) 27 | { 28 |
@fieldset.GetValue("firstName")
29 | 30 | 31 | foreach(var nestedFs in fieldset.GetValue("movieList")){ 32 |

@nestedFs.GetValue("title")

33 |
@nestedFs.GetValue("text")
34 | } 35 | } 36 | 37 | //use case #3; be able to iterate over the properties, however this will not pass value through converters 38 | @foreach (var fieldset in Model.Content.GetPropertyValue("a1")) 39 | { 40 | 41 | foreach (var prop in fieldset.Properties) 42 | { 43 |
@prop.Value
44 | } 45 | } 46 | ``` 47 | 48 | ## Page Builder 49 | You can even render partials based on the alias of the fieldset easily. If you have an Archetype that has more than one fieldset configured with aliases of `RichtextModule` and `GalleryModule`, then you can render them dynamically with one line of code: 50 | 51 | `@Html.RenderArchetypePartials(Model.Content.GetPropertyValue("modules"))` 52 | 53 | >This example assumes you named your property `modules` on your document type. 54 | 55 | Each partial would have to be defined in the `~/Views/Partials/Archetype` folder like so: 56 | 57 | ``` 58 | @* File ~/Views/Partials/Archetype/RichtextModule.cshtml *@ 59 | @inherits Umbraco.Web.Mvc.UmbracoViewPage 60 | @using Archetype.Models; 61 | 62 |
63 |
64 | @Html.Raw(Model.GetValue("text")) 65 |
66 |
67 | ``` 68 | 69 | ``` 70 | @* File ~/Views/Partials/Archetype/GalleryModule.cshtml *@ 71 | @inherits Umbraco.Web.Mvc.UmbracoViewPage 72 | @using Archetype.Models; 73 | 74 |
75 |
76 | 77 |
78 |
79 | ``` 80 | 81 | 82 | 83 | The next snippet is the final template: 84 | 85 | ``` 86 | @using Archetype.Extensions 87 | @using Archetype.Models 88 | @using MyNamespace.UmbracoExtensions.BizMag.Models 89 | @inherits Umbraco.Web.Mvc.UmbracoTemplatePage 90 | @{ 91 | Layout = "~/Views/BizMag/BizmagBase.cshtml"; 92 | } 93 | 94 | 95 |
96 | 97 |
98 |
99 | @Html.Partial("~/Views/BizMag/Partials/Breadcrumbs.cshtml") 100 |
101 |
102 |
103 |
104 |

@Model.Content.Name

105 |
106 |
107 |
108 | 109 | 110 |
111 | 112 | @* this will read the entire archetype and render a partial named the same as the fieldset alias *@ 113 | 114 | @Html.RenderArchetypePartials(Model.Content.GetPropertyValue("modules")) 115 | 116 | @Html.Partial("~/Views/BizMag/Partials/ContactForm.cshtml", new ContactUsModel()) 117 | 118 |
119 | 120 | 121 |
122 | 123 |
124 | @Html.Partial("~/Views/BizMag/Partials/Archives.cshtml") 125 |
126 | 127 |
128 | 129 |
130 | 131 |
132 | ``` 133 | -------------------------------------------------------------------------------- /04 - Patterns and Anti-patterns.md: -------------------------------------------------------------------------------- 1 | # Patterns and Anti-patterns 2 | 3 | * Do use Archetype when needing to group data together when you don't want to use the common Multinode Tree Picker pattern. 4 | * Do use the built-in property value conversions by getting your data like so: 5 | 6 | ``` 7 | @foreach(var fieldset in Model.Content.GetPropertyValue("myProperty")) 8 | { 9 |

@fieldset.GetValue("headlineProperty")

10 | } 11 | ``` 12 | * Do take care that if you use label template functions, they need to be super efficient since they may get called dozens of times. 13 | * Don't architect your data to rely solely on Archetype. i.e Don't plan to add 100 things to an Archetype. This will cause editor frustration and cause performance issues. 14 | * Don't overuse Archetype, if you can use core data types, you probably should. 15 | * Don't nest Archetypes more that one level deep. It makes it a pain for an editor to have to drill down. 16 | -------------------------------------------------------------------------------- /05 - Deserialize Archetype.md: -------------------------------------------------------------------------------- 1 | # Deserialize Archetype 2 | 3 | Often you may find yourself needing to work with the individual data in code. The following example shows how to deserialize an Archetype from `IContent`: 4 | 5 | ``` 6 | using Archetype.Models; 7 | using Newtonsoft.Json; 8 | using Umbraco.Core; 9 | 10 | namespace MyNamespace 11 | { 12 | public class MyClass 13 | { 14 | public void MyMethod() 15 | { 16 | var contentService = ApplicationContext.Current.Services.ContentService; 17 | 18 | var archetypeValueAsString = contentService.GetById(1234).GetValue("myArchetypeProperty"); 19 | 20 | var archetype = JsonConvert.DeserializeObject (archetypeValueAsString); 21 | 22 | foreach (var fieldset in archetype) 23 | { 24 | var value = fieldset.GetValue("text"); 25 | } 26 | } 27 | } 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /06 - Editing an Archetype in Code.md: -------------------------------------------------------------------------------- 1 | # Editing an Archetype in Code 2 | 3 | Often times you may want to edit an Archetype or create a new one altogether. The following example illustrates how to retrieve an Archetype from `ContentService`, edit it and save it back. 4 | 5 | ```c# 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using Archetype.Models; 9 | using Newtonsoft.Json; 10 | using Umbraco.Core; 11 | 12 | namespace MyApp 13 | { 14 | public class MyClass 15 | { 16 | public void MyMethod() 17 | { 18 | //get a ref to services 19 | var services = ApplicationContext.Current.Services; 20 | 21 | //get a reference to the current content if an edit (or create a new node instead) 22 | var content = services.ContentService.GetById(1234); 23 | 24 | var currentArchetypeJson = content.GetValue("myDoctypeAliasForArchetypeProperty"); 25 | 26 | //deserialize into an Archetype 27 | var myArchetype = JsonConvert.DeserializeObject(currentArchetypeJson); 28 | 29 | //get the current fieldsets 30 | var currentFieldsets = new List(); 31 | currentFieldsets = myArchetype.Fieldsets.ToList(); 32 | 33 | //edit some of the fieldsets or properties if you want 34 | var someCurrentFieldsets = currentFieldsets.Where(x => x.Alias == "someFieldsetAlias"); 35 | 36 | foreach (var fieldset in someCurrentFieldsets) 37 | { 38 | var property = fieldset.Properties.FirstOrDefault(x => x.Alias == "somePropertyAlias"); 39 | 40 | if (property != null) 41 | { 42 | property.Value = "new value"; 43 | } 44 | } 45 | 46 | //add some new fieldsets 47 | currentFieldsets.AddRange( 48 | new List(){ 49 | //fieldset 1 of type 'myFieldsetAlias' 50 | new ArchetypeFieldsetModel() { 51 | Alias = "myFieldsetAlias", 52 | Properties = new List() 53 | { 54 | //property 1 of type 'myFieldsetAlias' 55 | new ArchetypePropertyModel() { 56 | Alias = "myPropertyAlias", 57 | Value = "" 58 | }, 59 | new ArchetypePropertyModel() { 60 | Alias = "myPropertyAlias2", 61 | Value = "" 62 | }, 63 | new ArchetypePropertyModel() { 64 | Alias = "myPropertyAlias3", 65 | Value = "" 66 | } 67 | }, 68 | Disabled = false, 69 | }, 70 | //fieldset 2 of type 'myFieldsetAlias' 71 | new ArchetypeFieldsetModel() { 72 | Alias = "myFieldsetAlias", 73 | Properties = new List() 74 | { 75 | new ArchetypePropertyModel() { 76 | Alias = "myPropertyAlias", 77 | Value = "" 78 | }, 79 | new ArchetypePropertyModel() { 80 | Alias = "myPropertyAlias2", 81 | Value = "" 82 | }, 83 | new ArchetypePropertyModel() { 84 | Alias = "myPropertyAlias3", 85 | Value = "" 86 | } 87 | }, 88 | Disabled = false, 89 | } 90 | //keep adding as you like 91 | }); 92 | 93 | //add our edited fieldsets to the Archetype 94 | myArchetype.Fieldsets = currentFieldsets; 95 | 96 | //generate the json that needs to be saved 97 | var json = myArchetype.SerializeForPersistence(); 98 | 99 | //use ContentService or MemberService etc to save it to a node 100 | content.SetValue("myDoctypeAliasForArchetypeProperty", json); 101 | services.ContentService.Save(content); 102 | } 103 | } 104 | } 105 | ``` 106 | >Note if you want to create an Archetype instead of loading it, just instantiate a new `ArchetypeModel` instead of loading and deserializing it. 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Archetype # 2 | 3 | Archetype is an Umbraco 7 property editor that wraps other installed property editors. By wrapping the other properties, Archetype allows for custom and repeatable fieldset mashups. 4 | 5 | # Important, please read! 6 | This project has been sunset. No further updates will be coming. Thank you to all of the contributors over the years. We had a good run. Please consider using Nested Content for similar needs. 7 | 8 | ## News and Updates ## 9 | Follow us at: https://twitter.com/ArchetypeKit 10 | 11 | ![archetype](assets/archetype.png) 12 | 13 | ## Features at a Glance ## 14 | Archetype can do many things but most people will only need a few features provided below: 15 | 16 | ### Basic ### 17 | * Create groupings (fieldsets) of installed data types 18 | * Enable/disable fieldsets or delete them 19 | * Sortable fieldsets 20 | * Validation 21 | * Allow for zero or more fieldsets 22 | * Enforce a maximum number of fieldsets 23 | * Hide property labels for more screen space 24 | * Toggle collapsing behavior 25 | * Clone fieldsets 26 | 27 | ### Advanced ### 28 | * Multiple types of fieldsets mixed together 29 | * Add custom CSS 30 | * Add custom JS 31 | * Switch the view altogether 32 | * Enable route hijacking by your server side code 33 | * Disable the built-in property value converter so you can implement your own 34 | 35 | ## Use Cases ## 36 | The best use case for Archetype occurs when you need a short list of collapsible fieldsets that contain other installed data types. The best concrete example would be using hero sliders: 37 | 38 | ![sliders](assets/sliders.png) 39 | 40 | Get up and running in 15 minutes! https://www.youtube.com/watch?v=79LksNwGjLk 41 | 42 | ## Source ## 43 | The source is open and located at: https://github.com/kgiszewski/Archetype 44 | -------------------------------------------------------------------------------- /assets/archetype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgiszewski/ArchetypeManual/38d5ea73774f4cce98ec7c00ed3654ea66c74232/assets/archetype.png -------------------------------------------------------------------------------- /assets/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgiszewski/ArchetypeManual/38d5ea73774f4cce98ec7c00ed3654ea66c74232/assets/config.png -------------------------------------------------------------------------------- /assets/cross-drag.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgiszewski/ArchetypeManual/38d5ea73774f4cce98ec7c00ed3654ea66c74232/assets/cross-drag.gif -------------------------------------------------------------------------------- /assets/label-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgiszewski/ArchetypeManual/38d5ea73774f4cce98ec7c00ed3654ea66c74232/assets/label-template.png -------------------------------------------------------------------------------- /assets/nuget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgiszewski/ArchetypeManual/38d5ea73774f4cce98ec7c00ed3654ea66c74232/assets/nuget.png -------------------------------------------------------------------------------- /assets/package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgiszewski/ArchetypeManual/38d5ea73774f4cce98ec7c00ed3654ea66c74232/assets/package.png -------------------------------------------------------------------------------- /assets/sliders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgiszewski/ArchetypeManual/38d5ea73774f4cce98ec7c00ed3654ea66c74232/assets/sliders.png --------------------------------------------------------------------------------