├── .gitattributes ├── .gitignore ├── PowerSite.Specs ├── App.config ├── Class1.cs ├── ConfigParsing.feature ├── ConfigParsing.feature.cs ├── ConfigParsingSteps.cs ├── PowerSite.Specs.csproj ├── Properties │ └── AssemblyInfo.cs ├── Samples │ └── Blog │ │ ├── Pages │ │ └── index.cshtml │ │ ├── Posts │ │ ├── a-fresh-start.md │ │ ├── about huddled masses.md │ │ ├── missing-content.md │ │ └── validating-self-signed-certificates-properly-from-powershell.md │ │ ├── Themes │ │ └── BootstrapBlog │ │ │ ├── 404.html │ │ │ ├── BlogLayout.cshtml │ │ │ ├── SiteLayout.cshtml │ │ │ ├── apple-touch-icon-precomposed.png │ │ │ ├── archive.cshtml │ │ │ ├── css │ │ │ ├── blog.css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── main.css │ │ │ ├── favicon.ico │ │ │ ├── feed.cshtml │ │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ └── glyphicons-halflings-regular.woff │ │ │ ├── js │ │ │ ├── main.js │ │ │ └── vendor │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── jquery-1.11.1.js │ │ │ │ ├── jquery-1.11.1.min.js │ │ │ │ └── modernizr-2.6.2-respond-1.1.0.min.js │ │ │ ├── page.cshtml │ │ │ └── post.cshtml │ │ └── config.psd1 └── packages.config ├── PowerSite.sln ├── PowerSite.sln.DotSettings ├── PowerSite.sln.GhostDoc.xml ├── PowerSite ├── Actions │ ├── BaseMefCommand.cs │ ├── BasePowerSiteCommand.cs │ ├── ConvertPageCommand.cs │ ├── GetPowerSiteCommand.cs │ └── UpdatePowerSiteCommand.cs ├── App.config ├── Builtin │ └── Renderers │ │ ├── MarkdownRenderer.cs │ │ └── RazorRenderer.cs ├── DataModel │ ├── Author.cs │ ├── Document.cs │ ├── IdentityCollection.cs │ ├── LayoutFile.cs │ ├── RenderingState.cs │ └── Theme.cs ├── EngineHost.cs ├── IRenderer.cs ├── PowerSite.csproj ├── PowerSite │ ├── PowerSite.psd1 │ └── PowerSite.psm1 ├── Properties │ └── AssemblyInfo.cs ├── Site.cs ├── Utility.cs └── packages.config └── ReadMe.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # NuGet Packages Directory 99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 100 | #packages/ 101 | 102 | # Windows Azure Build Output 103 | csx 104 | *.build.csdef 105 | 106 | # Windows Store app package directory 107 | AppPackages/ 108 | 109 | # Others 110 | sql/ 111 | *.Cache 112 | ClientBin/ 113 | [Ss]tyle[Cc]op.* 114 | ~$* 115 | *~ 116 | *.dbmdl 117 | *.[Pp]ublish.xml 118 | *.pfx 119 | *.publishsettings 120 | 121 | # RIA/Silverlight projects 122 | Generated_Code/ 123 | 124 | # Backup & report files from converting an old project file to a newer 125 | # Visual Studio version. Backup files are not needed, because we have git ;-) 126 | _UpgradeReport_Files/ 127 | Backup*/ 128 | UpgradeLog*.XML 129 | UpgradeLog*.htm 130 | 131 | # SQL Server files 132 | App_Data/*.mdf 133 | App_Data/*.ldf 134 | 135 | 136 | #LightSwitch generated files 137 | GeneratedArtifacts/ 138 | _Pvt_Extensions/ 139 | ModelManifest.xml 140 | 141 | # ========================= 142 | # Windows detritus 143 | # ========================= 144 | 145 | # Windows image file caches 146 | Thumbs.db 147 | ehthumbs.db 148 | 149 | # Folder config file 150 | Desktop.ini 151 | 152 | # Recycle Bin used on file shares 153 | $RECYCLE.BIN/ 154 | 155 | # Mac desktop service store files 156 | .DS_Store 157 | packages/ 158 | PowerSite.Specs/Samples/Blog/Cache/ 159 | PowerSite.Specs/Samples/Blog/Output/ 160 | -------------------------------------------------------------------------------- /PowerSite.Specs/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /PowerSite.Specs/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PowerSite.Specs 8 | { 9 | public class Class1 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /PowerSite.Specs/ConfigParsing.feature: -------------------------------------------------------------------------------- 1 | Feature: ConfigParsing 2 | In order to configure a PowerSite 3 | As a PowerShell user 4 | I want to write PSD1 files 5 | 6 | Scenario: Load the sample blog 7 | Given I have a sample blog with a config.psd1 8 | When I try to load the site 9 | Then the site should have matching properties: 10 | | Property | Value | 11 | | RootUrl | http://HuddledMasses.org/ | 12 | | BlogPath | blog/ | 13 | | PrettyUrl | True | 14 | | Title | Huddled Masses | 15 | | Description | You can do more than breathe for free... | 16 | | Theme | BootstrapBlog | 17 | 18 | Scenario: Load Documents 19 | Given I have loaded the sample blog 20 | When I load the documents 21 | Then the site should have Posts with RawContent 22 | But the site should not have Posts with RenderedContent 23 | 24 | Scenario: Calculating Page URLs 25 | Given I have loaded the sample blog 26 | When I load the documents 27 | Then the Pages should have URLs: http://HuddledMasses.org/index.html 28 | 29 | Scenario: Calculating Blog Post URLs 30 | Given I have loaded the sample blog 31 | When I load the documents 32 | Then the Posts should have URLs: http://HuddledMasses.org/blog/a-fresh-start/index.html 33 | And the Posts should have URLs: http://HuddledMasses.org/blog/about-huddled-masses/index.html 34 | And the Posts should have URLs: http://HuddledMasses.org/blog/missing-content/index.html 35 | And the Posts should have URLs: http://HuddledMasses.org/blog/validating-self-signed-certificates-properly-from-powershell/index.html 36 | 37 | Scenario: Render Markup 38 | Given I have loaded the sample blog 39 | And I load the documents 40 | When I render the markup 41 | Then all the posts in the site should have RenderedContent 42 | 43 | Scenario: Render Pages 44 | Given I have loaded the sample blog 45 | And I load the documents 46 | And I render the markup 47 | When I render the pages 48 | Then I get actual pages -------------------------------------------------------------------------------- /PowerSite.Specs/ConfigParsing.feature.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by SpecFlow (http://www.specflow.org/). 4 | // SpecFlow Version:2.0.0.0 5 | // SpecFlow Generator Version:2.0.0.0 6 | // 7 | // Changes to this file may cause incorrect behavior and will be lost if 8 | // the code is regenerated. 9 | // 10 | // ------------------------------------------------------------------------------ 11 | #region Designer generated code 12 | #pragma warning disable 13 | namespace PowerSite.Specs 14 | { 15 | using TechTalk.SpecFlow; 16 | 17 | 18 | [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.0.0.0")] 19 | [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 20 | public partial class ConfigParsingFeature : Xunit.IClassFixture, System.IDisposable 21 | { 22 | 23 | private static TechTalk.SpecFlow.ITestRunner testRunner; 24 | 25 | #line 1 "ConfigParsing.feature" 26 | #line hidden 27 | 28 | public ConfigParsingFeature() 29 | { 30 | this.TestInitialize(); 31 | } 32 | 33 | public static void FeatureSetup() 34 | { 35 | testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); 36 | TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "ConfigParsing", "\tIn order to configure a PowerSite\r\n\tAs a PowerShell user\r\n\tI want to write PSD1 " + 37 | "files", ProgrammingLanguage.CSharp, ((string[])(null))); 38 | testRunner.OnFeatureStart(featureInfo); 39 | } 40 | 41 | public static void FeatureTearDown() 42 | { 43 | testRunner.OnFeatureEnd(); 44 | testRunner = null; 45 | } 46 | 47 | public virtual void TestInitialize() 48 | { 49 | } 50 | 51 | public virtual void ScenarioTearDown() 52 | { 53 | testRunner.OnScenarioEnd(); 54 | } 55 | 56 | public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) 57 | { 58 | testRunner.OnScenarioStart(scenarioInfo); 59 | } 60 | 61 | public virtual void ScenarioCleanup() 62 | { 63 | testRunner.CollectScenarioErrors(); 64 | } 65 | 66 | public virtual void SetFixture(ConfigParsingFeature.FixtureData fixtureData) 67 | { 68 | } 69 | 70 | void System.IDisposable.Dispose() 71 | { 72 | this.ScenarioTearDown(); 73 | } 74 | 75 | [Xunit.FactAttribute()] 76 | [Xunit.TraitAttribute("FeatureTitle", "ConfigParsing")] 77 | [Xunit.TraitAttribute("Description", "Load the sample blog")] 78 | public virtual void LoadTheSampleBlog() 79 | { 80 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Load the sample blog", ((string[])(null))); 81 | #line 6 82 | this.ScenarioSetup(scenarioInfo); 83 | #line 7 84 | testRunner.Given("I have a sample blog with a config.psd1", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); 85 | #line 8 86 | testRunner.When("I try to load the site", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); 87 | #line hidden 88 | TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] { 89 | "Property", 90 | "Value"}); 91 | table1.AddRow(new string[] { 92 | "RootUrl", 93 | "http://HuddledMasses.org/"}); 94 | table1.AddRow(new string[] { 95 | "BlogPath", 96 | "blog/"}); 97 | table1.AddRow(new string[] { 98 | "PrettyUrl", 99 | "True"}); 100 | table1.AddRow(new string[] { 101 | "Title", 102 | "Huddled Masses"}); 103 | table1.AddRow(new string[] { 104 | "Description", 105 | "You can do more than breathe for free..."}); 106 | table1.AddRow(new string[] { 107 | "Theme", 108 | "BootstrapBlog"}); 109 | #line 9 110 | testRunner.Then("the site should have matching properties:", ((string)(null)), table1, "Then "); 111 | #line hidden 112 | this.ScenarioCleanup(); 113 | } 114 | 115 | [Xunit.FactAttribute()] 116 | [Xunit.TraitAttribute("FeatureTitle", "ConfigParsing")] 117 | [Xunit.TraitAttribute("Description", "Load Documents")] 118 | public virtual void LoadDocuments() 119 | { 120 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Load Documents", ((string[])(null))); 121 | #line 18 122 | this.ScenarioSetup(scenarioInfo); 123 | #line 19 124 | testRunner.Given("I have loaded the sample blog", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); 125 | #line 20 126 | testRunner.When("I load the documents", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); 127 | #line 21 128 | testRunner.Then("the site should have Posts with RawContent", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); 129 | #line 22 130 | testRunner.But("the site should not have Posts with RenderedContent", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "But "); 131 | #line hidden 132 | this.ScenarioCleanup(); 133 | } 134 | 135 | [Xunit.FactAttribute()] 136 | [Xunit.TraitAttribute("FeatureTitle", "ConfigParsing")] 137 | [Xunit.TraitAttribute("Description", "Calculating Page URLs")] 138 | public virtual void CalculatingPageURLs() 139 | { 140 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Calculating Page URLs", ((string[])(null))); 141 | #line 24 142 | this.ScenarioSetup(scenarioInfo); 143 | #line 25 144 | testRunner.Given("I have loaded the sample blog", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); 145 | #line 26 146 | testRunner.When("I load the documents", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); 147 | #line 27 148 | testRunner.Then("the Pages should have URLs: http://HuddledMasses.org/index.html", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); 149 | #line hidden 150 | this.ScenarioCleanup(); 151 | } 152 | 153 | [Xunit.FactAttribute()] 154 | [Xunit.TraitAttribute("FeatureTitle", "ConfigParsing")] 155 | [Xunit.TraitAttribute("Description", "Calculating Blog Post URLs")] 156 | public virtual void CalculatingBlogPostURLs() 157 | { 158 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Calculating Blog Post URLs", ((string[])(null))); 159 | #line 29 160 | this.ScenarioSetup(scenarioInfo); 161 | #line 30 162 | testRunner.Given("I have loaded the sample blog", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); 163 | #line 31 164 | testRunner.When("I load the documents", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); 165 | #line 32 166 | testRunner.Then("the Posts should have URLs: http://HuddledMasses.org/blog/a-fresh-start/index.htm" + 167 | "l", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); 168 | #line 33 169 | testRunner.And("the Posts should have URLs: http://HuddledMasses.org/blog/about-huddled-masses/in" + 170 | "dex.html", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); 171 | #line 34 172 | testRunner.And("the Posts should have URLs: http://HuddledMasses.org/blog/missing-content/index.h" + 173 | "tml", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); 174 | #line 35 175 | testRunner.And("the Posts should have URLs: http://HuddledMasses.org/blog/validating-self-signed-" + 176 | "certificates-properly-from-powershell/index.html", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); 177 | #line hidden 178 | this.ScenarioCleanup(); 179 | } 180 | 181 | [Xunit.FactAttribute()] 182 | [Xunit.TraitAttribute("FeatureTitle", "ConfigParsing")] 183 | [Xunit.TraitAttribute("Description", "Render Markup")] 184 | public virtual void RenderMarkup() 185 | { 186 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Render Markup", ((string[])(null))); 187 | #line 37 188 | this.ScenarioSetup(scenarioInfo); 189 | #line 38 190 | testRunner.Given("I have loaded the sample blog", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); 191 | #line 39 192 | testRunner.And("I load the documents", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); 193 | #line 40 194 | testRunner.When("I render the markup", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); 195 | #line 41 196 | testRunner.Then("all the posts in the site should have RenderedContent", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); 197 | #line hidden 198 | this.ScenarioCleanup(); 199 | } 200 | 201 | [Xunit.FactAttribute()] 202 | [Xunit.TraitAttribute("FeatureTitle", "ConfigParsing")] 203 | [Xunit.TraitAttribute("Description", "Render Pages")] 204 | public virtual void RenderPages() 205 | { 206 | TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Render Pages", ((string[])(null))); 207 | #line 43 208 | this.ScenarioSetup(scenarioInfo); 209 | #line 44 210 | testRunner.Given("I have loaded the sample blog", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); 211 | #line 45 212 | testRunner.And("I load the documents", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); 213 | #line 46 214 | testRunner.And("I render the markup", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); 215 | #line 47 216 | testRunner.When("I render the pages", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); 217 | #line 48 218 | testRunner.Then("I get actual pages", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); 219 | #line hidden 220 | this.ScenarioCleanup(); 221 | } 222 | 223 | [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.0.0.0")] 224 | [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 225 | public class FixtureData : System.IDisposable 226 | { 227 | 228 | public FixtureData() 229 | { 230 | ConfigParsingFeature.FeatureSetup(); 231 | } 232 | 233 | void System.IDisposable.Dispose() 234 | { 235 | ConfigParsingFeature.FeatureTearDown(); 236 | } 237 | } 238 | } 239 | } 240 | #pragma warning restore 241 | #endregion 242 | -------------------------------------------------------------------------------- /PowerSite.Specs/ConfigParsingSteps.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Management.Automation; 7 | using System.Management.Automation.Runspaces; 8 | using TechTalk.SpecFlow; 9 | using Xunit; 10 | using PowerSite.DataModel; 11 | namespace PowerSite.Specs 12 | { 13 | [Binding] 14 | public class ConfigParsingSteps : Steps 15 | { 16 | public ConfigParsingSteps() 17 | { 18 | Runspace.DefaultRunspace = PowerShell.Create().Runspace; 19 | } 20 | 21 | [Given(@"I have a sample ([^ ]+) with a config\.psd1")] 22 | public void GivenASample(string sample) 23 | { 24 | Trace.TraceWarning(Environment.CurrentDirectory); 25 | // C:\Users\Joel\Projects\PowerSite\PowerSite.Specs\bin\Debug 26 | 27 | var sampleRoot = string.Format(@"..\..\Samples\{0}", sample); 28 | var samplePath = string.Format(@"..\..\Samples\{0}\config.psd1", sample); 29 | Assert.True(Directory.Exists(sampleRoot)); 30 | Assert.True(File.Exists(samplePath)); 31 | ScenarioContext.Current.Add("SiteRoot", sampleRoot); 32 | } 33 | 34 | 35 | [When(@"I try to load the site")] 36 | public void LoadTheSite() 37 | { 38 | 39 | var site = Site.ForPath(ScenarioContext.Current.Get("SiteRoot")); 40 | ScenarioContext.Current.Add("Site", site); 41 | } 42 | 43 | [Given(@"I have loaded the sample ([^ ]+)")] 44 | public void GivenIHaveLoadedASample(string sample) 45 | { 46 | Given(string.Format("I have a sample {0} with a config.psd1", sample)); 47 | When("I try to load the site"); 48 | } 49 | 50 | 51 | [Given(@"I load the documents")] 52 | [When(@"I load the documents")] 53 | public void LoadDocuments() 54 | { 55 | var site = ScenarioContext.Current.Get("Site"); 56 | site.LoadDocuments(); 57 | } 58 | 59 | [Then(@"the site should have matching properties:")] 60 | public void ThenThePowerSiteShouldHaveMatchingProperties(Table table) 61 | { 62 | var site = ScenarioContext.Current.Get("Site"); 63 | var config = (Hashtable)((PSObject)site.Config).BaseObject; 64 | 65 | foreach (var row in table.Rows) 66 | { 67 | Assert.True(config.ContainsKey(row["Property"])); 68 | 69 | Assert.Equal(row["Value"], config[row["Property"]].ToString()); 70 | } 71 | } 72 | 73 | [Then(@"the site should have Posts with RawContent")] 74 | public void ThenThePowerSiteShouldHavePostsWithRawContent() 75 | { 76 | var site = ScenarioContext.Current.Get("Site"); 77 | Assert.True( site.Posts.All(doc => !string.IsNullOrEmpty(doc.RawContent)) ); 78 | } 79 | 80 | [Then(@"the site should not have Posts with RenderedContent")] 81 | public void ThenThePowerSiteShouldNotHavePostsWithRenderedContent() 82 | { 83 | var site = ScenarioContext.Current.Get("Site"); 84 | Assert.True( site.Posts.All(doc => string.IsNullOrEmpty(doc.RenderedContent)) ); 85 | } 86 | 87 | [When(@"I render the markup")] 88 | [Given(@"I render the markup")] 89 | public void RenderDocuments() 90 | { 91 | var site = ScenarioContext.Current.Get("Site"); 92 | site.RenderDocuments(); 93 | } 94 | 95 | [Then(@"all the posts in the site should have RenderedContent")] 96 | public void ThenAllThePostsInThePowerSiteShouldHaveRenderedContent() 97 | { 98 | var site = ScenarioContext.Current.Get("Site"); 99 | Assert.True(site.Posts.All(doc => !string.IsNullOrEmpty(doc.RenderedContent))); 100 | } 101 | 102 | [When(@"I render the pages")] 103 | public void WhenIRenderThePages() 104 | { 105 | var site = ScenarioContext.Current.Get("Site"); 106 | site.RenderTemplates(); 107 | } 108 | 109 | [Then(@"I get actual pages")] 110 | public void ThenIGetActualPages() 111 | { 112 | var root = ScenarioContext.Current.Get("SiteRoot"); 113 | var blog = ScenarioContext.Current.Get("Site").BlogPath; 114 | blog = Path.Combine(root, "Cache", blog); 115 | 116 | foreach (var post in new[] {"a-fresh-start/index.html", "about-huddled-masses/index.html"}.Select(post => Path.Combine(blog, post))) 117 | { 118 | Assert.True(File.Exists(post), string.Format("Blog post '{0}' does not exist.", post)); 119 | Assert.NotEqual(0, new FileInfo(post).Length); 120 | } 121 | 122 | foreach (var page in new[] {"index.html"}.Select(page => Path.Combine(blog, page))) 123 | { 124 | Assert.True(File.Exists(page), string.Format("Web page '{0}' does not exist.", page)); 125 | Assert.NotEqual(0, new FileInfo(page).Length); 126 | } 127 | } 128 | 129 | 130 | [Then(@"the Posts should have URLs: ([^ ]+)")] 131 | public void ThenThePostsShouldHaveURLs(string url) 132 | { 133 | var blog = ScenarioContext.Current.Get("Site"); 134 | Assert.Contains(url, blog.Posts.Select(post => post.FullyQualifiedUrl)); 135 | } 136 | 137 | [Then(@"the Pages should have URLs: ([^ ]+)")] 138 | public void ThenThePagesShouldHaveURLs(string url) 139 | { 140 | var blog = ScenarioContext.Current.Get("Site"); 141 | // TODO: this may break if I add another page test 142 | Assert.Equal(url, blog.Pages[0].FullyQualifiedUrl); 143 | } 144 | 145 | [AfterScenario] 146 | public void DisposeSite() 147 | { 148 | if(ScenarioContext.Current.ContainsKey("Site")) 149 | ScenarioContext.Current.Get("Site").Dispose(); 150 | } 151 | 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /PowerSite.Specs/PowerSite.Specs.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {61D72176-9C50-4D38-B6AC-91A19E197C26} 9 | Library 10 | Properties 11 | PowerSite.Specs 12 | PowerSite.Specs 13 | v4.5 14 | 512 15 | 4d1fa453 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Microsoft.AspNet.Razor.4.0.0-beta7\lib\net45\Microsoft.AspNet.Razor.dll 37 | True 38 | 39 | 40 | ..\packages\RazorEngine.4.2.7-beta1\lib\net45\RazorEngine.dll 41 | True 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ..\packages\SpecFlow.2.0.0\lib\net45\TechTalk.SpecFlow.dll 54 | True 55 | 56 | 57 | ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll 58 | True 59 | 60 | 61 | ..\packages\xunit.assert.2.1.0\lib\portable-net45+win8+wp8+wpa81\xunit.assert.dll 62 | True 63 | 64 | 65 | ..\packages\xunit.extensibility.core.2.1.0\lib\portable-net45+win8+wp8+wpa81\xunit.core.dll 66 | True 67 | 68 | 69 | ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll 70 | True 71 | 72 | 73 | 74 | 75 | 76 | True 77 | True 78 | ConfigParsing.feature 79 | 80 | 81 | 82 | 83 | 84 | 85 | Code 86 | 87 | 88 | 89 | Code 90 | 91 | 92 | 93 | 94 | 95 | SpecFlowSingleFileGenerator 96 | ConfigParsing.feature.cs 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | {4a8f250c-3a76-423d-883b-cec3687895e7} 137 | PowerSite 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 151 | 152 | 153 | 154 | 161 | -------------------------------------------------------------------------------- /PowerSite.Specs/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PowerSite.Specs")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PowerSite.Specs")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6f9c5447-b2ba-43df-bcd8-43a9611e7afc")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Pages/index.cshtml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/PowerSite/3ca9d62783ee8283de32c2aa156acd6a9008f5ef/PowerSite.Specs/Samples/Blog/Pages/index.cshtml -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Posts/a-fresh-start.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A Fresh Start 3 | date: 2014-07-24 01:02:43 -04:00 4 | tags: Site News 5 | author: Joel Bennett (Jaykul) http://HuddledMasses.org 6 | description: An explanation of why everything is missing 7 | --- 8 | 9 | A few weeks ago, someone somehow injected a shell onto my WordPress powered blog site. They managed to get multiple hacking tools installed, delete files required for hosting, and who knows what else. Needless to say I was frustrated and upset. In fact, I was so frustrated that to get rid of it I just tore down the whole site. 10 | 11 | I apologize for all the hundreds of broken links that are pointed at my domain right now. I have a database backup, but I want to try a few other blogging tools out, and I am not sure I can trust the downloads or even images on the old site -- I don't want to restore all the posts *and then* find out the downloads are infected or the images have been replaced. Furthermore, when I stood up a new WordPress site, it did not perform well on my DreamHost server, and I started to wonder if I needed new hosting or new blogging tools. 12 | 13 | A state of flux 14 | --------------- 15 | 16 | In the end, I decided to try switching to a static site generator instead of a server-side blogging tool, so I went to [StaticGen][1] and I've started working my way through some of the many interesting options. I'll probably be switching back and forth between them over the coming days, so the site may change quite a bit (not just visually, but in permalinks, etc.) until I settle on one. 17 | 18 | I also decided that I will not restore the database backup and deal with cleaning all the downloads that have accumulated in the last ... almost 20 years of blogging (isn't that crazy?). Instead, I will start over. I can still restore individual articles from my old blog by hand (at least the ones that people really are still looking for), and that will give me the chance to update the content and to convert them to markdown (yeah, I think textile lost that battle). 19 | 20 | Please [let me know][2] when you hit a missing page that you want back, and I'll move that up my priority list. 21 | 22 | [1]: http://www.staticgen.com/ 23 | [2]: /missing-content/ -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Posts/about huddled masses.md: -------------------------------------------------------------------------------- 1 | ## Converted from ReST 2 | title: About Huddled Masses 3 | date: 2014-07-21 01:02:18 -04:00 4 | tags: Site News 5 | description: What this site is about 6 | 7 | This is web site is dedicated to the musings of Joel Bennett (aka Jaykul) 8 | about technology, software, software development, the web, and the world. 9 | 10 | Any resemblance of the views expressed and the views of my employer, my terminal, or the view out my window 11 | are purely coincidental. The resemblance between them and my own views is non-deterministic. 12 | The question of the existence of views in the absence of anyone to hold them is left as an exercise for the reader. 13 | 14 | The Man of Many Hats 15 | -------------------- 16 | 17 | > Not like the giant companies of great fame,
18 | > With componentized factories cranking out clones;
19 | > Here on our white-washed pages shall stand
20 | > A solitary man with a keyboard whose products
21 | > Are the collected sparks, and his name:
22 | > The DevOps King.
23 | >
24 | > -- Joel Bennett
25 | 26 | With apologies to Emma Lazarus: 27 | 28 | The New Colossus 29 | ---------------- 30 | 31 | > Not like the brazen giant of Greek fame,
32 | > With conquering limbs astride from land to land;
33 | > Here at our sea-washed, sunset gates shall stand
34 | > A mighty woman with a torch, whose flame
35 | > Is the imprisoned lightning, and her name
36 | > Mother of Exiles. From her beacon-hand
37 | > Glows world-wide welcome; her mild eyes command
38 | > The air-bridged harbor that twin cities frame.
39 | > "Keep ancient lands, your storied pomp!" cries she
40 | > With silent lips. "Give me your tired, your poor,
41 | > Your huddled masses yearning to breathe free,
42 | > The wretched refuse of your teeming shore.
43 | > Send these, the homeless, tempest-tost to me,
44 | > I lift my lamp beside the golden door!"
45 | >
46 | > -- Emma Lazarus
47 | 48 | **Please Note:** I occasionally link to things I think are great. 49 | When I do, I occasionally find a "referral code" so I can make a little cash. 50 | I promise that I don't link to anything just because of the cash 51 | (I wouldn't cross the street for the amount of cash those links bring in, never mind write a whole blog post), 52 | and I promise I won't let anyone buy links in my blog content ... 53 | but I do not promise that things I link to will stay great as time passes, 54 | nor that you will agree with me about their greatness! 55 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Posts/missing-content.md: -------------------------------------------------------------------------------- 1 | title: Missing Content 2 | date: 2014-07-22 12:02:18 -04:00 3 | tags: Site News 4 | description: Where you should ask for updates and missing pages 5 | 6 | Since I've blown away all my old blog content, there are a lot of pages missing that were really useful. 7 | I'm going to bring the best of them back, and I have plans to actually rewrite some of the older ones to update them 8 | (part of the reason I let the old ones go is that some of them were so out-of-date that they might have been misleading). 9 | 10 | If there is one or more of my old articles in particular that you'd like to see come back, please post a comment below! 11 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Posts/validating-self-signed-certificates-properly-from-powershell.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2014-07-28 01:30:03 -04:00 3 | tags: PowerShell, SSL, REST, WebRequest 4 | description: A PowerShell module to allow weakening or circumventing SSL validation on web queries. 5 | title: Validating Self-Signed Certificates From .Net and PowerShell 6 | --- 7 | 8 | In this article I'm going to present a module that helps you deal with one of the common problems for Windows PowerShell users (and even .Net developers) who are trying to interact from command-line applications with web interfaces (especially those that are hosted internally): Self-signed certificates, and how to ignore the errors that come when you try to validate them. If you don't care about why I wrote it the way I wrote it, you can just [check out the module on GitHub](https://github.com/Jaykul/Tunable-SSL-Validator) or install it with PoshCode or PowerShellGet by running: 9 | 10 | Install-Module TunableSSLValidator 11 | 12 | The module includes commands for importing certificates from files, loading them from the web server response of an http url, importing them to the Windows certificate store (to be trusted), and temporarily trusting them for a single PowerShell session. It also includes proxy function command wrappers for ``Invoke-WebRequest`` and ``Invoke-RestMethod`` to add an ``-Insecure`` switch which allows single queries to ignore invalid SSL certificates. 13 | 14 | **One caveat** is that the way that it works is based on implementing the ServerCertificateValidationCallback, and the *results of that callback are cached* by your system, so in testing I've found that if you allow a certain URL, that URL is going to be valid for several seconds until the cache expires, so if you make several repeated calls to the same URL, and only the first one is flagged ``-insecure``, they *may* all succeed. I can't remember what the documentation says about the timing or flushing the cache right now, but although it's obviously not a security issue, I am going to look for a way to flush that if it's possible. 15 | 16 | 17 | Some Background 18 | =============== 19 | 20 | The root of the problem is that the web request classes in .Net automatically validate SSL certificates, and until version 4.5 there was not an easy way to ignore SSL errors or skip the validation on an individual request. That means that when you try to get a web page from a server like the [computer science house at RIT](https://csh.rit.edu), you get an error like: 21 | 22 | The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. 23 | 24 | For most linux command line apps like *curl* you have a parameter like ``--insecure`` which allows you to just ignore invalid SSL certificates for a single web request, but for .Net and PowerShell there is no such a flag, resulting in [a lot of questions on StackOverflow](http://stackoverflow.com/search?q=self-signed+SSL+certificates+[csharp]+OR+[powershell]) and other such websites about the best way to deal with them. 25 | 26 | Beginning with version 3.0, PowerShell ships with ``Invoke-WebRequest`` and ``Invoke-RestMethod`` cmdlets, but these cmdlets don't have an ``-insecure`` switch, and so you can't use them unless you disable validation. The module I'm going to present here will fix that, and I want to show you how I did it so you can do the same thing for other similar cmdlets (like the ``Export-ODataEndpointProxy`` cmdlet that showed up in the July preview of PowerShell 5, and the cmdlets it generates). 27 | 28 | Removing SSL Validation 29 | ======================= 30 | 31 | There are a couple of common approaches to this problem in PowerShell (and .Net too, actually). The first is to just add the SSL certificate to your trusted store. The second is to set the ServicePointManager's ServerCertificateValidationCallback to a function that just returns TRUE -- thus ignoring **all** certificate errors. 32 | 33 | That first solution is probably the right one, and I actually wrote a couple of function in this module to make it easier (one to fetch a cert from a web server, and another to add a certificate to your trusted store). Of course, it would be even better to set up an actual trusted root certificate authority (for instance, using Active Directory), but the bottom line is that either of these require permanently altering the trust of the computer in order to make a web request. The problem is that if you're writing scripts, cmdlets or .Net applications that may be used by others, it basically amounts to telling your potential users they have to deal with the problem themselves (which, for the record, is exactly what Microsoft did when they wrote their web cmdlets for PowerShell 3). 34 | 35 | So if you want to proactively avoid SSL errors, you have to set the ServerCertificateValidationCallback. For certain situations, it's enough to just do this in PowerShell: 36 | 37 | $url = "https://csh.rit.edu" 38 | $web = New-Object Net.WebClient 39 | [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } 40 | $output = $web.DownloadString($url) 41 | [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null 42 | 43 | Note, that I set the ServerCertificateValidationCallback back to ``$null`` when I was done -- this restores normal validation, so I have, in effect, only disabled the validation for that one call (since PowerShell isn't generally multi-threaded, I don't normally have to worry about other threads being affeected). However, setting the ServerCertificateValidationCallback to a scriptblock won't work for an asynchronous callback (one that happens on a task thread), because the other thread won't have a runspace to execute the script on. So, if you try to use the same technique with Invoke-WebRequest or Invoke-RestMethod instead of calling the .Net ``WebClient`` methods directly, you'll just get a different error: 44 | 45 | The underlying connection was closed: An unexpected error occurred on a send. 46 | 47 | If you dig in a little bit, you'll find that the InnerException of the error was: 48 | 49 | There is no Runspace available to run scripts in this thread. 50 | You can provide one in the DefaultRunspace property 51 | of the System.Management.Automation.Runspaces.Runspace type. 52 | The script block you attempted to invoke was: $true 53 | 54 | Obviously this approach doesn't work at that point, and the Invoke-WebRequest cmdlet is not the only place which will call web APIs on background threads, so to make those cmdlets and APIs work, we need to write it in C# (and do so in a way that's flexible enough that we can control it from PowerShell). 55 | 56 | Additionally, simply returning true will disable all validation, and that's not really a safe practice -- it's certainly not what you want to do all of the time. If you're on .Net 4.5 or later, you can set the callback on the a raw HttpWebRequest and only affect that one request, but obviously that only works if you write your code at that low level, don't use the PowerShell cmdlets, and are on the latest version of .Net -- plus, you still have to write the logic that determines when that should happen. 57 | 58 | The bottom line is that what we probably want is something like an ``insecure`` switch on the PowerShell cmdlets, so that we can make a specific request be insecure, and then when we were writing functions, we could just pass that parameter up to our functions. 59 | 60 | 61 | Custom SSL Validator 62 | ==================== 63 | 64 | There are several example validators on the [Using Trusted Roots Respectfully](http://www.mono-project.com/UsingTrustedRootsRespectfully) page from mono project, but I'm going to try to blend a few of those validators to give us the option of tuning the SSL validation to our specific needs. 65 | 66 | The point is that I don't want to weaken *all* validation, I just want to trust a specific cert for a specific domain, or perhaps just ignore problems on one domain, or make one specific request regardless of whether the SSL certificate is valid or not. 67 | 68 | Let's look at the callback and see the information we have to work with: 69 | 70 | bool TunableValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 71 | 72 | 1. The sender is usually going to be the WebRequest that was calling an https domain that failed validation. 73 | 2. The certificate, of course, is the one the actually failed ... 74 | 3. The chain is the series of certificates that issued the original one, back to the root certificate authority, along with the trust information about them. 75 | 4. The sslPolicyErrors tells us what went wrong: Was there no cert? Was the cert for the wrong domain? Was the root CA not trusted? 76 | 77 | So, what I've written is first a check for the three main SSL errors, and a way to pre-emptively ignore them once, or post-humously trust a certificate that failed the first time, as well as some better error messages (which have to be output using Console.Error.WriteLine rather than Write-Error because they might be running on a background thread). 78 | 79 | For now, that's enough of an explanation, I've posted the [tunable SSL validator code to github](https://github.com/Jaykul/Tunable-SSL-Validator), and this blog post as the ReadMe, where I'll update it with more details if need be. 80 | 81 | [//]: # (This should turn into something like a cucumber spec... ) 82 | [//]: # ( ) 83 | [//]: # (# #. I want to be sure I'm not weakening validation for requests that I don't mean to affect. ) 84 | [//]: # (# #. I want to be able to just trust a few specific certificate(s). ) 85 | [//]: # (# #. I want to be able to just ignore problems for a single web request. ) 86 | [//]: # (# except the ones that I specifically override security on. ) 87 | [//]: # (# ) -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

Sorry, but the page you were trying to view does not exist.

146 |

It looks like this was the result of either:

147 |
    148 |
  • a mistyped address
  • 149 |
  • an out-of-date link
  • 150 |
151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/BlogLayout.cshtml: -------------------------------------------------------------------------------- 1 | @using PowerSite 2 | @using PowerSite.Actions 3 | @using PowerSite.DataModel 4 | @inherits RazorEngine.Templating.TemplateBase 5 | @{ 6 | ViewBag.Active = "blog"; 7 | if (string.IsNullOrEmpty(ViewBag.FeedUrl)) 8 | { 9 | ViewBag.FeedUrl = "/blog/feed.xml"; 10 | } 11 | } 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | @ViewBag.Title 26 | 27 | 28 | 34 | 35 | 36 | 37 | @RenderSection("head", false) 38 | 39 | 40 | 43 | 64 |
65 |
66 |

@Site.Current.Title

67 |

@Site.Current.Description

68 |
69 |
70 |
71 | @RenderBody() 72 |
73 |
74 | 78 | 87 | 92 | 96 |
97 | 98 |
99 | 100 |
101 |
102 |

© @Site.Current.Author.Name 2014

103 |
104 |
105 | 106 | 107 | 108 | 109 | 110 | @* Google Analytics: change UA-XXXXX-X to be your site's ID. *@ 111 | 122 | @RenderSection("script", false) 123 | 124 | 125 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/SiteLayout.cshtml: -------------------------------------------------------------------------------- 1 | @using PowerSite 2 | @using PowerSite.DataModel 3 | @using RazorEngine.Templating 4 | @inherits TemplateBase 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | @Raw(string.IsNullOrEmpty(Model.Title) ? "" : Model.Title + " - ") @Site.Current.Title 19 | 20 | 21 | 27 | 28 | 29 | 30 | @RenderSection("head", false) 31 | 32 | 33 | 36 | 56 | 57 | @RenderBody() 58 | 59 | 60 | 61 | 62 | 63 | @* Google Analytics: change UA-XXXXX-X to be your site's ID. *@ 64 | 75 | @RenderSection("script", false) 76 | 77 | 78 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/PowerSite/3ca9d62783ee8283de32c2aa156acd6a9008f5ef/PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/archive.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Linq 2 | @using PowerSite 3 | @using PowerSite.Actions 4 | @using PowerSite.DataModel 5 | @inherits RazorEngine.Templating.TemplateBase> 6 | @{ 7 | Layout = "BlogLayout.cshtml"; 8 | ViewBag.Author = Site.Current.Author.Name; 9 | ViewBag.Title = Site.Current.Author.Name + "'s Blog - " + Site.Current.Title; 10 | ViewBag.FeedUrl = "feed.xml"; 11 | } 12 | 13 | @foreach (var blog in Model) 14 | { 15 |
16 |

@blog.Title

17 | 20 |
21 | Tagged: 22 |
    23 | @foreach (var tag in blog.Tags) 24 | { 25 |
  • @tag
  • 26 | } 27 |
28 |
29 | @Raw(blog.Summary) 30 |
31 | } 32 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/css/blog.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Globals 3 | */ 4 | 5 | body { 6 | font-family: Georgia, "Times New Roman", Times, serif; 7 | /*color: #555;*/ 8 | } 9 | 10 | h1, .h1, 11 | h2, .h2, 12 | h3, .h3, 13 | h4, .h4, 14 | h5, .h5, 15 | h6, .h6 { 16 | margin-top: 0; 17 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 18 | font-weight: normal; 19 | /*color: #333;*/ 20 | } 21 | 22 | 23 | /* 24 | * Override Bootstrap's default container. 25 | */ 26 | 27 | @media (min-width: 1200px) { 28 | .container { 29 | width: 970px; 30 | } 31 | } 32 | 33 | 34 | /* 35 | * Masthead for nav 36 | */ 37 | 38 | .blog-masthead { 39 | background-color: #428bca; 40 | -webkit-box-shadow: inset 0 -2px 5px rgba(0,0,0,.1); 41 | box-shadow: inset 0 -2px 5px rgba(0,0,0,.1); 42 | } 43 | 44 | /* Nav links */ 45 | .blog-nav-item { 46 | position: relative; 47 | display: inline-block; 48 | padding: 10px; 49 | font-weight: 500; 50 | color: #cdddeb; 51 | } 52 | .blog-nav-item:hover, 53 | .blog-nav-item:focus { 54 | color: #fff; 55 | text-decoration: none; 56 | } 57 | 58 | /* Active state gets a caret at the bottom */ 59 | .blog-nav .active { 60 | color: #fff; 61 | } 62 | .blog-nav .active:after { 63 | position: absolute; 64 | bottom: 0; 65 | left: 50%; 66 | width: 0; 67 | height: 0; 68 | margin-left: -5px; 69 | vertical-align: middle; 70 | content: " "; 71 | border-right: 5px solid transparent; 72 | border-bottom: 5px solid; 73 | border-left: 5px solid transparent; 74 | } 75 | 76 | 77 | /* 78 | * Blog name and description 79 | */ 80 | 81 | .blog-header { 82 | padding-top: 20px; 83 | padding-bottom: 20px; 84 | } 85 | .blog-title { 86 | margin-top: 30px; 87 | margin-bottom: 0; 88 | font-size: 60px; 89 | font-weight: normal; 90 | } 91 | .blog-description { 92 | font-size: 20px; 93 | color: #999; 94 | } 95 | 96 | 97 | /* 98 | * Main column and sidebar layout 99 | */ 100 | 101 | .blog-main { 102 | font-size: 18px; 103 | line-height: 1.5; 104 | } 105 | 106 | /* Sidebar modules for boxing content */ 107 | .sidebar-module { 108 | padding: 15px; 109 | margin: 0 -15px 15px; 110 | } 111 | .sidebar-module-inset { 112 | padding: 15px; 113 | background-color: #f5f5f5; 114 | border-radius: 4px; 115 | } 116 | .sidebar-module-inset p:last-child, 117 | .sidebar-module-inset ul:last-child, 118 | .sidebar-module-inset ol:last-child { 119 | margin-bottom: 0; 120 | } 121 | 122 | 123 | 124 | /* Pagination */ 125 | .pager { 126 | margin-bottom: 60px; 127 | text-align: left; 128 | } 129 | .pager > li > a { 130 | width: 140px; 131 | padding: 10px 20px; 132 | text-align: center; 133 | border-radius: 30px; 134 | } 135 | 136 | 137 | /* 138 | * Blog posts 139 | */ 140 | 141 | .blog-post { 142 | margin-bottom: 60px; 143 | } 144 | .blog-post-title { 145 | margin-bottom: 5px; 146 | font-size: 40px; 147 | } 148 | .blog-post-meta { 149 | margin-bottom: 20px; 150 | color: #999; 151 | } 152 | 153 | 154 | /* 155 | * Footer 156 | */ 157 | 158 | .blog-footer { 159 | padding: 40px 0; 160 | margin-bottom: -20px; 161 | color: #c8c8c8; 162 | text-align: center; 163 | background-color: #2e3338; 164 | border-top: 1px solid rgba(0, 0, 0, .6); 165 | } 166 | .blog-footer p:last-child { 167 | margin-bottom: 0; 168 | } 169 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 16 | } 17 | .btn-default:active, 18 | .btn-primary:active, 19 | .btn-success:active, 20 | .btn-info:active, 21 | .btn-warning:active, 22 | .btn-danger:active, 23 | .btn-default.active, 24 | .btn-primary.active, 25 | .btn-success.active, 26 | .btn-info.active, 27 | .btn-warning.active, 28 | .btn-danger.active { 29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 31 | } 32 | .btn:active, 33 | .btn.active { 34 | background-image: none; 35 | } 36 | .btn-default { 37 | text-shadow: 0 1px 0 #fff; 38 | background-image: -webkit-linear-gradient(top, #3a3f44 0%, #1e2023 100%); 39 | background-image: -o-linear-gradient(top, #3a3f44 0%, #1e2023 100%); 40 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3a3f44), to(#1e2023)); 41 | background-image: linear-gradient(to bottom, #3a3f44 0%, #1e2023 100%); 42 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3a3f44', endColorstr='#ff1e2023', GradientType=0); 43 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 44 | background-repeat: repeat-x; 45 | border-color: #191b1d; 46 | border-color: #ccc; 47 | } 48 | .btn-default:hover, 49 | .btn-default:focus { 50 | background-color: #1e2023; 51 | background-position: 0 -15px; 52 | } 53 | .btn-default:active, 54 | .btn-default.active { 55 | background-color: #1e2023; 56 | border-color: #191b1d; 57 | } 58 | .btn-default:disabled, 59 | .btn-default[disabled] { 60 | background-color: #1e2023; 61 | background-image: none; 62 | } 63 | .btn-primary { 64 | background-image: -webkit-linear-gradient(top, #7a8288 0%, #5d6368 100%); 65 | background-image: -o-linear-gradient(top, #7a8288 0%, #5d6368 100%); 66 | background-image: -webkit-gradient(linear, left top, left bottom, from(#7a8288), to(#5d6368)); 67 | background-image: linear-gradient(to bottom, #7a8288 0%, #5d6368 100%); 68 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7a8288', endColorstr='#ff5d6368', GradientType=0); 69 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 70 | background-repeat: repeat-x; 71 | border-color: #585e62; 72 | } 73 | .btn-primary:hover, 74 | .btn-primary:focus { 75 | background-color: #5d6368; 76 | background-position: 0 -15px; 77 | } 78 | .btn-primary:active, 79 | .btn-primary.active { 80 | background-color: #5d6368; 81 | border-color: #585e62; 82 | } 83 | .btn-primary:disabled, 84 | .btn-primary[disabled] { 85 | background-color: #5d6368; 86 | background-image: none; 87 | } 88 | .btn-success { 89 | background-image: -webkit-linear-gradient(top, #62c462 0%, #40a940 100%); 90 | background-image: -o-linear-gradient(top, #62c462 0%, #40a940 100%); 91 | background-image: -webkit-gradient(linear, left top, left bottom, from(#62c462), to(#40a940)); 92 | background-image: linear-gradient(to bottom, #62c462 0%, #40a940 100%); 93 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff40a940', GradientType=0); 94 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 95 | background-repeat: repeat-x; 96 | border-color: #3da23d; 97 | } 98 | .btn-success:hover, 99 | .btn-success:focus { 100 | background-color: #40a940; 101 | background-position: 0 -15px; 102 | } 103 | .btn-success:active, 104 | .btn-success.active { 105 | background-color: #40a940; 106 | border-color: #3da23d; 107 | } 108 | .btn-success:disabled, 109 | .btn-success[disabled] { 110 | background-color: #40a940; 111 | background-image: none; 112 | } 113 | .btn-info { 114 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 115 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 116 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 117 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 118 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 119 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 120 | background-repeat: repeat-x; 121 | border-color: #28a4c9; 122 | } 123 | .btn-info:hover, 124 | .btn-info:focus { 125 | background-color: #2aabd2; 126 | background-position: 0 -15px; 127 | } 128 | .btn-info:active, 129 | .btn-info.active { 130 | background-color: #2aabd2; 131 | border-color: #28a4c9; 132 | } 133 | .btn-info:disabled, 134 | .btn-info[disabled] { 135 | background-color: #2aabd2; 136 | background-image: none; 137 | } 138 | .btn-warning { 139 | background-image: -webkit-linear-gradient(top, #f89406 0%, #bc7005 100%); 140 | background-image: -o-linear-gradient(top, #f89406 0%, #bc7005 100%); 141 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f89406), to(#bc7005)); 142 | background-image: linear-gradient(to bottom, #f89406 0%, #bc7005 100%); 143 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#ffbc7005', GradientType=0); 144 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 145 | background-repeat: repeat-x; 146 | border-color: #b26a04; 147 | } 148 | .btn-warning:hover, 149 | .btn-warning:focus { 150 | background-color: #bc7005; 151 | background-position: 0 -15px; 152 | } 153 | .btn-warning:active, 154 | .btn-warning.active { 155 | background-color: #bc7005; 156 | border-color: #b26a04; 157 | } 158 | .btn-warning:disabled, 159 | .btn-warning[disabled] { 160 | background-color: #bc7005; 161 | background-image: none; 162 | } 163 | .btn-danger { 164 | background-image: -webkit-linear-gradient(top, #ee5f5b 0%, #e82924 100%); 165 | background-image: -o-linear-gradient(top, #ee5f5b 0%, #e82924 100%); 166 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ee5f5b), to(#e82924)); 167 | background-image: linear-gradient(to bottom, #ee5f5b 0%, #e82924 100%); 168 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffe82924', GradientType=0); 169 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 170 | background-repeat: repeat-x; 171 | border-color: #e7201a; 172 | } 173 | .btn-danger:hover, 174 | .btn-danger:focus { 175 | background-color: #e82924; 176 | background-position: 0 -15px; 177 | } 178 | .btn-danger:active, 179 | .btn-danger.active { 180 | background-color: #e82924; 181 | border-color: #e7201a; 182 | } 183 | .btn-danger:disabled, 184 | .btn-danger[disabled] { 185 | background-color: #e82924; 186 | background-image: none; 187 | } 188 | .thumbnail, 189 | .img-thumbnail { 190 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 191 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 192 | } 193 | .dropdown-menu > li > a:hover, 194 | .dropdown-menu > li > a:focus { 195 | background-color: #1c1e22; 196 | background-image: -webkit-linear-gradient(top, #272b30 0%, #1c1e22 100%); 197 | background-image: -o-linear-gradient(top, #272b30 0%, #1c1e22 100%); 198 | background-image: -webkit-gradient(linear, left top, left bottom, from(#272b30), to(#1c1e22)); 199 | background-image: linear-gradient(to bottom, #272b30 0%, #1c1e22 100%); 200 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff272b30', endColorstr='#ff1c1e22', GradientType=0); 201 | background-repeat: repeat-x; 202 | } 203 | .dropdown-menu > .active > a, 204 | .dropdown-menu > .active > a:hover, 205 | .dropdown-menu > .active > a:focus { 206 | background-color: #1c1e22; 207 | background-image: -webkit-linear-gradient(top, #272b30 0%, #1c1e22 100%); 208 | background-image: -o-linear-gradient(top, #272b30 0%, #1c1e22 100%); 209 | background-image: -webkit-gradient(linear, left top, left bottom, from(#272b30), to(#1c1e22)); 210 | background-image: linear-gradient(to bottom, #272b30 0%, #1c1e22 100%); 211 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff272b30', endColorstr='#ff1c1e22', GradientType=0); 212 | background-repeat: repeat-x; 213 | } 214 | .navbar-default { 215 | background-image: -webkit-linear-gradient(top, #515960 0%, #3a3f44 100%); 216 | background-image: -o-linear-gradient(top, #515960 0%, #3a3f44 100%); 217 | background-image: -webkit-gradient(linear, left top, left bottom, from(#515960), to(#3a3f44)); 218 | background-image: linear-gradient(to bottom, #515960 0%, #3a3f44 100%); 219 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff515960', endColorstr='#ff3a3f44', GradientType=0); 220 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 221 | background-repeat: repeat-x; 222 | border-radius: 4px; 223 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 224 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 225 | } 226 | .navbar-default .navbar-nav > .active > a { 227 | background-image: -webkit-linear-gradient(top, #2e3236 0%, #353a3e 100%); 228 | background-image: -o-linear-gradient(top, #2e3236 0%, #353a3e 100%); 229 | background-image: -webkit-gradient(linear, left top, left bottom, from(#2e3236), to(#353a3e)); 230 | background-image: linear-gradient(to bottom, #2e3236 0%, #353a3e 100%); 231 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2e3236', endColorstr='#ff353a3e', GradientType=0); 232 | background-repeat: repeat-x; 233 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 234 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 235 | } 236 | .navbar-brand, 237 | .navbar-nav > li > a { 238 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 239 | } 240 | .navbar-inverse { 241 | background-image: -webkit-linear-gradient(top, #959ba0 0%, #7a8288 100%); 242 | background-image: -o-linear-gradient(top, #959ba0 0%, #7a8288 100%); 243 | background-image: -webkit-gradient(linear, left top, left bottom, from(#959ba0), to(#7a8288)); 244 | background-image: linear-gradient(to bottom, #959ba0 0%, #7a8288 100%); 245 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff959ba0', endColorstr='#ff7a8288', GradientType=0); 246 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 247 | background-repeat: repeat-x; 248 | } 249 | .navbar-inverse .navbar-nav > .active > a { 250 | background-image: -webkit-linear-gradient(top, #7a8288 0%, #81888e 100%); 251 | background-image: -o-linear-gradient(top, #7a8288 0%, #81888e 100%); 252 | background-image: -webkit-gradient(linear, left top, left bottom, from(#7a8288), to(#81888e)); 253 | background-image: linear-gradient(to bottom, #7a8288 0%, #81888e 100%); 254 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7a8288', endColorstr='#ff81888e', GradientType=0); 255 | background-repeat: repeat-x; 256 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 257 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 258 | } 259 | .navbar-inverse .navbar-brand, 260 | .navbar-inverse .navbar-nav > li > a { 261 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 262 | } 263 | .navbar-static-top, 264 | .navbar-fixed-top, 265 | .navbar-fixed-bottom { 266 | border-radius: 0; 267 | } 268 | .alert { 269 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 270 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 271 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 272 | } 273 | .alert-success { 274 | background-image: -webkit-linear-gradient(top, #62c462 0%, #46ba46 100%); 275 | background-image: -o-linear-gradient(top, #62c462 0%, #46ba46 100%); 276 | background-image: -webkit-gradient(linear, left top, left bottom, from(#62c462), to(#46ba46)); 277 | background-image: linear-gradient(to bottom, #62c462 0%, #46ba46 100%); 278 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff46ba46', GradientType=0); 279 | background-repeat: repeat-x; 280 | border-color: #3b9e3b; 281 | } 282 | .alert-info { 283 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #3bb4d8 100%); 284 | background-image: -o-linear-gradient(top, #5bc0de 0%, #3bb4d8 100%); 285 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#3bb4d8)); 286 | background-image: linear-gradient(to bottom, #5bc0de 0%, #3bb4d8 100%); 287 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff3bb4d8', GradientType=0); 288 | background-repeat: repeat-x; 289 | border-color: #28a1c5; 290 | } 291 | .alert-warning { 292 | background-image: -webkit-linear-gradient(top, #f89406 0%, #d37e05 100%); 293 | background-image: -o-linear-gradient(top, #f89406 0%, #d37e05 100%); 294 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f89406), to(#d37e05)); 295 | background-image: linear-gradient(to bottom, #f89406 0%, #d37e05 100%); 296 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#ffd37e05', GradientType=0); 297 | background-repeat: repeat-x; 298 | border-color: #ad6704; 299 | } 300 | .alert-danger { 301 | background-image: -webkit-linear-gradient(top, #ee5f5b 0%, #ea3d38 100%); 302 | background-image: -o-linear-gradient(top, #ee5f5b 0%, #ea3d38 100%); 303 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ee5f5b), to(#ea3d38)); 304 | background-image: linear-gradient(to bottom, #ee5f5b 0%, #ea3d38 100%); 305 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffea3d38', GradientType=0); 306 | background-repeat: repeat-x; 307 | border-color: #e51d18; 308 | } 309 | .progress { 310 | background-image: -webkit-linear-gradient(top, #121417 0%, #1c1e22 100%); 311 | background-image: -o-linear-gradient(top, #121417 0%, #1c1e22 100%); 312 | background-image: -webkit-gradient(linear, left top, left bottom, from(#121417), to(#1c1e22)); 313 | background-image: linear-gradient(to bottom, #121417 0%, #1c1e22 100%); 314 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff121417', endColorstr='#ff1c1e22', GradientType=0); 315 | background-repeat: repeat-x; 316 | } 317 | .progress-bar { 318 | background-image: -webkit-linear-gradient(top, #7a8288 0%, #62686d 100%); 319 | background-image: -o-linear-gradient(top, #7a8288 0%, #62686d 100%); 320 | background-image: -webkit-gradient(linear, left top, left bottom, from(#7a8288), to(#62686d)); 321 | background-image: linear-gradient(to bottom, #7a8288 0%, #62686d 100%); 322 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7a8288', endColorstr='#ff62686d', GradientType=0); 323 | background-repeat: repeat-x; 324 | } 325 | .progress-bar-success { 326 | background-image: -webkit-linear-gradient(top, #62c462 0%, #42b142 100%); 327 | background-image: -o-linear-gradient(top, #62c462 0%, #42b142 100%); 328 | background-image: -webkit-gradient(linear, left top, left bottom, from(#62c462), to(#42b142)); 329 | background-image: linear-gradient(to bottom, #62c462 0%, #42b142 100%); 330 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff42b142', GradientType=0); 331 | background-repeat: repeat-x; 332 | } 333 | .progress-bar-info { 334 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 335 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 336 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 337 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 338 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 339 | background-repeat: repeat-x; 340 | } 341 | .progress-bar-warning { 342 | background-image: -webkit-linear-gradient(top, #f89406 0%, #c67605 100%); 343 | background-image: -o-linear-gradient(top, #f89406 0%, #c67605 100%); 344 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f89406), to(#c67605)); 345 | background-image: linear-gradient(to bottom, #f89406 0%, #c67605 100%); 346 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#ffc67605', GradientType=0); 347 | background-repeat: repeat-x; 348 | } 349 | .progress-bar-danger { 350 | background-image: -webkit-linear-gradient(top, #ee5f5b 0%, #e9322d 100%); 351 | background-image: -o-linear-gradient(top, #ee5f5b 0%, #e9322d 100%); 352 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ee5f5b), to(#e9322d)); 353 | background-image: linear-gradient(to bottom, #ee5f5b 0%, #e9322d 100%); 354 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffe9322d', GradientType=0); 355 | background-repeat: repeat-x; 356 | } 357 | .progress-bar-striped { 358 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 359 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 360 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 361 | } 362 | .list-group { 363 | border-radius: 4px; 364 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 365 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 366 | } 367 | .list-group-item.active, 368 | .list-group-item.active:hover, 369 | .list-group-item.active:focus { 370 | text-shadow: 0 -1px 0 #272b30; 371 | background-image: -webkit-linear-gradient(top, #3e444c 0%, #2d3137 100%); 372 | background-image: -o-linear-gradient(top, #3e444c 0%, #2d3137 100%); 373 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3e444c), to(#2d3137)); 374 | background-image: linear-gradient(to bottom, #3e444c 0%, #2d3137 100%); 375 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3e444c', endColorstr='#ff2d3137', GradientType=0); 376 | background-repeat: repeat-x; 377 | border-color: rgba(0, 0, 0, .6); 378 | } 379 | .panel { 380 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 381 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 382 | } 383 | .panel-default > .panel-heading { 384 | background-image: -webkit-linear-gradient(top, #3e444c 0%, #32383e 100%); 385 | background-image: -o-linear-gradient(top, #3e444c 0%, #32383e 100%); 386 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3e444c), to(#32383e)); 387 | background-image: linear-gradient(to bottom, #3e444c 0%, #32383e 100%); 388 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3e444c', endColorstr='#ff32383e', GradientType=0); 389 | background-repeat: repeat-x; 390 | } 391 | .panel-primary > .panel-heading { 392 | background-image: -webkit-linear-gradient(top, #7a8288 0%, #6e757b 100%); 393 | background-image: -o-linear-gradient(top, #7a8288 0%, #6e757b 100%); 394 | background-image: -webkit-gradient(linear, left top, left bottom, from(#7a8288), to(#6e757b)); 395 | background-image: linear-gradient(to bottom, #7a8288 0%, #6e757b 100%); 396 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7a8288', endColorstr='#ff6e757b', GradientType=0); 397 | background-repeat: repeat-x; 398 | } 399 | .panel-success > .panel-heading { 400 | background-image: -webkit-linear-gradient(top, #62c462 0%, #4fbd4f 100%); 401 | background-image: -o-linear-gradient(top, #62c462 0%, #4fbd4f 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#62c462), to(#4fbd4f)); 403 | background-image: linear-gradient(to bottom, #62c462 0%, #4fbd4f 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff4fbd4f', GradientType=0); 405 | background-repeat: repeat-x; 406 | } 407 | .panel-info > .panel-heading { 408 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #46b8da 100%); 409 | background-image: -o-linear-gradient(top, #5bc0de 0%, #46b8da 100%); 410 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#46b8da)); 411 | background-image: linear-gradient(to bottom, #5bc0de 0%, #46b8da 100%); 412 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff46b8da', GradientType=0); 413 | background-repeat: repeat-x; 414 | } 415 | .panel-warning > .panel-heading { 416 | background-image: -webkit-linear-gradient(top, #f89406 0%, #df8505 100%); 417 | background-image: -o-linear-gradient(top, #f89406 0%, #df8505 100%); 418 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f89406), to(#df8505)); 419 | background-image: linear-gradient(to bottom, #f89406 0%, #df8505 100%); 420 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#ffdf8505', GradientType=0); 421 | background-repeat: repeat-x; 422 | } 423 | .panel-danger > .panel-heading { 424 | background-image: -webkit-linear-gradient(top, #ee5f5b 0%, #ec4844 100%); 425 | background-image: -o-linear-gradient(top, #ee5f5b 0%, #ec4844 100%); 426 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ee5f5b), to(#ec4844)); 427 | background-image: linear-gradient(to bottom, #ee5f5b 0%, #ec4844 100%); 428 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffec4844', GradientType=0); 429 | background-repeat: repeat-x; 430 | } 431 | .well { 432 | background-image: -webkit-linear-gradient(top, #101214 0%, #1c1e22 100%); 433 | background-image: -o-linear-gradient(top, #101214 0%, #1c1e22 100%); 434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#101214), to(#1c1e22)); 435 | background-image: linear-gradient(to bottom, #101214 0%, #1c1e22 100%); 436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff101214', endColorstr='#ff1c1e22', GradientType=0); 437 | background-repeat: repeat-x; 438 | border-color: #050506; 439 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 440 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 441 | } 442 | /*# sourceMappingURL=bootstrap-theme.css.map */ 443 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/css/bootstrap-theme.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAeA;;;;;;EAME,0CAAA;EC+CA,6FAAA;EACQ,qFAAA;EC5DT;AFiBC;;;;;;;;;;;;EC0CA,0DAAA;EACQ,kDAAA;EC7CT;AFqCC;;EAEE,wBAAA;EEnCH;AFwCD;EG/CI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EA+B2C,2BAAA;EAA2B,oBAAA;EE7BvE;AFAC;;EAEE,2BAAA;EACA,8BAAA;EEEH;AFCC;;EAEE,2BAAA;EACA,uBAAA;EECH;AFEC;;EAEE,2BAAA;EACA,wBAAA;EEAH;AFeD;EGhDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0BD;AFxBC;;EAEE,2BAAA;EACA,8BAAA;EE0BH;AFvBC;;EAEE,2BAAA;EACA,uBAAA;EEyBH;AFtBC;;EAEE,2BAAA;EACA,wBAAA;EEwBH;AFRD;EGjDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EEkDD;AFhDC;;EAEE,2BAAA;EACA,8BAAA;EEkDH;AF/CC;;EAEE,2BAAA;EACA,uBAAA;EEiDH;AF9CC;;EAEE,2BAAA;EACA,wBAAA;EEgDH;AF/BD;EGlDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0ED;AFxEC;;EAEE,2BAAA;EACA,8BAAA;EE0EH;AFvEC;;EAEE,2BAAA;EACA,uBAAA;EEyEH;AFtEC;;EAEE,2BAAA;EACA,wBAAA;EEwEH;AFtDD;EGnDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EEkGD;AFhGC;;EAEE,2BAAA;EACA,8BAAA;EEkGH;AF/FC;;EAEE,2BAAA;EACA,uBAAA;EEiGH;AF9FC;;EAEE,2BAAA;EACA,wBAAA;EEgGH;AF7ED;EGpDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0HD;AFxHC;;EAEE,2BAAA;EACA,8BAAA;EE0HH;AFvHC;;EAEE,2BAAA;EACA,uBAAA;EEyHH;AFtHC;;EAEE,2BAAA;EACA,wBAAA;EEwHH;AF7FD;;ECbE,oDAAA;EACQ,4CAAA;EC8GT;AFvFD;;EGvEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHsEF,2BAAA;EE6FD;AF3FD;;;EG5EI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4EF,2BAAA;EEiGD;AFvFD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EJ4GA,oBAAA;EC9CA,6FAAA;EACQ,qFAAA;EC4IT;AFlGD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,0DAAA;EACQ,kDAAA;ECqJT;AF/FD;;EAEE,gDAAA;EEiGD;AF7FD;EG5GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EFgOD;AFrGD;EG5GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,yDAAA;EACQ,iDAAA;EC0KT;AF9GD;;EAWI,2CAAA;EEuGH;AFlGD;;;EAGE,kBAAA;EEoGD;AF1FD;EACE,+CAAA;EC3FA,4FAAA;EACQ,oFAAA;ECwLT;AFlFD;EGtJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EE8FD;AFzFD;EGvJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EEsGD;AFhGD;EGxJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EE8GD;AFvGD;EGzJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EEsHD;AFtGD;EGlKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED2QH;AFnGD;EG5KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDkRH;AFzGD;EG7KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDyRH;AF/GD;EG9KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDgSH;AFrHD;EG/KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDuSH;AF3HD;EGhLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8SH;AF9HD;EGnJI,+MAAA;EACA,0MAAA;EACA,uMAAA;EDoRH;AF1HD;EACE,oBAAA;EC/IA,oDAAA;EACQ,4CAAA;EC4QT;AF3HD;;;EAGE,+BAAA;EGpME,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHkMF,kCAAA;EEiID;AFvHD;ECjKE,mDAAA;EACQ,2CAAA;EC2RT;AFjHD;EG1NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8UH;AFvHD;EG3NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDqVH;AF7HD;EG5NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED4VH;AFnID;EG7NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDmWH;AFzID;EG9NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED0WH;AF/ID;EG/NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDiXH;AF9ID;EGvOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHqOF,uBAAA;EC1LA,2FAAA;EACQ,mFAAA;EC+UT","file":"bootstrap-theme.css","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &:disabled,\n &[disabled] {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n",null,"// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#3a3f44 0,#1e2023 100%);background-image:-o-linear-gradient(top,#3a3f44 0,#1e2023 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3a3f44),to(#1e2023));background-image:linear-gradient(to bottom,#3a3f44 0,#1e2023 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3a3f44', endColorstr='#ff1e2023', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#191b1d;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#1e2023;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#1e2023;border-color:#191b1d}.btn-default:disabled,.btn-default[disabled]{background-color:#1e2023;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#7a8288 0,#5d6368 100%);background-image:-o-linear-gradient(top,#7a8288 0,#5d6368 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#7a8288),to(#5d6368));background-image:linear-gradient(to bottom,#7a8288 0,#5d6368 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7a8288', endColorstr='#ff5d6368', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#585e62}.btn-primary:hover,.btn-primary:focus{background-color:#5d6368;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#5d6368;border-color:#585e62}.btn-primary:disabled,.btn-primary[disabled]{background-color:#5d6368;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#62c462 0,#40a940 100%);background-image:-o-linear-gradient(top,#62c462 0,#40a940 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#62c462),to(#40a940));background-image:linear-gradient(to bottom,#62c462 0,#40a940 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff40a940', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3da23d}.btn-success:hover,.btn-success:focus{background-color:#40a940;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#40a940;border-color:#3da23d}.btn-success:disabled,.btn-success[disabled]{background-color:#40a940;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f89406 0,#bc7005 100%);background-image:-o-linear-gradient(top,#f89406 0,#bc7005 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f89406),to(#bc7005));background-image:linear-gradient(to bottom,#f89406 0,#bc7005 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#ffbc7005', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b26a04}.btn-warning:hover,.btn-warning:focus{background-color:#bc7005;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#bc7005;border-color:#b26a04}.btn-warning:disabled,.btn-warning[disabled]{background-color:#bc7005;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#ee5f5b 0,#e82924 100%);background-image:-o-linear-gradient(top,#ee5f5b 0,#e82924 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ee5f5b),to(#e82924));background-image:linear-gradient(to bottom,#ee5f5b 0,#e82924 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffe82924', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e7201a}.btn-danger:hover,.btn-danger:focus{background-color:#e82924;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#e82924;border-color:#e7201a}.btn-danger:disabled,.btn-danger[disabled]{background-color:#e82924;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#1c1e22;background-image:-webkit-linear-gradient(top,#272b30 0,#1c1e22 100%);background-image:-o-linear-gradient(top,#272b30 0,#1c1e22 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#272b30),to(#1c1e22));background-image:linear-gradient(to bottom,#272b30 0,#1c1e22 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff272b30', endColorstr='#ff1c1e22', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#1c1e22;background-image:-webkit-linear-gradient(top,#272b30 0,#1c1e22 100%);background-image:-o-linear-gradient(top,#272b30 0,#1c1e22 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#272b30),to(#1c1e22));background-image:linear-gradient(to bottom,#272b30 0,#1c1e22 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff272b30', endColorstr='#ff1c1e22', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#515960 0,#3a3f44 100%);background-image:-o-linear-gradient(top,#515960 0,#3a3f44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#515960),to(#3a3f44));background-image:linear-gradient(to bottom,#515960 0,#3a3f44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff515960', endColorstr='#ff3a3f44', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#2e3236 0,#353a3e 100%);background-image:-o-linear-gradient(top,#2e3236 0,#353a3e 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#2e3236),to(#353a3e));background-image:linear-gradient(to bottom,#2e3236 0,#353a3e 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2e3236', endColorstr='#ff353a3e', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#959ba0 0,#7a8288 100%);background-image:-o-linear-gradient(top,#959ba0 0,#7a8288 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#959ba0),to(#7a8288));background-image:linear-gradient(to bottom,#959ba0 0,#7a8288 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff959ba0', endColorstr='#ff7a8288', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#7a8288 0,#81888e 100%);background-image:-o-linear-gradient(top,#7a8288 0,#81888e 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#7a8288),to(#81888e));background-image:linear-gradient(to bottom,#7a8288 0,#81888e 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7a8288', endColorstr='#ff81888e', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#62c462 0,#46ba46 100%);background-image:-o-linear-gradient(top,#62c462 0,#46ba46 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#62c462),to(#46ba46));background-image:linear-gradient(to bottom,#62c462 0,#46ba46 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff46ba46', GradientType=0);background-repeat:repeat-x;border-color:#3b9e3b}.alert-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#3bb4d8 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#3bb4d8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#3bb4d8));background-image:linear-gradient(to bottom,#5bc0de 0,#3bb4d8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff3bb4d8', GradientType=0);background-repeat:repeat-x;border-color:#28a1c5}.alert-warning{background-image:-webkit-linear-gradient(top,#f89406 0,#d37e05 100%);background-image:-o-linear-gradient(top,#f89406 0,#d37e05 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f89406),to(#d37e05));background-image:linear-gradient(to bottom,#f89406 0,#d37e05 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#ffd37e05', GradientType=0);background-repeat:repeat-x;border-color:#ad6704}.alert-danger{background-image:-webkit-linear-gradient(top,#ee5f5b 0,#ea3d38 100%);background-image:-o-linear-gradient(top,#ee5f5b 0,#ea3d38 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ee5f5b),to(#ea3d38));background-image:linear-gradient(to bottom,#ee5f5b 0,#ea3d38 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffea3d38', GradientType=0);background-repeat:repeat-x;border-color:#e51d18}.progress{background-image:-webkit-linear-gradient(top,#121417 0,#1c1e22 100%);background-image:-o-linear-gradient(top,#121417 0,#1c1e22 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#121417),to(#1c1e22));background-image:linear-gradient(to bottom,#121417 0,#1c1e22 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff121417', endColorstr='#ff1c1e22', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#7a8288 0,#62686d 100%);background-image:-o-linear-gradient(top,#7a8288 0,#62686d 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#7a8288),to(#62686d));background-image:linear-gradient(to bottom,#7a8288 0,#62686d 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7a8288', endColorstr='#ff62686d', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#62c462 0,#42b142 100%);background-image:-o-linear-gradient(top,#62c462 0,#42b142 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#62c462),to(#42b142));background-image:linear-gradient(to bottom,#62c462 0,#42b142 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff42b142', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f89406 0,#c67605 100%);background-image:-o-linear-gradient(top,#f89406 0,#c67605 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f89406),to(#c67605));background-image:linear-gradient(to bottom,#f89406 0,#c67605 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#ffc67605', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#ee5f5b 0,#e9322d 100%);background-image:-o-linear-gradient(top,#ee5f5b 0,#e9322d 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ee5f5b),to(#e9322d));background-image:linear-gradient(to bottom,#ee5f5b 0,#e9322d 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffe9322d', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #272b30;background-image:-webkit-linear-gradient(top,#3e444c 0,#2d3137 100%);background-image:-o-linear-gradient(top,#3e444c 0,#2d3137 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3e444c),to(#2d3137));background-image:linear-gradient(to bottom,#3e444c 0,#2d3137 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3e444c', endColorstr='#ff2d3137', GradientType=0);background-repeat:repeat-x;border-color:rgba(0,0,0,.6)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#3e444c 0,#32383e 100%);background-image:-o-linear-gradient(top,#3e444c 0,#32383e 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3e444c),to(#32383e));background-image:linear-gradient(to bottom,#3e444c 0,#32383e 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3e444c', endColorstr='#ff32383e', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#7a8288 0,#6e757b 100%);background-image:-o-linear-gradient(top,#7a8288 0,#6e757b 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#7a8288),to(#6e757b));background-image:linear-gradient(to bottom,#7a8288 0,#6e757b 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff7a8288', endColorstr='#ff6e757b', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#62c462 0,#4fbd4f 100%);background-image:-o-linear-gradient(top,#62c462 0,#4fbd4f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#62c462),to(#4fbd4f));background-image:linear-gradient(to bottom,#62c462 0,#4fbd4f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff4fbd4f', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#5bc0de 0,#46b8da 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#46b8da 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#46b8da));background-image:linear-gradient(to bottom,#5bc0de 0,#46b8da 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff46b8da', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#f89406 0,#df8505 100%);background-image:-o-linear-gradient(top,#f89406 0,#df8505 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f89406),to(#df8505));background-image:linear-gradient(to bottom,#f89406 0,#df8505 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#ffdf8505', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#ee5f5b 0,#ec4844 100%);background-image:-o-linear-gradient(top,#ee5f5b 0,#ec4844 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ee5f5b),to(#ec4844));background-image:linear-gradient(to bottom,#ee5f5b 0,#ec4844 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffec4844', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#101214 0,#1c1e22 100%);background-image:-o-linear-gradient(top,#101214 0,#1c1e22 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#101214),to(#1c1e22));background-image:linear-gradient(to bottom,#101214 0,#1c1e22 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff101214', endColorstr='#ff1c1e22', GradientType=0);background-repeat:repeat-x;border-color:#050506;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/css/main.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* ========================================================================== 4 | Author's custom styles 5 | ========================================================================== */ 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/PowerSite/3ca9d62783ee8283de32c2aa156acd6a9008f5ef/PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/favicon.ico -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/feed.cshtml: -------------------------------------------------------------------------------- 1 | @using System 2 | @using System.Linq 3 | @using PowerSite 4 | @using PowerSite.DataModel 5 | @inherits RazorEngine.Templating.TemplateBase> 6 | 7 | 8 | 9 | 10 | @Site.Current.Title 11 | @Site.Current.BlogUrl 12 | @Site.Current.Description 13 | en 14 | @DateTime.UtcNow.ToString("r") 15 | http://HuddledMasses.org/PowerSite 16 | http://blogs.law.harvard.edu/tech/rss 17 | @foreach(var post in Model){ 18 | 19 | @post.Title 20 | @post.Author.Name 21 | @Raw(post.FullyQualifiedUrl) 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/PowerSite/3ca9d62783ee8283de32c2aa156acd6a9008f5ef/PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/PowerSite/3ca9d62783ee8283de32c2aa156acd6a9008f5ef/PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/PowerSite/3ca9d62783ee8283de32c2aa156acd6a9008f5ef/PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/js/main.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js: -------------------------------------------------------------------------------- 1 | /* Modernizr 2.6.2 (Custom Build) | MIT & BSD 2 | * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load 3 | */ 4 | ;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f #mq-test-1 { width: 42px; }';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document); 9 | 10 | /*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 11 | (function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this); -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/page.cshtml: -------------------------------------------------------------------------------- 1 | @using PowerSite.DataModel 2 | @inherits RazorEngine.Templating.TemplateBase 3 | @{ 4 | Layout = "SiteLayout.cshtml"; 5 | ViewBag.Active = "Home"; 6 | } 7 | 8 | 9 | @Raw(Model.RenderedContent) 10 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/Themes/BootstrapBlog/post.cshtml: -------------------------------------------------------------------------------- 1 | @using PowerSite 2 | @using PowerSite.Actions 3 | @using PowerSite.DataModel 4 | @inherits RazorEngine.Templating.TemplateBase 5 | @{ 6 | Layout = "BlogLayout.cshtml"; 7 | ViewBag.Author = Model.Author.Name; 8 | ViewBag.Title = Model.Title + " - " + Site.Current.Title; 9 | } 10 | 11 |
12 |

@Model.Title

13 | 16 | @Raw(Model.RenderedContent) 17 |
18 | Tagged: 19 |
    20 | @foreach (var tag in Model.Tags) 21 | { 22 |
  • @tag
  • 23 | } 24 |
25 |
26 |
27 | -------------------------------------------------------------------------------- /PowerSite.Specs/Samples/Blog/config.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | # Note that as with any PSD1 in PowerShell, this config file is translateable 3 | # However, in addition, we want to support translating your posts ... 4 | # You simply need to provide a copy with the specific file name pattern: 5 | # FileName.lang.ext 6 | 7 | # Please see the ReadMe for more complete documentation of the settings... 8 | Author = @{ 9 | Id = 'Jaykul' 10 | Name = 'Joel "Jaykul" Bennett' 11 | Email = "Jaykul@HuddledMasses.org" 12 | Url = "http://HuddledMasses.org/about_me" 13 | } 14 | 15 | # This is the main URL for your site. It will be used in a prominent link 16 | RootUrl = "http://HuddledMasses.org/" 17 | 18 | # This is the path where blog posts will be placed, below the RootUel 19 | # If not set, it defaults to empty, which is just fine for a blog, but if 20 | # if you want to also have static pages, and not worry about confusing the paths, 21 | # just set this path to something like "blog/" 22 | BlogPath = "blog/" 23 | 24 | # Data about this site 25 | Title = "Huddled Masses" # (translatable) 26 | Description = "You can do more than breathe for free..." # (translatable) 27 | 28 | # This controls which set of layout templates will be used 29 | Theme = "BootstrapBlog" 30 | 31 | # The rest of these settings are entirely optional: 32 | 33 | # Instead of saving files as BlogUrl/.html, store them in BlogUrl//index.html 34 | # Generates links to BlogUrl/, make sure "index.html" is your site's default document. 35 | PrettyUrl = $True 36 | 37 | # Controls how many posts are rendered on each index page 38 | PostsPerArchivePage = 5 39 | 40 | # Date format used to display post dates. 41 | # Passed to DateTimeOffset.ToString(...) 42 | DateFormat = 'yyyy-MM-dd H:mm' 43 | #################### 44 | ### SETTINGS BELOW THIS ARE WISHFUL THINKING 45 | #################### 46 | 47 | # This should control which languages we should generate, but doesn't do anything yet 48 | DefaultCulture = "En-US" 49 | # Translations = "Es", "De" 50 | 51 | 52 | # Post's dates use UTC by default, if you want to use a different timezone, 53 | # Specify the name here: 54 | # To get a list of valid names, in PowerShell, run this, and use the "Id": 55 | # [System.TimeZoneInfo]::GetSystemTimeZones() | ft Id, DisplayName -auto 56 | TimeZoneInfo = "Eastern Standard Time" 57 | 58 | } -------------------------------------------------------------------------------- /PowerSite.Specs/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /PowerSite.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30723.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerSite", "PowerSite\PowerSite.csproj", "{4A8F250C-3A76-423D-883B-CEC3687895E7}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerSite.Specs", "PowerSite.Specs\PowerSite.Specs.csproj", "{61D72176-9C50-4D38-B6AC-91A19E197C26}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReadMe", "ReadMe", "{C97FE500-0BF7-4C15-B704-D4D11BA5F883}" 11 | ProjectSection(SolutionItems) = preProject 12 | ReadMe.md = ReadMe.md 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {4A8F250C-3A76-423D-883B-CEC3687895E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {4A8F250C-3A76-423D-883B-CEC3687895E7}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {4A8F250C-3A76-423D-883B-CEC3687895E7}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {4A8F250C-3A76-423D-883B-CEC3687895E7}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {61D72176-9C50-4D38-B6AC-91A19E197C26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {61D72176-9C50-4D38-B6AC-91A19E197C26}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {61D72176-9C50-4D38-B6AC-91A19E197C26}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {61D72176-9C50-4D38-B6AC-91A19E197C26}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | EndGlobal 34 | -------------------------------------------------------------------------------- /PowerSite.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | <data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="PowerSite" ModuleVersionMask="*" ClassMask="PowerSite.Actions.*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data> -------------------------------------------------------------------------------- /PowerSite.sln.GhostDoc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | .\Help 13 | PowerSite 14 | 15 | 16 | true 17 | false 18 | false 19 | false 20 | 21 | 22 | true 23 | false 24 | false 25 | false 26 | true 27 | true 28 | false 29 | 30 | 31 | true 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /PowerSite/Actions/BaseMefCommand.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.ComponentModel.Composition.Hosting; 3 | using System.IO; 4 | using System.Management.Automation; 5 | 6 | namespace PowerSite.Actions 7 | { 8 | public class BaseMefCommand : PSCmdlet 9 | { 10 | protected string _siteRootPath; 11 | 12 | protected override void BeginProcessing() 13 | { 14 | if (string.IsNullOrEmpty(_siteRootPath)) 15 | { 16 | _siteRootPath = CurrentProviderLocation("FileSystem").ProviderPath; 17 | } 18 | 19 | base.BeginProcessing(); 20 | } 21 | 22 | private CompositionContainer _container; 23 | 24 | /// 25 | /// Initializes the plugin catalog. 26 | /// 27 | /// The site root path. 28 | protected virtual void InitializePluginCatalog(string siteRootPath) 29 | { 30 | var catalog = new AggregateCatalog(); 31 | //Adds all the parts found in the same assembly as the Program class 32 | var assembly = typeof (BasePowerSiteCommand).Assembly; 33 | catalog.Catalogs.Add(new AssemblyCatalog(assembly)); 34 | 35 | if (!string.IsNullOrEmpty(siteRootPath) && Directory.Exists(siteRootPath)) 36 | { 37 | WriteVerbose("Site root: " + siteRootPath); 38 | var pluginRoot = Path.Combine(siteRootPath, "Plugins"); 39 | 40 | if (Directory.Exists(pluginRoot)) 41 | { 42 | catalog.Catalogs.Add(new DirectoryCatalog(pluginRoot)); 43 | } 44 | else 45 | { 46 | WriteVerbose("No Plugins directory found in site root: " + siteRootPath); 47 | } 48 | } 49 | else 50 | { 51 | WriteWarning("Could not determine module root"); 52 | } 53 | 54 | //Create the CompositionContainer with the parts in the catalog 55 | _container = new CompositionContainer(catalog); 56 | 57 | try 58 | { 59 | _container.ComposeParts(this); 60 | } 61 | catch (CompositionException compositionException) 62 | { 63 | WriteError(new ErrorRecord(compositionException, "PluginFailure", ErrorCategory.ResourceUnavailable, _container)); 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /PowerSite/Actions/BasePowerSiteCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Management.Automation; 7 | using PowerSite.Builtin; 8 | using PowerSite.DataModel; 9 | 10 | namespace PowerSite.Actions 11 | { 12 | public class BasicallyPowerSiteCommand : PSCmdlet 13 | { 14 | protected string _siteRootPath; 15 | protected Site _helper; 16 | 17 | protected dynamic Config { get { return _helper.Config; } } 18 | 19 | protected override void BeginProcessing() 20 | { 21 | base.BeginProcessing(); 22 | 23 | } 24 | 25 | protected override void EndProcessing() 26 | { 27 | _helper.Dispose(); 28 | base.EndProcessing(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /PowerSite/Actions/ConvertPageCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Management.Automation; 3 | using PowerSite.DataModel; 4 | 5 | namespace PowerSite.Actions 6 | { 7 | [Cmdlet(VerbsData.Convert, "Page")] 8 | public class ConvertPageCommand : PSCmdlet 9 | { 10 | [Parameter(Position = 0, ValueFromPipelineByPropertyName = true, ValueFromPipeline = true, ParameterSetName = "FromPath")] 11 | [Alias("PSPath")] 12 | public string Path { get; set; } 13 | 14 | [Parameter()] 15 | [Alias("Root")] 16 | public string SiteRootPath { get; set; } 17 | 18 | [Parameter(Position = 0, ValueFromPipeline = true, ParameterSetName = "FromPost")] 19 | public NamedContentBase Markup { get; set; } 20 | 21 | [Parameter()] 22 | public PSObject Data { get; set; } 23 | 24 | private string GetPluginPath(string path) 25 | { 26 | if (SiteRootPath != null) 27 | return SiteRootPath; 28 | 29 | ProviderInfo providerInfo; 30 | // Path is something like siteRoot\Posts\File.md 31 | // and after this, _siteRootPath is siteRoot\Posts 32 | path = System.IO.Path.GetDirectoryName(path); 33 | // and after this, _siteRootPath is siteRoot\ 34 | SiteRootPath = System.IO.Path.GetDirectoryName(path); 35 | SiteRootPath = GetResolvedProviderPathFromPSPath(SiteRootPath, out providerInfo).FirstOrDefault(); 36 | return SiteRootPath; 37 | } 38 | 39 | protected Site helper; 40 | 41 | protected override void ProcessRecord() 42 | { 43 | if (ParameterSetName == "FromPath") 44 | { 45 | if (helper == null) 46 | helper = Site.ForPath(GetPluginPath(Path)); 47 | 48 | ProviderInfo providerInfo; 49 | var files = GetResolvedProviderPathFromPSPath(Path, out providerInfo); 50 | foreach (var file in files) 51 | { 52 | Markup = new NamedContentBase(file, preloadContent: true); 53 | WriteObject(helper[Markup.Extension].Render(SiteRootPath, Markup.RawContent, Data)); 54 | } 55 | } 56 | else 57 | { 58 | if (helper == null) 59 | helper = Site.ForPath(GetPluginPath(Markup.SourcePath)); 60 | 61 | Markup.RenderedContent = helper[Markup.Extension].Render(SiteRootPath, Markup.RawContent, Data); 62 | WriteObject(Markup); 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /PowerSite/Actions/GetPowerSiteCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Management.Automation; 5 | using Microsoft.PowerShell.Commands; 6 | using PowerSite.Builtin; 7 | using PowerSite.DataModel; 8 | 9 | namespace PowerSite.Actions 10 | { 11 | [Cmdlet(VerbsCommon.Get, "PowerSite")] 12 | public class GetPowerSiteCommand : PSCmdlet 13 | { 14 | private string _siteRootPath; 15 | protected Site _helper; 16 | //[Parameter(ParameterSetName = "FromConfiguration")] 17 | //public PSObject Configuration 18 | //{ 19 | // get { return base.Config; } 20 | // set { base.Config = value; } 21 | //} 22 | 23 | [Parameter(ParameterSetName = "FromPath")] 24 | [Alias("PSPath", "Path", "Root")] 25 | public string SiteRootPath 26 | { 27 | get { return _siteRootPath; } 28 | set { _siteRootPath = value; } 29 | } 30 | 31 | protected override void BeginProcessing() 32 | { 33 | base.BeginProcessing(); 34 | switch (ParameterSetName) 35 | { 36 | case "FromPath": 37 | { 38 | ProviderInfo provider; 39 | _siteRootPath = GetResolvedProviderPathFromPSPath(_siteRootPath, out provider).SingleOrDefault(); 40 | if (provider.ImplementingType != typeof (FileSystemProvider)) 41 | { 42 | ThrowTerminatingError( 43 | new ErrorRecord( 44 | new DirectoryNotFoundException( 45 | string.Format("The SiteRootPath '{0}' is not a valid folder path", _siteRootPath)), "InvalidSiteRootPath", 46 | ErrorCategory.InvalidData, _siteRootPath)); 47 | } 48 | 49 | break; 50 | } 51 | default: 52 | { 53 | if (string.IsNullOrEmpty(_siteRootPath)) 54 | { 55 | _siteRootPath = CurrentProviderLocation("FileSystem").ProviderPath; 56 | } 57 | break; 58 | } 59 | } 60 | try 61 | { 62 | if (File.Exists(_siteRootPath)) 63 | { 64 | _siteRootPath = Path.GetDirectoryName(_siteRootPath); 65 | } 66 | 67 | _helper = Site.ForPath(_siteRootPath); 68 | } 69 | catch (IOException ex) 70 | { 71 | ThrowTerminatingError(new ErrorRecord(ex, "ConfigFileNotLoaded", ErrorCategory.InvalidData, _siteRootPath)); 72 | } 73 | } 74 | 75 | protected override void EndProcessing() 76 | { 77 | WriteObject(_helper); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /PowerSite/Actions/UpdatePowerSiteCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Management.Automation; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Microsoft.VisualBasic.FileIO; 9 | namespace PowerSite.Actions 10 | { 11 | [Cmdlet(VerbsData.Update, "PowerSite")] 12 | public class UpdatePowerSiteCommand : GetPowerSiteCommand 13 | { 14 | protected override void EndProcessing() 15 | { 16 | try 17 | { 18 | // 1. Parallel: Collect All Files (done) 19 | _helper.LoadDocuments(); 20 | var themeRoot = _helper.Theme.ThemeRoot; 21 | var cachePath = _helper.Paths["cache"]; 22 | var outputPath = _helper.Paths["output"]; 23 | 24 | // 2. Calculate destinations (output paths and URLs) 25 | 26 | if (FileSystem.DirectoryExists(cachePath)) 27 | { 28 | FileSystem.DeleteDirectory(cachePath, DeleteDirectoryOption.DeleteAllContents); 29 | } 30 | 31 | FileSystem.CreateDirectory(cachePath); 32 | // 2. XCopy static Theme parts (or copy everything and delete ones which need to be rendered) 33 | FileSystem.CopyDirectory(themeRoot, cachePath); 34 | 35 | foreach (var file in _helper.Keys. 36 | SelectMany(extension => Directory.EnumerateFiles(cachePath, string.Format("*.{0}", extension)))) 37 | { 38 | File.Delete(file); 39 | } 40 | 41 | // 3. XCopy static pages over the top of the theme 42 | FileSystem.CopyDirectory(_helper.Paths["static"], cachePath); 43 | 44 | // 4. Parallel: Render Markdown for each 45 | _helper.RenderDocuments(); 46 | // 5. Parallel: Render Page for each 47 | _helper.RenderTemplates(); 48 | 49 | 50 | // If we get to this point, we can replace the Output with the cache: 51 | if (FileSystem.DirectoryExists(outputPath)) 52 | { 53 | FileSystem.DeleteDirectory(outputPath, DeleteDirectoryOption.DeleteAllContents); 54 | } 55 | FileSystem.MoveDirectory(cachePath, outputPath); 56 | } 57 | catch (Exception ex) 58 | { 59 | WriteError(new ErrorRecord(ex, "FailedToProcess", ErrorCategory.NotSpecified, _helper)); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /PowerSite/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /PowerSite/Builtin/Renderers/MarkdownRenderer.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Management.Automation; 3 | using PowerSite.DataModel; 4 | 5 | namespace PowerSite.Builtin.Renderers 6 | { 7 | using System.ComponentModel.Composition; 8 | 9 | using MarkdownSharp; 10 | 11 | [Export(typeof(IRenderer))] 12 | [ExportMetadata("Extension", "md")] 13 | [Cmdlet(VerbsData.ConvertFrom, "Markdown")] 14 | 15 | public class MarkdownRenderer : IRenderer 16 | { 17 | 18 | public MarkdownRenderer() 19 | { 20 | MarkdownEngine = new Markdown(new MarkdownOptions() { AutoHyperlink = true }); 21 | } 22 | 23 | private Markdown MarkdownEngine { get; set; } 24 | 25 | public string Render(string siteKey, string template, dynamic data = null) 26 | { 27 | var engine = new Markdown(new MarkdownOptions() { AutoHyperlink = true }); 28 | return engine.Transform(template).Trim(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /PowerSite/Builtin/Renderers/RazorRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Composition; 4 | using System.Globalization; 5 | using System.IO; 6 | using System.Management.Automation; 7 | using PowerSite.Actions; 8 | using PowerSite.DataModel; 9 | using RazorEngine; 10 | using RazorEngine.Configuration; 11 | using RazorEngine.Templating; 12 | 13 | namespace PowerSite.Builtin.Renderers 14 | { 15 | [Export(typeof(IRenderer))] 16 | [ExportMetadata("Extension", "cshtml")] 17 | public class RazorRenderer : IRenderer 18 | { 19 | public string Render(string siteKey, string template, dynamic data) 20 | { 21 | string result = null; 22 | 23 | var config = new TemplateServiceConfiguration { Resolver = new TemplateResolver(siteKey) }; 24 | config.Namespaces.Add("System.IO"); 25 | config.Namespaces.Add("RazorEngine.Text"); 26 | 27 | using (var service = new TemplateService(config)) 28 | { 29 | Razor.SetTemplateService(service); 30 | 31 | var cacheName = template.GetHashCode().ToString(CultureInfo.InvariantCulture); 32 | 33 | try 34 | { 35 | var pso = data as PSObject; 36 | if (pso != null) 37 | { 38 | data = pso.BaseObject; 39 | } 40 | result = Razor.Parse(template, data, cacheName); 41 | } 42 | catch (TemplateCompilationException e) 43 | { 44 | foreach (var error in e.Errors) 45 | { 46 | Console.Error.WriteLine(error); 47 | } 48 | } 49 | } 50 | 51 | return result; 52 | } 53 | 54 | private class TemplateResolver : ITemplateResolver 55 | { 56 | private readonly string _siteRootPath; 57 | 58 | public TemplateResolver(string siteRootPath) 59 | { 60 | _siteRootPath = siteRootPath; 61 | } 62 | 63 | public string Resolve(string name) 64 | { 65 | var id = (Path.GetFileNameWithoutExtension(name) ?? "default").ToLowerInvariant().Slugify(); 66 | 67 | var extension = (Path.GetExtension(name) ?? ".cshtml").TrimStart('.'); 68 | 69 | try 70 | { 71 | var layout = Site.ForPath(_siteRootPath).Theme.Layouts[id]; 72 | 73 | if (!layout.Extension.Equals(String.IsNullOrEmpty(extension) ? "cshtml" : extension, StringComparison.OrdinalIgnoreCase)) 74 | { 75 | Console.Error.WriteLine("Resolved wrong. Layout {0} is not razor. Extension: {1}", name, extension); 76 | return "Raw(@Model)"; 77 | } 78 | return layout.RawContent; 79 | } 80 | catch (KeyNotFoundException knf) 81 | { 82 | Console.Error.WriteLine("Layout not found: Layout {0} extension {1}", name, extension); 83 | return "Raw(@Model)"; 84 | } 85 | } 86 | } 87 | } 88 | 89 | public class PowerSiteTemplate : TemplateBase 90 | { 91 | public Site Site { get; set; } 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /PowerSite/DataModel/Author.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using PowerSite.Actions; 3 | 4 | namespace PowerSite.DataModel 5 | { 6 | public class Author : IIdentityObject 7 | { 8 | private readonly Regex _parser = new Regex(@"(?.*)\s+(?:\((?[^\)].*)\))?\s+(?:<(?[^>]+)>)?\s+(?https?://.*)?(?:$|\s)", RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline); 9 | 10 | public Author() {} 11 | 12 | public Author(string name) 13 | { 14 | var match = _parser.Match(name); 15 | if (match.Success) 16 | { 17 | Name = match.Groups["name"].Value; 18 | Id = match.Groups["id"].Length > 0 ? match.Groups["id"].Value : Name.Slugify(); 19 | 20 | if (match.Groups["email"].Length > 0) 21 | { 22 | Email = match.Groups["email"].Value; 23 | } 24 | if (match.Groups["url"].Length > 0) 25 | { 26 | Url = match.Groups["url"].Value; 27 | } 28 | } 29 | else 30 | { 31 | Name = name; 32 | Id = name.Slugify(); 33 | } 34 | } 35 | 36 | public string Id { get; set; } 37 | 38 | public string Name { get; set; } 39 | 40 | public string Email { get; set; } 41 | 42 | public string Url { get; set; } 43 | 44 | public override string ToString() 45 | { 46 | return string.Format("{0} ({1})", Name, Id) + (string.IsNullOrEmpty(Email) ? "" : string.Format(" <{0}>",Email)) +(string.IsNullOrEmpty(Url) ? "" : " " + Url); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /PowerSite/DataModel/Document.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Management.Automation; 6 | using System.Text.RegularExpressions; 7 | using PowerSite.Actions; 8 | 9 | namespace PowerSite.DataModel 10 | { 11 | public class Document : NamedContentBase 12 | { 13 | public Document(Author author, string path, string id = null, string dateTimeFormat = "yyyy-MM-dd H:mm", bool preLoadContent = false) 14 | : base(path, id, preLoadContent) 15 | { 16 | if (Author == null) Author = author; 17 | if (Tags == null || Tags.Length == 0) Tags = new string[] {}; 18 | _dtFormat = dateTimeFormat; 19 | } 20 | 21 | public string Title { get; set; } 22 | 23 | public Author Author { get; set; } 24 | 25 | public DateTime Date { get; set; } 26 | 27 | public string DateString { get { return Date.ToString(_dtFormat, CultureInfo.InvariantCulture); } } 28 | 29 | public string[] Tags { get; set; } 30 | 31 | public bool Draft { get; set; } 32 | 33 | private string _summary; 34 | private readonly string _dtFormat; 35 | 36 | public string Summary { 37 | get 38 | { 39 | if (_summary == null) 40 | { 41 | Match match = Regex.Match(RenderedContent, "

.*?

", RegexOptions.IgnoreCase | RegexOptions.Singleline); 42 | if (match.Success && match.Value != RenderedContent) 43 | { 44 | _summary = match.Value; 45 | } 46 | } 47 | 48 | return _summary; 49 | } 50 | } 51 | } 52 | 53 | public class NamedContentBase : IIdentityObject 54 | { 55 | public NamedContentBase(string path, string id = null, bool preloadContent = false) 56 | { 57 | SourcePath = path; 58 | Id = id ?? Path.GetFileNameWithoutExtension(path).Slugify(); 59 | Extension = (Path.GetExtension(path) ?? "md").Trim(new []{'.'}); 60 | LoadFile(true, preloadContent); 61 | } 62 | 63 | public string SourcePath { get; protected set; } 64 | public string Id { get; set; } 65 | public string Extension { get; set; } 66 | 67 | private string _rawContent; 68 | public string RawContent 69 | { 70 | get 71 | { 72 | if (string.IsNullOrEmpty(_rawContent)) 73 | { 74 | LoadRawContent(); 75 | } 76 | return _rawContent; 77 | } 78 | private set { _rawContent = value; } 79 | } 80 | 81 | public string RenderedContent { get; set; } 82 | public dynamic Metadata { get; set; } 83 | public string RelativeUrl { get; set; } 84 | public string FullyQualifiedUrl { get; set; } 85 | 86 | private static readonly Regex MetadataKeyValue = new Regex(@"^(?\w+):\s?(?.+)$", RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture | RegexOptions.Singleline); 87 | 88 | protected void LoadRawContent() 89 | { 90 | LoadFile(false, true); 91 | } 92 | 93 | protected void LoadMetadata() 94 | { 95 | LoadFile(true, false); 96 | } 97 | 98 | private void LoadFile(bool keepMetadata, bool keepContent) 99 | { 100 | var preambleOpened = false; 101 | var preambleSkipped = false; 102 | dynamic o = new PSObject(this); 103 | if (keepMetadata) 104 | { 105 | try 106 | { 107 | o.Draft = SourcePath.ToLowerInvariant().Contains(".draft."); 108 | o.Metadata = new PSObject(); 109 | } 110 | catch 111 | { 112 | keepMetadata = false; 113 | } 114 | } 115 | 116 | using (var reader = new StreamReader(SourcePath)) 117 | { 118 | string line; 119 | 120 | while ((line = reader.ReadLine()) != null) 121 | { 122 | // Eat any blank lines or comments at the top of the document or in the header. 123 | if (String.IsNullOrEmpty(line) || line.StartsWith("#") || line.StartsWith("//")) 124 | { 125 | if (preambleSkipped) break; 126 | continue; 127 | } 128 | 129 | if (line.Equals("---")) 130 | { 131 | line = String.Empty; 132 | // if we already parsed metadata, then when we see ---, we're done 133 | if (preambleOpened || preambleSkipped) break; 134 | preambleOpened = true; 135 | continue; 136 | } 137 | 138 | var match = MetadataKeyValue.Match(line); 139 | if (match.Success) 140 | { 141 | preambleSkipped = !preambleOpened; 142 | 143 | if (keepMetadata) 144 | { 145 | string key = match.Groups[1].Value.ToLowerInvariant(); 146 | string value = match.Groups[2].Value.Trim(); 147 | switch (key) 148 | { 149 | case "date": 150 | DateTime date; 151 | if (!DateTime.TryParse(value, out date)) 152 | { 153 | date = default(DateTime); 154 | } 155 | o.Date = date; 156 | break; 157 | 158 | case "title": 159 | o.Title = value; 160 | break; 161 | 162 | case "author": 163 | o.Author = LanguagePrimitives.ConvertTo(value); 164 | break; 165 | 166 | case "tag": 167 | case "tags": 168 | var tags = value.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) 169 | .Select(t => t.Trim()).Where(t => !String.IsNullOrEmpty(t)).ToArray(); 170 | 171 | o.Tags = tags; 172 | break; 173 | 174 | default: 175 | ((PSObject)o.Metadata).Properties.Add(new PSNoteProperty(key, value)); 176 | break; 177 | } 178 | } 179 | } 180 | else if (!preambleOpened) // no preamble, non-matches mean we're done with the header. 181 | { 182 | break; 183 | } 184 | } 185 | 186 | if (keepMetadata) 187 | { 188 | if (o.Date == default(DateTime)) 189 | { 190 | o.Date = File.GetLastWriteTime(SourcePath); 191 | } 192 | Metadata = o; 193 | } 194 | 195 | 196 | if (keepContent) 197 | { 198 | RawContent = String.Concat(line, "\n", reader.ReadToEnd()).Trim(); 199 | } 200 | 201 | } 202 | 203 | } 204 | } 205 | } -------------------------------------------------------------------------------- /PowerSite/DataModel/IdentityCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | 4 | namespace PowerSite.DataModel 5 | { 6 | public interface IIdentityObject 7 | { 8 | string Id { get; set; } 9 | } 10 | 11 | 12 | public class IdentityCollection : KeyedCollection where T : IIdentityObject 13 | { 14 | public static IdentityCollection Create(IEnumerable collection) 15 | { 16 | var namedCollection = new IdentityCollection(); 17 | 18 | foreach (var layout in collection) 19 | { 20 | namedCollection.Add(layout); 21 | } 22 | 23 | return namedCollection; 24 | } 25 | 26 | protected override string GetKeyForItem(T item) 27 | { 28 | return item.Id; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /PowerSite/DataModel/LayoutFile.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace PowerSite.DataModel 4 | { 5 | public class LayoutFile : NamedContentBase 6 | { 7 | public LayoutFile(string path) : base(path, preloadContent: true) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /PowerSite/DataModel/RenderingState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Composition; 4 | using PowerSite.Actions; 5 | using PowerSite.Builtin; 6 | 7 | namespace PowerSite.DataModel 8 | { 9 | public class RenderingState : IDisposable 10 | { 11 | private bool _disposed = false; 12 | 13 | [ImportMany] 14 | protected IEnumerable> Engines; 15 | 16 | public RenderingState() 17 | { 18 | if (RenderingState.Current != null) 19 | { 20 | throw new InvalidOperationException("Can only have one rendering transaction active at a time. Ensure the previous rendering transaction was disposed before creating this one."); 21 | } 22 | RenderingState.Current = this; 23 | } 24 | 25 | private static readonly string[] Keys = new[] 26 | { 27 | "Pages","Posts","Theme","ThemesPath","Title" 28 | }; 29 | public static void Initialize(PowerSiteHelper config) 30 | { 31 | Current = new RenderingState 32 | { 33 | Theme = config.Theme, 34 | Posts = config.Posts, 35 | Pages = config.Pages, 36 | Layouts = config.Theme.Layouts, 37 | Config = config 38 | }; 39 | 40 | } 41 | 42 | public static RenderingState Current { get; private set; } 43 | 44 | public dynamic Config { get; private set; } 45 | 46 | public Theme Theme { get; set; } 47 | public IdentityCollection Posts { get; set; } 48 | public IdentityCollection Pages { get; set; } 49 | public IdentityCollection Layouts { get; set; } 50 | 51 | public void Dispose() 52 | { 53 | this.Dispose(true); 54 | GC.SuppressFinalize(this); 55 | } 56 | 57 | protected virtual void Dispose(bool disposing) 58 | { 59 | if (_disposed) 60 | { 61 | return; 62 | } 63 | 64 | if (disposing) 65 | { 66 | if (RenderingState.Current == this) 67 | { 68 | RenderingState.Current = null; 69 | } 70 | } 71 | 72 | _disposed = true; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /PowerSite/DataModel/Theme.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | 4 | namespace PowerSite.DataModel 5 | { 6 | public class Theme 7 | { 8 | public readonly string ThemeRoot; 9 | 10 | public Theme(string root, string themeName) 11 | { 12 | Name = themeName; 13 | ThemeRoot = Path.Combine(root, themeName); 14 | } 15 | 16 | public void Load() 17 | { 18 | if (!Directory.Exists(ThemeRoot)) 19 | { 20 | throw new DirectoryNotFoundException(string.Format("Cannot find the theme '{0}' in the site themes '{1}'", Name, ThemeRoot)); 21 | } 22 | 23 | Layouts = IdentityCollection.Create(Directory.EnumerateFiles(ThemeRoot).Select(f => new LayoutFile(f))); 24 | } 25 | 26 | public IdentityCollection Layouts { get; set; } 27 | 28 | public string Name { get; private set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /PowerSite/EngineHost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.ComponentModel.Composition; 5 | using System.ComponentModel.Composition.Hosting; 6 | using System.IO; 7 | using System.Linq; 8 | using PowerSite.Actions; 9 | using PowerSite.DataModel; 10 | 11 | namespace PowerSite 12 | { 13 | public class EngineHost : IReadOnlyDictionary 14 | { 15 | private IEnumerable> _renderingEngines; 16 | private readonly Dictionary _renderEngines = new Dictionary(); 17 | private CompositionContainer _container; 18 | 19 | public readonly List Errors = new List(); 20 | public bool? HasException = null; 21 | 22 | protected EngineHost(string siteRootPath) 23 | { 24 | Utility.AssertDirectoryExists(siteRootPath); 25 | siteRootPath = Path.GetFullPath(siteRootPath.ToLowerInvariant()); 26 | if (Site.ActiveSites.ContainsKey(siteRootPath)) 27 | { 28 | throw new InvalidOperationException("Can only have one rendering transaction active on a site at a time. Ensure the previous rendering transaction was disposed before creating this one."); 29 | } 30 | 31 | SiteRootPath = siteRootPath; 32 | 33 | InitializeEngineCatalog(); 34 | 35 | } 36 | 37 | [ImportMany] 38 | protected IEnumerable> RenderingEngines 39 | { 40 | get { return _renderingEngines; } 41 | set 42 | { 43 | _renderingEngines = value; 44 | _renderingEngines.ToList().ForEach(ex => _renderEngines.Add(ex.Metadata.Extension, ex.Value)); 45 | } 46 | } 47 | 48 | public string SiteRootPath { get; private set; } 49 | 50 | /// 51 | /// Initializes the plugin catalog. 52 | /// 53 | protected void InitializeEngineCatalog() 54 | { 55 | var catalog = new AggregateCatalog(); 56 | //Adds all the parts found in the same assembly as the Program class 57 | var assembly = typeof(Site).Assembly; 58 | catalog.Catalogs.Add(new AssemblyCatalog(assembly)); 59 | 60 | if (!string.IsNullOrEmpty(SiteRootPath) && Directory.Exists(SiteRootPath)) 61 | { 62 | // WriteVerbose("Site root: " + siteRootPath); 63 | var pluginRoot = Path.Combine(SiteRootPath, "Plugins"); 64 | 65 | if (Directory.Exists(pluginRoot)) 66 | { 67 | catalog.Catalogs.Add(new DirectoryCatalog(pluginRoot)); 68 | } 69 | // Otherwise: WriteVerbose("No Plugins directory found in site root: " + siteRootPath); 70 | } 71 | // Otherwise: WriteWarning("Could not determine module root"); 72 | 73 | //Create the CompositionContainer with the parts in the catalog 74 | _container = new CompositionContainer(catalog); 75 | 76 | try 77 | { 78 | _container.ComposeParts(this); 79 | HasException = true; 80 | } 81 | catch (CompositionException compositionException) 82 | { 83 | Errors.Add(compositionException); 84 | HasException = false; 85 | } 86 | } 87 | 88 | public IEnumerator> GetEnumerator() 89 | { 90 | return _renderEngines.GetEnumerator(); 91 | } 92 | 93 | IEnumerator IEnumerable.GetEnumerator() 94 | { 95 | return GetEnumerator(); 96 | } 97 | 98 | public int Count { get; private set; } 99 | public bool ContainsKey(string key) 100 | { 101 | return _renderEngines.ContainsKey(key); 102 | } 103 | 104 | public bool TryGetValue(string key, out IRenderer value) 105 | { 106 | return _renderEngines.TryGetValue(key, out value); 107 | } 108 | 109 | public IRenderer this[string key] 110 | { 111 | get { return _renderEngines[key]; } 112 | } 113 | 114 | public IEnumerable Keys { get { return _renderEngines.Keys; } } 115 | 116 | public IEnumerable Values { get { return _renderEngines.Values; } } 117 | public int PageSize { get; set; } 118 | 119 | 120 | public void Render(NamedContentBase doc) 121 | { 122 | doc.RenderedContent = Render(doc, doc); 123 | } 124 | 125 | public string Render(NamedContentBase layout, dynamic model) 126 | { 127 | return _renderEngines[layout.Extension].Render(SiteRootPath, layout.RawContent, model); 128 | } 129 | 130 | protected void Render(NamedContentBase layout, dynamic model, string outputPath) 131 | { 132 | Utility.CreateDirectoryIfNecessary(Path.GetDirectoryName(outputPath)); 133 | File.WriteAllText(outputPath, Render(layout, model)); 134 | } 135 | 136 | protected void RenderIndex(LayoutFile layout, IEnumerable posts, string basePath) 137 | { 138 | int skip = 0; 139 | IEnumerable page; 140 | while ((page = posts.Skip(skip).Take(PageSize)).Any()) 141 | { 142 | var outputPath = Path.Combine(basePath, skip == 0 ? "index.html" : string.Format("index{0}.html", skip)); 143 | Render(layout, page, outputPath); 144 | skip += PageSize; 145 | } 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /PowerSite/IRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PowerSite 8 | { 9 | /// 10 | /// Interface implemented by classes that can render templates into content. 11 | /// 12 | public interface IRenderer 13 | { 14 | /// 15 | /// Renders a template with the provided data. 16 | /// 17 | /// Unique site key (e.g. the full path to the site root). 18 | /// Template to render. 19 | /// Data provided to template. 20 | /// Rendered template content. 21 | string Render(string siteKey, string template, dynamic data); 22 | } 23 | 24 | public interface IExtension 25 | { 26 | String Extension { get; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /PowerSite/PowerSite.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4A8F250C-3A76-423D-883B-CEC3687895E7} 8 | Library 9 | Properties 10 | PowerSite 11 | PowerSite 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll 35 | 36 | 37 | 38 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 39 | True 40 | 41 | 42 | ..\packages\RazorEngine.3.7.7\lib\net45\RazorEngine.dll 43 | True 44 | 45 | 46 | 47 | 48 | 49 | False 50 | ..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll 51 | 52 | 53 | ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll 54 | True 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Always 85 | 86 | 87 | Always 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | copy $(TargetDir)\*.dll $(TargetDir)\PowerSite 98 | 99 | 106 | -------------------------------------------------------------------------------- /PowerSite/PowerSite/PowerSite.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaykul/PowerSite/3ca9d62783ee8283de32c2aa156acd6a9008f5ef/PowerSite/PowerSite/PowerSite.psd1 -------------------------------------------------------------------------------- /PowerSite/PowerSite/PowerSite.psm1: -------------------------------------------------------------------------------- 1 | function New-PowerSitePost { 2 | [CmdletBinding(DefaultParameterSetName="PowerSite")] 3 | param( 4 | # The post title (headline) 5 | [Parameter(Mandatory=$true, Position=0, ValueFromRemainingArguments=$true)] 6 | [String]$Name, 7 | 8 | # keyword tags for the post 9 | [String[]]$Tags, 10 | 11 | # The root of the PowerSite to put it in 12 | [Parameter(ParameterSetName="Path")] 13 | [Alias("Path")] 14 | [String]$Root = $Pwd, 15 | 16 | # The PowerSite to use 17 | [Parameter(ValueFromPipeline=$true, ParameterSetName="PowerSite")] 18 | [PowerSite.Site]$PowerSite = $(Get-PowerSite -Root $Root) 19 | ) 20 | 21 | 22 | $date = Get-Date -f "yyyy-MM-dd HH:mm zzz" 23 | New-Item "$(Join-Path $PowerSite.Paths.posts $Name).md" -Value "---`ntitle: $Name`ndate: $date`ntags:$($Tags -join ', ')`n---`n`n" 24 | } 25 | 26 | function Get-PowerSitePost { 27 | [CmdletBinding(DefaultParameterSetName="PowerSite")] 28 | param( 29 | [Parameter(Mandatory=$true, Position=0, ValueFromRemainingArguments=$true)] 30 | [String]$Name, 31 | 32 | # The root of the PowerSite to put it in 33 | [Parameter(ParameterSetName="Path")] 34 | [Alias("Path")] 35 | [String]$Root = $Pwd, 36 | 37 | # The PowerSite to use 38 | [Parameter(ValueFromPipeline=$true, ParameterSetName="PowerSite")] 39 | [PowerSite.Site]$PowerSite = $(Get-PowerSite -Root $Root) 40 | ) 41 | Get-Item (Join-Path $PowerSite.Paths.posts $Name) 42 | } 43 | 44 | 45 | function FastPushGitHub { 46 | #.Synopsis 47 | # Push changes to github 48 | #.Description 49 | # Based on github pages model: 50 | # 1. Assume everything is checked in. 51 | # 2. Use a "source" branch for editing pages: build it to an ignored "Output" folder 52 | # 3. Switch to the "master" branch and copy from the output, push. 53 | [CmdletBinding(DefaultParameterSetName="PowerSite")] 54 | param( 55 | [Parameter(Mandatory=$true, Position=0, ValueFromRemainingArguments=$true)] 56 | [String]$Name, 57 | 58 | # The root of the PowerSite to put it in 59 | [Parameter(ParameterSetName="Path")] 60 | [Alias("Path")] 61 | [String]$Root = $Pwd, 62 | 63 | # The Source branch in git (defaults to source) 64 | [String]$SourceBranchName = "source", 65 | 66 | # The Publish branch in git (defaults to master) 67 | [String]$PublishBranchName = "master", 68 | 69 | # The PowerSite to use 70 | [Parameter(ValueFromPipeline=$true, ParameterSetName="PowerSite")] 71 | [PowerSite.Site]$PowerSite = $(Get-PowerSite -Root $Root) 72 | ) 73 | $site = Get-PowerSite -SiteRootPath $Root 74 | 75 | Push-Location $site.SiteRootPath 76 | if(git status -s) { 77 | Pop-Location 78 | throw "Your site directory isn't clean, please commit or clean up and try again." 79 | } 80 | $ErrorActionPreference = "Stop" 81 | 82 | git checkout $SourceBranchName --force 83 | 84 | Update-PowerSite -SiteRootPath $pwd 85 | 86 | git checkout $PublishBranchName --force 87 | 88 | ls -exclude output, .git\, .gitignore | rm -Recurse 89 | cp .\Output\* $Pwd -Force -Recurse 90 | git add * 91 | git commit -a -m "FastPush from PowerSite" 92 | git push 93 | } -------------------------------------------------------------------------------- /PowerSite/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Site")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Site")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f41f5a4f-ba38-44e6-9207-5cbf6c6a4afa")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PowerSite/Site.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Management.Automation; 6 | using System.Threading.Tasks; 7 | using PowerSite.Actions; 8 | using PowerSite.DataModel; 9 | 10 | namespace PowerSite 11 | { 12 | public class Site : EngineHost, IDisposable 13 | { 14 | public static Site Current; 15 | 16 | public static Site ForPath(string siteRootPath) 17 | { 18 | Utility.AssertDirectoryExists(siteRootPath); 19 | siteRootPath = Path.GetFullPath(siteRootPath).ToLowerInvariant(); 20 | return ActiveSites.ContainsKey(siteRootPath) ? ActiveSites[siteRootPath] : new Site(siteRootPath); 21 | } 22 | 23 | #region Initialization 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The site root path. 28 | private Site(string siteRootPath) 29 | : base(siteRootPath) 30 | { 31 | foreach (var path in new[] { "pages", "posts", "static", "themes" }) 32 | { 33 | Paths[path] = Utility.CreateDirectoryIfNecessary(Path.Combine(siteRootPath, path)); 34 | } 35 | 36 | foreach (var path in new[] {"plugins", "output", "cache"}) 37 | { 38 | Paths[path] = Path.Combine(siteRootPath, path); 39 | } 40 | 41 | Config = ImportSiteConfig(); 42 | 43 | ActiveSites.Add(siteRootPath, this); 44 | } 45 | 46 | private dynamic ImportSiteConfig() 47 | { 48 | string configPath = Path.Combine(SiteRootPath, ConfigFile); 49 | 50 | Utility.AssertFileExists(configPath, string.Format("The {0} file cannot be found ({{0}})", ConfigFile)); 51 | 52 | // Microsoft.PowerShell.Utility\\Import-LocalizedData [[-BindingVariable] ] [[-UICulture] ] [-BaseDirectory ] [-FileName ] [-SupportedCommand ] [] 53 | // var wrappedCmd = InvokeCommand.GetCommand("Microsoft.PowerShell.Utility\\Import-LocalizedData", CommandTypes.Cmdlet); 54 | 55 | var scriptCmd = 56 | ScriptBlock.Create( 57 | String.Format("& 'Microsoft.PowerShell.Utility\\Import-LocalizedData' -BaseDirectory '{0}' -FileName '{1}'", SiteRootPath, ConfigFile)); 58 | 59 | // Import-LocalizedData returns PSObject even if you InvokeReturnAsIs 60 | // So the cleanest thing is to always look at the BaseObject 61 | dynamic siteConfig = scriptCmd.Invoke().First(); 62 | 63 | // Validation 64 | if (siteConfig == null) 65 | { 66 | throw new FileNotFoundException(String.Format("The {0} file is invalid at {1}", ConfigFile, SiteRootPath)); 67 | } 68 | RootUrl = siteConfig.RootUrl; 69 | Title = siteConfig.Title; 70 | Description = siteConfig.Description; 71 | Author = LanguagePrimitives.ConvertTo(siteConfig.Author); 72 | DateFormat = siteConfig.DateFormat; 73 | 74 | BlogPath = siteConfig.BlogPath ?? ""; 75 | PrettyUrl = siteConfig.PrettyUrl ?? true; 76 | PageSize = siteConfig.PostsPerArchivePage ?? 5; 77 | 78 | Theme = new Theme(Paths["themes"], siteConfig.Theme ?? "BootstrapBlog"); 79 | 80 | return siteConfig; 81 | } 82 | 83 | public string DateFormat { get; set; } 84 | 85 | #endregion Initialization 86 | 87 | public string RootUrl 88 | { 89 | get { return _rootUrl; } 90 | set { _rootUrl = value.TrimEnd(new[] { '/', '\\' }) + '/'; } 91 | } 92 | 93 | public string BlogUrl 94 | { 95 | get { return RootUrl + BlogPath; } 96 | } 97 | 98 | 99 | private const string ConfigFile = "config.psd1"; 100 | public dynamic Config { get; private set; } 101 | 102 | /// 103 | /// Gets the site's default author. 104 | /// 105 | /// The author. 106 | public Author Author { get; private set; } 107 | 108 | /// 109 | /// Gets the active site theme. 110 | /// 111 | /// The site theme. 112 | public Theme Theme { get; private set; } 113 | 114 | /// 115 | /// Gets the site title. 116 | /// 117 | /// The site title. 118 | public string Title { get; private set; } 119 | 120 | /// 121 | /// Get the site description. 122 | /// 123 | /// The description. 124 | public string Description { get; private set; } 125 | 126 | public bool PrettyUrl { get; set; } 127 | 128 | public Dictionary Paths = new Dictionary(); 129 | 130 | public string BlogPath { get; private set; } 131 | 132 | public IdentityCollection Pages { get; set; } 133 | public IdentityCollection Posts { get; set; } 134 | 135 | private Dictionary _tags; 136 | private string _rootUrl; 137 | public readonly static Dictionary ActiveSites = new Dictionary(); 138 | 139 | public Dictionary Tags 140 | { 141 | get 142 | { 143 | return _tags ?? (_tags = Posts.SelectMany(p => p.Tags) 144 | .GroupBy(t => t) 145 | .ToDictionary(grouping => grouping.Key, grouping => grouping.Count())); 146 | } 147 | } 148 | 149 | public IEnumerable GetPostsByTag(string tag) 150 | { 151 | return Posts.Where(doc => doc.Tags.Contains(tag)); 152 | } 153 | 154 | public void LoadDocuments() 155 | { 156 | Pages = IdentityCollection.Create( 157 | from file in Directory.EnumerateFiles(Paths["pages"], "*.*", SearchOption.AllDirectories).AsParallel() 158 | let fileId = Path.GetFileNameWithoutExtension(file).Slugify() 159 | let relativeUrl = Path.Combine(Path.GetDirectoryName(file).Substring(Paths["pages"].Length), fileId + ".html").Replace('\\', '/') 160 | select new Document(Author, file, fileId, dateTimeFormat: DateFormat) 161 | { 162 | RelativeUrl = "/" + relativeUrl, 163 | FullyQualifiedUrl = RootUrl.TrimEnd('/') + "/" + relativeUrl 164 | } into pages 165 | orderby pages.Date descending 166 | select pages); 167 | 168 | Posts = IdentityCollection.Create( 169 | from file in Directory.EnumerateFiles(Paths["posts"], "*.*", SearchOption.TopDirectoryOnly).AsParallel() 170 | let fileId = Path.GetFileNameWithoutExtension(file).Slugify() 171 | let relativeUrl = Path.Combine(BlogPath, (fileId + (PrettyUrl ? "/index.html" : ".html"))).Replace('\\', '/') 172 | select new Document(Author, file, fileId, dateTimeFormat: DateFormat) 173 | { 174 | RelativeUrl = "/" + relativeUrl, 175 | FullyQualifiedUrl = RootUrl.TrimEnd('/') + "/" + relativeUrl 176 | } into posts 177 | orderby posts.Date descending 178 | select posts); 179 | 180 | Theme.Load(); 181 | } 182 | 183 | public void RenderDocuments() 184 | { 185 | Current = this; 186 | Parallel.ForEach(Pages, p => Render(p)); 187 | Parallel.ForEach(Posts, p => Render(p)); 188 | } 189 | 190 | public void RenderTemplates() 191 | { 192 | Current = this; 193 | Parallel.ForEach(Posts, p => Render(Theme.Layouts["post"], p, Path.Combine(Paths["cache"], p.RelativeUrl.TrimStart('/')))); 194 | Parallel.ForEach(Pages, p => Render(Theme.Layouts["page"], p, Path.Combine(Paths["cache"], p.RelativeUrl.TrimStart('/')))); 195 | 196 | Console.WriteLine("Rendered {0} blog posts", Posts.Count); 197 | Console.WriteLine("Rendered {0} pages", Pages.Count); 198 | 199 | if (Theme.Layouts.Contains("archive")) 200 | { 201 | var layout = Theme.Layouts["archive"]; 202 | 203 | // the main site index 204 | RenderIndex(layout, Posts.ToList(), Path.Combine(Paths["cache"], BlogPath)); 205 | Console.WriteLine("Rendered index page"); 206 | 207 | // tag indexes 208 | foreach (var tag in Tags.Keys) 209 | { 210 | RenderIndex(layout, GetPostsByTag(tag), Path.Combine(Paths["cache"], BlogPath, "tags", tag.Slugify())); 211 | Console.WriteLine("Rendered tag page {0}", tag); 212 | } 213 | } 214 | if (Theme.Layouts.Contains("feed")) 215 | { 216 | var layout = Theme.Layouts["feed"]; 217 | // the main site feed 218 | var outputPath = Path.Combine(Paths["cache"], BlogPath, "feed.xml"); 219 | Render(layout, Posts.Take(5), outputPath); 220 | Console.WriteLine("Rendered feed"); 221 | // tag indexes 222 | foreach (var tag in Tags.Keys) 223 | { 224 | Render(layout, GetPostsByTag(tag).Take(5), Path.Combine(Paths["cache"], BlogPath, "tags", tag.Slugify(), "feed.xml")); 225 | Console.WriteLine("Rendered tag feed {0}", tag); 226 | } 227 | } 228 | } 229 | 230 | #region IDisposable 231 | private bool _disposed = false; 232 | protected virtual void Dispose(bool disposing) 233 | { 234 | if (_disposed) return; 235 | 236 | if (disposing) 237 | { 238 | if (Site.ActiveSites.ContainsKey(this.SiteRootPath)) 239 | { 240 | Site.ActiveSites.Remove(this.SiteRootPath); 241 | } 242 | } 243 | 244 | _disposed = true; 245 | } 246 | 247 | public void Dispose() 248 | { 249 | this.Dispose(true); 250 | GC.SuppressFinalize(this); 251 | } 252 | #endregion IDisposable 253 | } 254 | } -------------------------------------------------------------------------------- /PowerSite/Utility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Management.Automation; 6 | using System.Management.Automation.Language; 7 | using System.Text; 8 | using System.Text.RegularExpressions; 9 | using System.Threading.Tasks; 10 | using PowerSite.DataModel; 11 | 12 | namespace PowerSite.Actions 13 | { 14 | public static class Utility 15 | { 16 | public static string Slugify(this string id) 17 | { 18 | if (String.IsNullOrWhiteSpace(id)) 19 | { 20 | return null; 21 | } 22 | id = Path.GetFileNameWithoutExtension(id); 23 | id = Regex.Replace(id, @"[^\w\s_\-\.]+", String.Empty); // first, allow only words, spaces, underscores, dashes and dots. 24 | id = Regex.Replace(id, @"\.{2,}", String.Empty); // strip out any dots stuck together (no pathing attempts). 25 | id = Regex.Replace(id, @"\s{2,}", " "); // convert multiple spaces into single space. 26 | id = id.Trim(new[] { ' ', '.' }); // ensure the string does not start or end with a dot 27 | return id.Replace(' ', '-').ToLowerInvariant(); // finally, replace all spaces with dashes and lowercase it. 28 | } 29 | public static string ToTitleCase(this string id) 30 | { 31 | return string.Join(" ", id.Split(' ').Select(str => str.Substring(0, 1).ToUpperInvariant() + str.Substring(1))); 32 | } 33 | 34 | public static string CreateDirectoryIfNecessary(string path) 35 | { 36 | if (!Directory.Exists(path)) 37 | { 38 | Directory.CreateDirectory(path); 39 | } 40 | return path; 41 | } 42 | 43 | public static void AssertDirectoryExists(string path, string messageTemplate = "The path '{0}' is not a valid FileSystem path") 44 | { 45 | if (!Directory.Exists(path)) 46 | { 47 | throw new DirectoryNotFoundException(String.Format(messageTemplate, path)); 48 | } 49 | } 50 | 51 | public static void AssertFileExists(string path, string messageTemplate = "The file '{0}' does not exist") 52 | { 53 | if (!File.Exists(path)) 54 | { 55 | throw new FileNotFoundException(String.Format(messageTemplate, path), path); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /PowerSite/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | PowerSite 2 | ========= 3 | 4 | PowerSite is a simple, blog-aware static site generator in .Net, written as a PowerShell module. 5 | 6 | It currently supports authoring posts and pages in markdown, and templates and themes in Razor, but I have plans to extend that (and there's already plugin support). 7 | 8 | And look, we have builds! [![Build status](https://ci.appveyor.com/api/projects/status/9j2r4dkpta5pgp14/branch/master?svg=true)](https://ci.appveyor.com/project/Jaykul/powersite) 9 | 10 | There are a lot of things still to do -- but I'm not going to write about that here, [that's what issues are for](https://github.com/Jaykul/PowerSite/issues). 11 | 12 | Usage 13 | ===== 14 | 15 | There's a bunch of conventions and configuration that go into a site. The following folders are specially named: 16 | 17 | \posts 18 | For a blog, blog posts go in this folder 19 | \pages 20 | Pages that aren't blog posts go here (and are output with relative paths) 21 | \static 22 | Static content like images and downloads go here, (and are output with relative paths) without processing. 23 | \themes 24 | All the layout templates, javascripts and styles for the themes go here (see below for a discussion of how these work) 25 | \plugins 26 | Any plugins used by this site should be installed in this folder 27 | 28 | Also note: output is rendered into the "cache" folder which is renamed to "output" if and when everything succeeds, so don't put anything in those folders either... 29 | 30 | 31 | Types of Content 32 | ---------------- 33 | 34 | There are three types of content in PowerSite: 35 | 36 | ### Static Content ### 37 | 38 | Static content are the files in the \static folder and it's subfolders, which are copied directly to the output, preserving paths. 39 | You can put anything in here that you like, but the traditional use is to put create folders for images, downloads, etc. 40 | 41 | 42 | ### Pages ### 43 | 44 | Pages are the files in the `\pages` folder and it's subfolders. 45 | 46 | Like the `\static` content, files in pages are output according to the path that they're in, 47 | so if you have a `\pages\index.md` it will be the root `\index.html` of your site after rendering, 48 | and a `\pages\PoshSite\index.md` will output in a "PoshSite" subdirectory. 49 | 50 | However, unlike the static files, these are usually markdown files which processed by the renderer, 51 | and then wrapped in the "page" layout template. If you have HTML files you don't want processed, 52 | you should put them in `\static` -- the pages content allows you to create absolutely any structure 53 | you want for your site in the pages, while still getting the benefit of markdown and layout templates. 54 | 55 | 56 | ### Posts ### 57 | 58 | Posts are the blog post files in the `\posts` folder. There's no support for subfolders here, so each 59 | post must have a unique name. These are usually markdown files which are processed by the renderer and 60 | then wrapped in the "post" layout template. The output location is calculated as RootUrl + BlogUrl + Slug, 61 | where the slug is calculated from the file name by removing 62 | 63 | Writing a Page or a Post 64 | ------------------------ 65 | 66 | Each post starts with an (optional) YAML metadata header composed of key: value pairs. If the first line is 67 | three dashes (---) then the metadata continues until another line which is just three dashes. Otherwise, the 68 | metadata starts at the first line of the file and continues until there's a blank line, or any other line that 69 | doesn't follow the key:value syntax. Note that keys can't have spaces, but values can. All metadata is passed 70 | to any rendering engines and templates in your theme (see Themeing, below) for use there. 71 | 72 | The default Metadata fields (which you really should provide) are: 73 | 74 | date: yyyy-mm-dd hh:mm 75 | author: Author Name 76 | tags: Tag, Another Tag 77 | 78 | Name the file with the slug and the markup type. For instance hello-world.md for a markdown post. 79 | If you don't want it published yet, name it with ".draft." in the name, like: hello-world.draft.md 80 | 81 | Posts also support the *title* field to override the file name (the file name will still be used for the slug, 82 | but the title will be rendered in the template). 83 | 84 | Themes and Layouts 85 | ------------------ 86 | 87 | Each folder in the Themes subfolder is a theme, and the active theme is selected by the "theme" setting in the config.psd1 88 | 89 | Subfolders in each theme are output to the site preserving paths, and files which need processing are processed 90 | (currently we only support razor templates, but we should add mustache, as well as non-template langauages like 91 | less and sass). 92 | 93 | The core template files are the output types: "post" and "page" as well as "archive" for lists and "feed" for 94 | rss/atom feeds. The index (and feed: **todo**) templates are generated for the whole site, (and for each tag and 95 | author: **todo**). 96 | 97 | Any additional template files are used only for includes in the core templates. 98 | Font and image files, as well as css and js are output untouched (preserving paths). 99 | --------------------------------------------------------------------------------