AI Instructions — Build a Rocket AppTheme
How to Use This Document
This document is an instruction set for an AI assistant. When a user says something like:
"Build me a RocketContent AppTheme that shows a hero image with a title and two columns of text" "Create a RocketDirectory product catalogue AppTheme with a card grid list and a detail page" "Make a RocketBlog AppTheme that shows posts with a category sidebar"
The AI should read this document and use it to produce a complete, working set of AppTheme files.
Step 0 — Determine the Target System
Ask the user (or infer from context) which Rocket module system the AppTheme is for:
| System | Folder prefix | Use case |
|---|---|---|
| RocketContent | rocketcontentapi. |
Simple single-article content with rows: text, images, rich-text, links, docs |
| RocketDirectory | rocketdirectoryapi. |
Product/service catalogue — list + detail + categories + properties |
| RocketBlog | rocketblogapi. |
Blog posts — list + detail + categories + tags + months archive |
| RocketNews | rocketnewsapi. |
News articles — same structure as RocketBlog |
| RocketEvents | rocketeventsapi. |
Date-based events — list + detail + calendar |
If the user says "RocketBlog", "RocketNews", or "RocketEvents", follow the RocketDirectory template rules below (they share the same base class) but use the system-specific values shown in the per-system tables.
Step 1 — Determine the AppTheme Name and Output Path
The AppTheme folder name follows the convention:
<systemprefix>.<ThemeName>
Rules:
- MUST NOT start with a number or underscore.
- ThemeName MUST be PascalCase, no spaces.
- The folder goes inside an AppTheme project folder, e.g.
AppThemes-W3-CSS\.
Ask the user for a name if not provided. Default to something descriptive of the design (e.g. rocketcontentapi.HeroCard).
Output the full set of files in this structure:
<systemprefix>.<ThemeName>\
versioncontrol.xml
1.0\
default\
(all .cshtml templates)
css\
<ThemeName>.css
dep\
<themenamelowercase>.dep
Step 2 — Understand the User's Design Request
Before generating any code, extract the following from the user's request:
- Fields — what data fields does the design need? (title, image, summary, date, price, rich-text body, etc.)
- List layout — how should articles/rows appear in a list? (card grid, table rows, single column, etc.)
- Detail layout — is there a separate detail/single-article view needed?
- Sidebar — does the design include categories, tags, filters, or months?
- Admin fields — what does the editor need to fill in? (maps directly to the fields above)
- Module settings — are there per-module display options? (image size, show/hide elements, colour, etc.)
Step 3 — Generate the Files
Generate ALL files listed for the target system. Do not skip any file, even if it is a minimal placeholder.
SYSTEM: RocketContent
When to Use
Use when the user wants simple page content: one article per module, with optional multiple rows per article. Best for hero sections, about pages, service blocks, icon grids, and similar fixed-layout content.
Template Header (all templates)
@inherits RocketContentAPI.Components.RocketContentAPITokens<Simplisity.SimplisityRazor>
@AssignDataModel(Model)
<!--inject-->
@AddProcessDataResx(appTheme, true) is optional on view templates (adds resource key lookup for the view theme). Add it after @AssignDataModel(Model) if the template uses @ResourceKey(...).
Available Model Objects
| Object | How to use |
|---|---|
articleData |
The article being displayed or edited |
articleRowData |
The current row in a foreach loop |
info |
Raw XML node for the current row (use for GetXmlProperty) |
rowData |
Alias for info |
headerData |
Article-level info node (not a row) |
moduleData |
Module settings — moduleData.GetSetting("key"), moduleData.GetSettingInt("key"), moduleData.GetSettingBool("key") |
sessionParams |
Session data, culture, paging |
portalData |
Portal name, paths |
appTheme |
Admin AppTheme object (same as appThemeAdmin) |
appThemeView |
View AppTheme object |
appThemeAdmin |
Admin AppTheme object |
appThemeSystem |
System shared templates |
Required Files
versioncontrol.xml
<genxml>
<rocketversion>1.0.0</rocketversion>
</genxml>
1.0\default\View.cshtml
Main public display. Iterates rows. Use [INJECT] for layout sub-templates.
@inherits RocketContentAPI.Components.RocketContentAPITokens<Simplisity.SimplisityRazor>
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
@{
var stylepadding = StylePadding();
var backgroundcolor = moduleData.GetSetting("backgroundcolor");
}
<div class="containerouter @backgroundcolor @(moduleData.GetSetting("cssclass"))">
<div class="w3-section containerinner" style="@stylepadding">
@foreach (var articleRowData in articleData.GetRows())
{
Model.SetDataObject("articlerow", articleRowData);
var info = articleRowData.Info;
if (!info.GetXmlPropertyBool("genxml/checkbox/hiderow"))
{
[INJECT:apptheme,LayoutRow.cshtml]
}
}
</div>
</div>
Replace
LayoutRow.cshtmlwith your actual layout sub-template name(s). Add multiple[INJECT]blocks for multiple layout variants.
1.0\default\LayoutRow.cshtml
The display sub-template for a single row. Build the HTML for the user's requested design here.
@inherits RocketContentAPI.Components.RocketContentAPITokens<Simplisity.SimplisityRazor>
@AssignDataModel(Model)
<!--inject-->
@{
var articleImage = articleRowData.GetImage(0);
var title = info.GetXmlProperty("genxml/lang/genxml/textbox/title");
var summary = info.GetXmlProperty("genxml/lang/genxml/textbox/summary");
}
<div class="w3-row w3-padding">
@if (articleImage.RelPath != "")
{
<img src="@ImageUrl(articleImage.RelPath, moduleData.GetSettingInt("width"), moduleData.GetSettingInt("height"))"
alt="@title" class="w3-image" />
}
<h2 class="w3-padding-top">@title</h2>
<p>@summary</p>
</div>
Adapt the fields and HTML to match the user's request. Replace
titleandsummarywith the field names the user asked for.
1.0\default\AdminDetail.cshtml
@inherits RocketContentAPI.Components.RocketContentAPITokens<Simplisity.SimplisityRazor>
@AssignDataModel(Model)
@AddProcessDataResx(appThemeView, true)
<!--inject-->
<div class="w3-row">
<div id="articledetailpanel" class="w3-threequarter">
[INJECT:appthemeadmin,AdminRow.cshtml]
</div>
<div class="w3-quarter">
[INJECT:appthemesystem,AdminRowSelect.cshtml]
</div>
</div>
1.0\default\AdminRow.cshtml
The admin data-entry form for a single row. Add one input block for every field the user's design needs.
@inherits RocketContentAPI.Components.RocketContentAPITokens<Simplisity.SimplisityRazor>
@AssignDataModel(Model)
@AddProcessDataResx(appThemeView, true)
<!--inject-->
@RowKey(rowData)
<div class="w3-row w3-padding">
<label>Title</label>
@EditFlag(sessionParams)
@TextBox(info, "genxml/lang/genxml/textbox/title",
"class='w3-input w3-border w3-margin-bottom' autocomplete='off'", "")
</div>
<div class="w3-row w3-padding">
<label>Summary</label>
@EditFlag(sessionParams)
@TextArea(info, "genxml/lang/genxml/textbox/summary",
"class='w3-input w3-border w3-margin-bottom' autocomplete='off' rows='4'", "")
</div>
<div class="w3-row w3-padding">
<label>Image</label>
[INJECT:appthemesystem,ArticleImage.cshtml]
</div>
<div class="w3-row w3-padding">
<label>Hide Row</label>
@CheckBox(info, "genxml/checkbox/hiderow", "", "class='w3-check'", false)
</div>
Add, remove, or rename fields to match the user's request. Use
genxml/lang/genxml/textbox/for localised fields andgenxml/textbox/for non-localised fields.
1.0\default\AdminFirstHeader.cshtml
@inherits RocketContentAPI.Components.RocketContentAPITokens<Simplisity.SimplisityRazor>
[INJECT:appthemesystem,CKEditor4.cshtml]
Only needed if the admin form includes a rich-text
@Editor(...)field. Leave minimal if not.
1.0\default\AdminLastHeader.cshtml
@inherits RocketContentAPI.Components.RocketContentAPITokens<Simplisity.SimplisityRazor>
1.0\default\ThemeSettings.cshtml
Per-module display settings. Add controls for any display options the user's design requires.
@inherits RocketContentAPI.Components.RocketContentAPITokens<Simplisity.SimplisityRazor>
@using Simplisity;
@using RocketContentAPI.Components;
@using DNNrocketAPI.Components;
@{
var moduleData = (ModuleContentLimpet)Model.GetDataObject("modulesettings");
var info = new SimplisityInfo(moduleData.Record);
// NOTE: xPath for module settings MUST use "genxml/settings/*"
}
<div class="w3-row">
<div class="w3-third w3-padding">
<label>Image Width (px)</label>
@TextBox(info, "genxml/settings/width", "class='w3-input w3-border'", "640")
</div>
<div class="w3-third w3-padding">
<label>Image Height (px)</label>
@TextBox(info, "genxml/settings/height", "class='w3-input w3-border'", "400")
</div>
<div class="w3-third w3-padding">
<label>CSS Class</label>
@TextBox(info, "genxml/settings/cssclass", "class='w3-input w3-border'", "")
</div>
<div class="w3-row w3-padding">
<label>Top Padding</label>
@TextBox(info, "genxml/settings/toppadding", "class='w3-input' min='0' max='320' step='8'", "8", false, 0, "", "range")
</div>
<div class="w3-row w3-padding">
<label>Bottom Padding</label>
@TextBox(info, "genxml/settings/bottompadding", "class='w3-input' min='0' max='320' step='8'", "8", false, 0, "", "range")
</div>
</div>
1.0\dep\<themenamelowercase>.dep
<genxml>
<deps list="true">
<genxml>
<ctrltype>css</ctrltype>
<url>/DesktopModules/DNNrocket/css/w3.css</url>
<ecofriendly>true</ecofriendly>
<condition check="notexist">/Portals/_default/skins/rocketw3/w3.css</condition>
</genxml>
<genxml>
<ctrltype>css</ctrltype>
<url>{appthemefolder}/css/<ThemeName>.css</url>
<ecofriendly>true</ecofriendly>
</genxml>
</deps>
<searchindex list="true">
<genxml>
<searchtitle>genxml/lang/genxml/textbox/title</searchtitle>
<searchdescription>genxml/lang/genxml/textbox/summary</searchdescription>
<searchbody>genxml/lang/genxml/textbox/summary</searchbody>
</genxml>
</searchindex>
</genxml>
1.0\css\<ThemeName>.css
Generate CSS rules that match the user's design request. Use W3.CSS utility classes in the templates where possible; only add custom CSS for anything W3.CSS does not provide.
SYSTEM: RocketDirectory (also RocketBlog, RocketNews, RocketEvents)
When to Use
Use when the user wants a full content directory, catalogue, blog, or news feed with:
- A list of articles (paged)
- A detail view for single articles
- Category navigation
- Tag or property/filter panels
- Admin CRUD for articles, categories, and properties
Per-System Values
Replace the placeholder values in every file according to the target system:
| System | @inherits class |
systemkey |
Article queryparam | Category queryparam |
|---|---|---|---|---|
| RocketDirectory | RocketDirectoryAPI.Components.RocketDirectoryAPITokens |
rocketdirectoryapi |
articleid |
catid |
| RocketBlog | RocketDirectoryAPI.Components.RocketDirectoryAPITokens |
rocketblogapi |
blogid |
blogcatid |
| RocketNews | RocketDirectoryAPI.Components.RocketDirectoryAPITokens |
rocketnewsapi |
newsid |
newscatid |
| RocketEvents | RocketEventsAPI.Components.RocketEventsAPITokens |
rocketeventsapi |
eventid |
(none) |
For RocketEvents, @using RocketEventsAPI.Components; must be added. For all others use @using RocketDirectoryAPI.Components;.
Template Header (all templates)
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
For RocketEvents replace both
RocketDirectoryAPI.Components.RocketDirectoryAPITokensand@using RocketDirectoryAPI.Components;withRocketEventsAPI.Components.RocketEventsAPITokensand@using RocketEventsAPI.Components;.
Available Model Objects
| Object | How to use |
|---|---|
articleData |
Single article — populated only when an article id is in the URL. null on list pages. |
articleDataList |
The paged article result set. Call articleDataList.GetArticleList() to iterate. |
categoryData |
Currently active category. Check categoryData.Exists before using. |
categoryDataList |
Full category tree. |
propertyData |
A single property/tag. |
propertyDataList |
All properties/tags. |
moduleData |
Module settings — .GetSetting("key"), .GetSettingInt("key"), .GetSettingBool("key") |
moduleSettings |
Alias for moduleData |
catalogSettings |
Portal-wide catalogue config (page size, sort, etc.) |
sessionParams |
Session, culture, paging |
portalData |
Portal info |
info |
Raw XML node for articleData |
infoempty |
Empty SimplisityInfo — use in add/review forms |
appTheme |
Current view AppTheme |
appThemeDirectory |
Directory shared templates ([INJECT:appthemedirectory,...]) |
appThemeDirectoryDefault |
Default directory templates ([INJECT:appthemedirectorydefault,...]) |
appThemeSystem |
System shared templates ([INJECT:appthemesystem,...]) |
Required Files
versioncontrol.xml
<genxml>
<rocketversion>1.0.0</rocketversion>
</genxml>
1.0\default\View.cshtml
Switches between list and detail based on whether articleData is populated.
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
@{
var hasSidebar = moduleData.GetSettingBool("showcategories")
|| moduleData.GetSettingBool("showtags")
|| moduleData.GetSettingBool("showfilters");
var mainCol = hasSidebar ? "w3-col l9 m8 s12 w3-margin-bottom"
: "w3-col l12 m12 s12 w3-margin-bottom";
}
<div class="w3-content" style="max-width:1400px;">
<div class="w3-row-padding">
<div class="@mainCol">
@if (articleData != null)
{
<text>[INJECT:apptheme,ArticleDetail.cshtml]</text>
}
else
{
<text>[INJECT:apptheme,ArticleList.cshtml]</text>
}
</div>
@if (hasSidebar)
{
<div class="w3-col l3 m4 s12 w3-margin-bottom">
@if (moduleData.GetSettingBool("showcategories"))
{
[INJECT:apptheme,Categories.cshtml]
}
@if (moduleData.GetSettingBool("showtags"))
{
[INJECT:apptheme,Tags.cshtml]
}
@if (moduleData.GetSettingBool("showfilters"))
{
[INJECT:apptheme,Filters.cshtml]
}
</div>
}
</div>
</div>
<div class="simplisity_loader" style="display:none;"><span class="simplisity_loader_inner"></span></div>
<script>
$(document).ready(function () { w3shared_pageLoad('w3-theme-l3'); });
</script>
1.0\default\ArticleList.cshtml
Renders the paged article list. Build the card/row/grid HTML to match the user's request.
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
@{
var articleList = articleDataList.GetArticleList();
var width = moduleData.GetSettingInt("width");
var imageHeight = moduleData.GetSettingInt("height");
}
[INJECT:appthemedirectorydefault,SearchBanner.cshtml]
@if (articleList.Count > 0)
{
<div class="w3-row" style="display:flex;flex-wrap:wrap;">
@foreach (var article in articleList)
{
var info = article.Info;
var articleImage = article.GetImage(0);
var detailUrl = DetailUrl(moduleData.DetailPageTabId(), article, categoryData,
new string[] { "page", sessionParams.Page.ToString() });
<div class="w3-col l4 m6 s12 w3-margin-bottom" style="display:flex;padding:8px;box-sizing:border-box;">
<div class="w3-card w3-white w3-round-large w3-border w3-hover-shadow" style="width:100%;overflow:hidden;">
<a href="@detailUrl" onclick="$('.simplisity_loader').show();">
@if (articleImage.RelPath != "" && moduleData.GetSettingBool("showimage"))
{
<img src="@ImageUrl(articleImage.RelPath, width, imageHeight)"
alt="@article.Name"
style="width:100%;height:@(imageHeight)px;object-fit:cover;" />
}
</a>
<div class="w3-container w3-padding">
[INJECT:apptheme,LayoutText.cshtml]
</div>
</div>
</div>
}
</div>
<div class="w3-center w3-padding-16">
[INJECT:appthemedirectorydefault,articlePaging.cshtml]
</div>
}
else
{
<div class="w3-card w3-white w3-round-large w3-border w3-padding w3-center">
<div class="w3-large w3-margin-top"><b>@ResourceKey("DNNrocket.notfound")</b></div>
</div>
}
1.0\default\LayoutText.cshtml
Text content inside each list card. Adapt fields to match the user's request.
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
<!--inject-->
@{
var localInfo = articleData.Info;
var name = articleData.Name;
var summary = localInfo.GetXmlProperty("genxml/lang/genxml/textbox/summary");
}
<h3 class="w3-margin-bottom">@name</h3>
<p class="w3-text-grey w3-small">@summary</p>
1.0\default\ArticleDetail.cshtml
Single article detail view. Build the full-page detail HTML to match the user's request.
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
@{
var articleImage = articleData.GetImage(0);
var name = articleData.Name;
var body = info.GetXmlProperty("genxml/lang/genxml/textbox/body");
var listRtnUrl = ReturnUrl(moduleData.DetailPageTabId(), categoryData);
}
<div class="w3-card w3-white w3-round-large w3-border w3-padding w3-margin-bottom">
@if (articleImage.RelPath != "")
{
<img src="@ImageUrl(articleImage.RelPath, moduleData.GetSettingInt("width"), 400)"
alt="@name" class="w3-image w3-margin-bottom" style="width:100%;" />
}
<h1>@name</h1>
<div class="w3-padding">@Raw(body)</div>
<div class="w3-margin-top">
<a href="@listRtnUrl" class="w3-button w3-theme-l5 w3-round-xlarge">
@ButtonIconText(ButtonTypes.back)
</a>
</div>
</div>
1.0\default\AdminList.cshtml
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
<div class="w3-animate-opacity w3-card w3-padding w3-margin w3-white">
[INJECT:appthemedirectory,AdminSearch.cshtml]
<div id="datalistsection" class="w3-padding">
<table class="w3-table w3-bordered w3-hoverable">
<thead>
<tr>
<th style="width:54px;"></th>
<th>@ResourceKey("DNNrocket.name")</th>
</tr>
</thead>
@foreach (ArticleLimpet article in articleDataList.GetArticleList())
{
<tr class="simplisity_click"
s-cmd="articleadmin_editarticle"
s-fields='{"articleid":"@article.ArticleId","track":"true"}'
style="cursor:pointer;">
<td>
<img src="@ImageUrl(article.GetImage(0).RelPath, 48, 48)"
style="height:48px;width:48px;" class="w3-round" />
</td>
<td><b>@article.Name</b></td>
</tr>
}
</table>
@RenderTemplate("AdminPaging.cshtml", appThemeDirectory, Model, true)
</div>
</div>
1.0\default\AdminDetail.cshtml
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
<div id="articleeditcontent" class="w3-animate-opacity w3-card w3-padding w3-margin w3-white">
[INJECT:appthemedirectory,editbuttonbar.cshtml]
<div class="w3-row">
<div class="w3-twothird w3-padding-small">
[INJECT:appthemesystem,AdminGeneralBlock.cshtml]
[INJECT:appthemedirectory,ArticleModelsBlock.cshtml]
</div>
<div class="w3-third w3-padding-small">
[INJECT:appthemedirectory,ArticleCategoryListBlock.cshtml]
[INJECT:appthemedirectory,ArticlePropertyListBlock.cshtml]
[INJECT:appthemedirectory,ArticleimagesBlock.cshtml]
[INJECT:appthemedirectory,ArticleDocumentsBlock.cshtml]
[INJECT:appthemedirectory,ArticleLinksBlock.cshtml]
</div>
</div>
</div>
1.0\default\AdminExtra.cshtml
Custom admin fields specific to this AppTheme. Called by ArticleModelsBlock.cshtml.
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
<!--inject-->
<div class="w3-row w3-padding">
<label>Summary</label>
@EditFlag(sessionParams)
@TextArea(info, "genxml/lang/genxml/textbox/summary",
"class='w3-input w3-border w3-margin-bottom' autocomplete='off' rows='3'", "")
</div>
<div class="w3-row w3-padding">
<label>Body</label>
@EditFlag(sessionParams)
@Editor(info, "genxml/lang/genxml/textbox/body", Model, 0, "")
</div>
Add, remove, or rename fields to match the user's request. Only put fields here that are NOT already in
AdminGeneralBlock.cshtml(which provides name, ref, published date, hide/show).
1.0\default\AdminHeader.cshtml
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
<!-- Placeholder template so the system does not show an error on admin. -->
<!--inject-->
1.0\default\Categories.cshtml
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
[INJECT:appthemeshared,categories.cshtml]
1.0\default\Tags.cshtml
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
[INJECT:appthemeshared,tags.cshtml]
1.0\default\Filters.cshtml
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
[INJECT:appthemeshared,filters.cshtml]
1.0\default\ArticleSat.cshtml
Satellite template — displays article data without loading it (loaded via AJAX by another module).
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using DNNrocketAPI.Components;
@using RocketDirectoryAPI.Components;
@AssignDataModel(Model)
@AddProcessDataResx(appTheme, true)
<!--inject-->
@if (articleData != null)
{
<div class="w3-padding">
<h3>@articleData.Name</h3>
</div>
}
1.0\default\ThemeSettings.cshtml
@inherits RocketDirectoryAPI.Components.RocketDirectoryAPITokens<Simplisity.SimplisityRazor>
@using Simplisity;
@using RocketDirectoryAPI.Components;
@using DNNrocketAPI.Components;
@{
var moduleData = (ModuleContentLimpet)Model.GetDataObject("modulesettings");
var info = new SimplisityInfo(moduleData.Record);
}
<div class="w3-row">
<div class="w3-third w3-padding">
<label>Image Width (px)</label>
@TextBox(info, "genxml/settings/width", "class='w3-input w3-border'", "640")
</div>
<div class="w3-third w3-padding">
<label>Image Height (px)</label>
@TextBox(info, "genxml/settings/height", "class='w3-input w3-border'", "200")
</div>
<div class="w3-third w3-padding">
<label>Show Image</label>
@CheckBox(info, "genxml/settings/showimage", "", "class='w3-check'", true)
</div>
</div>
@if (moduleData.DisplayTemplate == "view.cshtml")
{
<div class="w3-row">
<div class="w3-third w3-padding">
@CheckBox(info, "genxml/settings/showcategories", "Show Categories", "class='w3-check'")
</div>
<div class="w3-third w3-padding">
@CheckBox(info, "genxml/settings/showtags", "Show Tags", "class='w3-check'")
</div>
<div class="w3-third w3-padding">
@CheckBox(info, "genxml/settings/showfilters", "Show Filters", "class='w3-check'")
</div>
</div>
}
<div class="w3-row w3-padding">
<label>Top Padding</label>
@TextBox(info, "genxml/settings/toppadding", "class='w3-input' min='0' max='320' step='8'", "8", false, 0, "", "range")
</div>
<div class="w3-row w3-padding">
<label>Bottom Padding</label>
@TextBox(info, "genxml/settings/bottompadding", "class='w3-input' min='0' max='320' step='8'", "8", false, 0, "", "range")
</div>
1.0\dep\<themenamelowercase>.dep
Replace SYSTEMKEY, ARTICLEIDPARAM, and CATIDPARAM with the values from the per-system table above.
<genxml>
<deps list="true">
<genxml>
<ctrltype>css</ctrltype>
<url>/DesktopModules/DNNrocket/css/w3.css</url>
<ecofriendly>true</ecofriendly>
<ignoreonskin>rocketw3</ignoreonskin>
</genxml>
<genxml>
<ctrltype>css</ctrltype>
<url>/DesktopModules/DNNrocket/Simplisity/css/simplisity.css</url>
<ecofriendly>true</ecofriendly>
</genxml>
<genxml>
<ctrltype>js</ctrltype>
<url>/DesktopModules/DNNrocket/Simplisity/js/simplisity.js</url>
<ecofriendly>true</ecofriendly>
</genxml>
<genxml>
<ctrltype>js</ctrltype>
<url>{appthemeshareddirectory}/js/w3shared.js</url>
<ecofriendly>true</ecofriendly>
</genxml>
<genxml>
<ctrltype>css</ctrltype>
<url>{appthemeshareddirectory}/css/w3shared.css</url>
<ecofriendly>true</ecofriendly>
</genxml>
<genxml>
<ctrltype>css</ctrltype>
<url>{appthemefolder}/css/<ThemeName>.css</url>
<ecofriendly>true</ecofriendly>
</genxml>
<genxml>
<ctrltype>js</ctrltype>
<url>{jquery}</url>
<ecofriendly>true</ecofriendly>
</genxml>
</deps>
<moduletemplates list="true">
<genxml>
<file>view.cshtml</file>
<name>Full View</name>
<cmd>listdetail</cmd>
</genxml>
<genxml>
<file>Categories.cshtml</file>
<name>Category Menu</name>
<cmd>catmenu</cmd>
</genxml>
<genxml>
<file>ArticleSat.cshtml</file>
<name>Satellite</name>
<cmd>satellite</cmd>
</genxml>
</moduletemplates>
<adminpanelinterfacekeys list="true">
<genxml>
<interfacekey>articleadmin</interfacekey>
<show>true</show>
</genxml>
<genxml>
<interfacekey>categoryadmin</interfacekey>
<show>true</show>
</genxml>
<genxml>
<interfacekey>propertyadmin</interfacekey>
<show>true</show>
</genxml>
<genxml>
<interfacekey>settingsadmin</interfacekey>
<show>true</show>
</genxml>
<genxml>
<interfacekey>rocketdirectoryadmin</interfacekey>
<show>true</show>
</genxml>
</adminpanelinterfacekeys>
<queryparams list="true">
<genxml>
<queryparam>CATIDPARAM</queryparam>
<tablename>rocketdirectoryapi</tablename>
<systemkey>SYSTEMKEY</systemkey>
<datatype>category</datatype>
</genxml>
<genxml>
<queryparam>ARTICLEIDPARAM</queryparam>
<tablename>rocketdirectoryapi</tablename>
<systemkey>SYSTEMKEY</systemkey>
<datatype>article</datatype>
</genxml>
</queryparams>
<menuprovider>
<genxml>
<assembly>RocketDirectoryAPI</assembly>
<namespaceclass>RocketDirectoryAPI.Components.MenuDirectory</namespaceclass>
<systemkey>SYSTEMKEY</systemkey>
</genxml>
</menuprovider>
</genxml>
1.0\css\<ThemeName>.css
Generate CSS to match the user's design. Use W3.CSS utility classes in templates first; only add custom CSS here for anything W3.CSS does not cover.
Step 4 — Field Naming Conventions
Use these xPath conventions consistently:
| Field type | xPath |
|---|---|
| Localised text (title, name, summary, body) | genxml/lang/genxml/textbox/fieldname |
| Non-localised text (ref, price, date) | genxml/textbox/fieldname |
| Checkbox | genxml/checkbox/fieldname |
| Select / dropdown | genxml/select/fieldname |
| Module setting | genxml/settings/fieldname |
Read values in view templates:
var title = info.GetXmlProperty("genxml/lang/genxml/textbox/title");
var price = info.GetXmlPropertyDecimal("genxml/textbox/price");
var isHidden = info.GetXmlPropertyBool("genxml/checkbox/hidden");
Read module settings:
var showImage = moduleData.GetSettingBool("showimage");
var width = moduleData.GetSettingInt("width");
var cssClass = moduleData.GetSetting("cssclass");
Step 5 — Common Helper Tokens
These tokens are available in all templates and should be used where appropriate:
| Token | Purpose |
|---|---|
@ImageUrl(relPath, width, height) |
Returns a resized image URL |
@Raw(htmlString) |
Outputs HTML without encoding (for rich-text fields) |
@ResourceKey("key") |
Localised string from .resx |
@EditFlag(sessionParams) |
Multi-language flag icon (admin only) |
@DeepL("field", "xpath") |
DeepL translation button (admin only) |
@ChatGPT("field") |
ChatGPT assist button (admin only) |
@DetailUrl(tabId, article, category, extras) |
SEO-friendly article detail URL |
@ReturnUrl(tabId, category) |
Back-to-list URL from detail page |
@ButtonIconText(ButtonTypes.back) |
Back button with icon |
@DateOf(info, xpath, culture, format) |
Formatted date from XML field |
@StylePadding() |
CSS padding string from toppadding/bottompadding module settings |
Step 6 — Mandatory Rules
The AI MUST follow these rules for every generated AppTheme:
- Every template file MUST start with the correct
@inheritsline for the target system. @AssignDataModel(Model)MUST be called in every template that accesses model objects.<!--inject-->MUST be present in every template that will be used as an injected sub-template.@RowKey(rowData)MUST be the first output line inAdminRow.cshtmlfor RocketContent themes.- Folder names MUST NOT start with a number.
- Module settings xPaths MUST use
genxml/settings/inThemeSettings.cshtml. - The
.depfile MUST include the correctsystemkeyandqueryparamvalues for the target system. versioncontrol.xmlMUST be present in the root of the AppTheme folder.- Do not load w3.css if the skin already provides it — use the
<condition>or<ignoreonskin>guard in the dep file. - Do not hardcode portal IDs or module IDs in templates — always use tokens and model objects.