Skip to content

Commit 689a084

Browse files
committed
Theme data settings
1 parent 68fc6d4 commit 689a084

File tree

6 files changed

+167
-20
lines changed

6 files changed

+167
-20
lines changed

src/App/Pages/Admin/Themes/Index.cshtml

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,66 @@
44
ViewData["Title"] = Localizer["themes"];
55
}
66

7-
<div id="app" class="bf-content">
8-
<div id="themesList" class="bf-posts-grid d-flex">
7+
<div id="app" class="bf-content">
8+
<div id="themesList" class="bf-posts-grid d-flex">
99

10-
<div v-for="(theme, index) in themes" class="post-grid-col">
11-
<div class="post-grid-item">
12-
<a class="item-link" v-bind:style="{ backgroundImage: 'url(' + webRoot + theme.cover + ')' }">
13-
<div class="item-title mt-auto">&nbsp;</div>
14-
</a>
15-
<div class="item-info d-flex align-items-center">
16-
<span class="item-date mr-auto">
17-
{{ theme.title }}
18-
</span>
19-
<i v-if="theme.isCurrent" class="fas fa-star" style="color: #ffbe00; font-size: 1.3em"></i>
20-
<button v-if="!theme.isCurrent" class="btn-unstyled item-favorite ml-3" v-on:click="select(theme.title)" data-tooltip="" title="" data-original-title="select">
21-
<i class="far fa-star"></i>
22-
</button>
23-
<a v-if="!theme.isCurrent" class="item-show ml-4" href="#" v-on:click="return remove(theme.title)" data-tooltip="" title="" data-original-title="delete">
24-
<i class="fas fa-trash" style="color: #ff6666"></i>
10+
<div v-for="(theme, index) in themes" class="post-grid-col">
11+
<div class="post-grid-item">
12+
<a class="item-link" v-bind:style="{ backgroundImage: 'url(' + webRoot + theme.cover + ')' }">
13+
<div class="item-title mt-auto">&nbsp;</div>
2514
</a>
15+
<div class="item-info d-flex align-items-center">
16+
<span class="item-date mr-auto">
17+
{{ theme.title }}
18+
</span>
19+
<i v-if="theme.isCurrent" class="fas fa-star" style="color: #ffbe00; font-size: 1.3em"></i>
20+
<button v-if="!theme.isCurrent" class="btn-unstyled item-favorite ml-3" v-on:click="select(theme.title)" data-tooltip="" title="Active" data-original-title="select">
21+
<i class="far fa-star"></i>
22+
</button>
23+
<button v-if="theme.hasSettings" class="btn-unstyled item-show ml-3" v-on:click="settings(theme.title)" data-tooltip="" title="Settings" data-original-title="select">
24+
<i class="fa fa-sliders-h"></i>
25+
</button>
26+
27+
<a v-if="!theme.isCurrent" class="item-show ml-4" href="#" v-on:click="return remove(theme.title)" data-tooltip="" title="Delete" data-original-title="delete">
28+
<i class="fas fa-trash" style="color: #ff6666"></i>
29+
</a>
30+
</div>
31+
</div>
32+
</div>
33+
34+
</div>
35+
36+
<div class="modal fade" id="dlgSettings" tabindex="-1" role="dialog" aria-hidden="true">
37+
<div class="modal-dialog" role="document">
38+
<div class="modal-content">
39+
<div class="modal-header">
40+
<h4 class="modal-title" id="hdrSettings">@Localizer["settings"]</h4>
41+
<button type="button" class="close ml-2" title="Close" data-placement="bottom" data-tooltip data-dismiss="modal" aria-label="@Localizer["close"]">
42+
<i class="fa fa-times"></i>
43+
</button>
44+
</div>
45+
<div class="modal-body">
46+
<form>
47+
<div class="form-group">
48+
<textarea rows="10" v-model="themeData" class="form-control" autofocus></textarea>
49+
</div>
50+
<button type="button" v-on:click="save()" class="btn btn-primary btn-main">@Localizer["save"]</button>
51+
</form>
52+
</div>
2653
</div>
2754
</div>
2855
</div>
2956

3057
</div>
31-
</div>
3258

3359
@section Scripts{
3460
<script>
3561
new Vue({
3662
el: "#app",
3763
data: {
38-
themes: []
64+
themes: [],
65+
themeSelected: '',
66+
themeData: {}
3967
},
4068
methods: {
4169
load: function (page) {
@@ -55,6 +83,31 @@
5583
toastr.error(error);
5684
});
5785
},
86+
settings: function (title) {
87+
this.themeSelected = title;
88+
89+
axios.get(webRoot + 'api/themes/data?theme=' + title)
90+
.then(response => {
91+
this.themeData = JSON.stringify(response.data, null, '\t');
92+
})
93+
.catch(function (error) { toastr.error(error); });
94+
95+
$('#dlgSettings').modal();
96+
},
97+
save: function () {
98+
var dt = {
99+
"theme": this.themeSelected,
100+
"data": this.themeData
101+
};
102+
axios.post(webRoot + 'api/themes/data', dt)
103+
.then(function (response) {
104+
toastr.success('Updated');
105+
$('#dlgSettings').modal('hide');
106+
})
107+
.catch(function (error) {
108+
toastr.error(error);
109+
});
110+
},
58111
remove: function(title){
59112
var result = confirm("Please confirm removing this theme");
60113
if (result) {

src/Core/Api/ThemesController.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,47 @@ public ActionResult Put(string id)
8787
}
8888
}
8989

90+
/// <summary>
91+
/// Get theme settings from data.json (admins only)
92+
/// </summary>
93+
/// <param name="theme">Theme name</param>
94+
/// <returns>Json data</returns>
95+
[Administrator]
96+
[HttpGet("data")]
97+
public ActionResult<string> GetThemeData(string theme)
98+
{
99+
try
100+
{
101+
var results = _store.GetThemeData(theme);
102+
103+
return Ok(results);
104+
}
105+
catch (Exception)
106+
{
107+
return StatusCode(StatusCodes.Status500InternalServerError, "File System Failure");
108+
}
109+
}
110+
111+
/// <summary>
112+
/// Saves theme data (theme/assets/data.json file, admins only)
113+
/// </summary>
114+
/// <param name="model">Theme data model</param>
115+
/// <returns>Ok or error</returns>
116+
[Administrator]
117+
[HttpPost("data")]
118+
public async Task<IActionResult> SaveThemeData(ThemeDataModel model)
119+
{
120+
try
121+
{
122+
await _store.SaveThemeData(model);
123+
return Ok("Created");
124+
}
125+
catch (Exception)
126+
{
127+
return StatusCode(StatusCodes.Status500InternalServerError, "File save error");
128+
}
129+
}
130+
90131
/// <summary>
91132
/// Remove and unistall theme from the blog (admins only)
92133
/// </summary>
@@ -140,11 +181,13 @@ List<ThemeItem> GetThemes()
140181
var theme = themeTitle.ToLower();
141182
var slash = Path.DirectorySeparatorChar.ToString();
142183
var file = $"{AppSettings.WebRootPath}{slash}themes{slash}{theme}{slash}{Constants.ThemeScreenshot}";
184+
var data = $"{AppSettings.WebRootPath}{slash}themes{slash}{theme}{slash}assets{slash}{Constants.ThemeDataFile}";
143185
var item = new ThemeItem
144186
{
145187
Title = themeTitle,
146188
Cover = System.IO.File.Exists(file) ? $"themes/{theme}/{Constants.ThemeScreenshot}" : Constants.ImagePlaceholder,
147-
IsCurrent = theme == _blog.Theme.ToLower()
189+
IsCurrent = theme == _blog.Theme.ToLower(),
190+
HasSettings = System.IO.File.Exists(data)
148191
};
149192

150193
if (theme == _blog.Theme.ToLower())
@@ -164,5 +207,6 @@ public class ThemeItem
164207
public string Title { get; set; }
165208
public string Cover { get; set; }
166209
public bool IsCurrent { get; set; }
210+
public bool HasSettings { get; set; }
167211
}
168212
}

src/Core/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ public class Constants
2323
public static string ImagePlaceholder = "lib/img/img-placeholder.png";
2424
public static string ThemeScreenshot = "screenshot.png";
2525
public static string ThemeEditReturnUrl = "~/admin/settings/theme";
26+
public static string ThemeDataFile = "data.json";
2627
}
2728
}

src/Core/CoreAPI.xml

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Core/Data/Models/ThemeModel.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Core.Data
2+
{
3+
public class ThemeDataModel
4+
{
5+
public string Theme { get; set; }
6+
public string Data { get; set; }
7+
}
8+
}

src/Core/Services/StorageService.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public interface IStorageService
3333

3434
string GetHtmlTemplate(string template);
3535

36+
string GetThemeData(string theme);
37+
Task SaveThemeData(ThemeDataModel model);
38+
3639
Task<IEnumerable<AssetItem>> Find(Func<AssetItem, bool> predicate, Pager pager, string path = "", bool sanitize = false);
3740

3841
Task Reset();
@@ -191,6 +194,30 @@ public IList<WidgetItem> GetWidgets(string theme)
191194
return widgets;
192195
}
193196

197+
public string GetThemeData(string theme)
198+
{
199+
string jsonFile = $"{AppSettings.WebRootPath}{_separator}themes{_separator}{theme}{_separator}assets{_separator}{Constants.ThemeDataFile}";
200+
if (File.Exists(jsonFile))
201+
{
202+
using (StreamReader r = new StreamReader(jsonFile))
203+
{
204+
return r.ReadToEnd();
205+
}
206+
}
207+
return "";
208+
}
209+
210+
public async Task SaveThemeData(ThemeDataModel model)
211+
{
212+
string jsonFile = $"{AppSettings.WebRootPath}{_separator}themes{_separator}{model.Theme}{_separator}assets{_separator}{Constants.ThemeDataFile}";
213+
if (File.Exists(jsonFile))
214+
{
215+
File.Delete(jsonFile);
216+
File.WriteAllText(jsonFile, model.Data);
217+
}
218+
await Task.CompletedTask;
219+
}
220+
194221
public string GetHtmlTemplate(string template)
195222
{
196223
string content = "<p>Not found</p>";

0 commit comments

Comments
 (0)