diff --git a/cinera/cinera.c b/cinera/cinera.c index a617c3b..fa23d8d 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -23,7 +23,7 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 10, - .Patch = 10 + .Patch = 11 }; #include // NOTE(matt): varargs @@ -1416,6 +1416,7 @@ publicly, then we can set ignore_privacy to \"true\" and save the resources othe "The ID of a person (see also person) who indexes a project. They will then appear in the credits menu of each entry in the project. Note that setting an indexer in the configuration \ file credits this person for the entire project, but indexers may \"uncredit\" people in the [video] node of a HMML file." }, + { "instance_title", "The name of the instance, used as the cinera:title on the global search page." }, { "js_path", "Path relative to assets_root_dir and assets_root_url where JavaScript files are located." }, { "lineage", 0, 0, "A slash-separated string of all project IDs from the top of the family tree to the present project." }, { "lineage_without_origin", 0, 0, "Same as the $lineage, without the first component (the $origin)." }, @@ -1534,6 +1535,7 @@ typedef enum IDENT_IMAGES_PATH, IDENT_INCLUDE, IDENT_INDEXER, + IDENT_INSTANCE_TITLE, IDENT_JS_PATH, IDENT_LINEAGE, IDENT_LINEAGE_WITHOUT_ORIGIN, @@ -3705,6 +3707,16 @@ CopyStringToBufferHTMLSafe_(int LineNumber, buffer *Dest, string String) *Dest->Ptr = '\0'; } +#define CopyStringToBufferHTMLSafeSurrounded(Dest, Pre, String, Post) CopyStringToBufferHTMLSafeSurrounded_(__LINE__, Dest, Pre, String, Post) +void +CopyStringToBufferHTMLSafeSurrounded_(int LineNumber, buffer *Dest, string Pre, string String, string Post) +{ + // NOTE(matt): Only the String gets HTML-encoded. The Pre and Post parts get copied as-is + CopyStringToBufferNoFormat_(LineNumber, Dest, Pre); + CopyStringToBufferHTMLSafe_(LineNumber, Dest, String); + CopyStringToBufferNoFormat_(LineNumber, Dest, Post); +} + #define CopyStringToBufferHTMLSafeBreakingOnSlash(Dest, String) CopyStringToBufferHTMLSafeBreakingOnSlash_(__LINE__, Dest, String) void CopyStringToBufferHTMLSafeBreakingOnSlash_(int LineNumber, buffer *Dest, string String) @@ -11029,6 +11041,16 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF CopyStringToBuffer(&CollationBuffers->IncludesPlayer, "\">"); + CopyStringToBuffer(&CollationBuffers->IncludesPlayer, + "\n" + "\n "); + CopyStringToBufferHTMLSafeSurrounded(&CollationBuffers->IncludesPlayer, + Wrap0("\n ")); + CopyStringToBufferHTMLSafeSurrounded(&CollationBuffers->IncludesPlayer, + Wrap0("\n Title, Wrap0("\">")); + CopyStringToBufferHTMLSafeSurrounded(&CollationBuffers->IncludesPlayer, + Wrap0("\n WrittenLineage, Wrap0("\">")); + asset *JSPlayerPost = GetAsset(Wrap0(BuiltinAssets[ASSET_JS_PLAYER_POST].Filename), ASSET_JS); ConstructResolvedAssetURL(&URL, JSPlayerPost, PAGE_PLAYER); CopyStringToBuffer(&PlayerBuffers.Script, @@ -13967,6 +13989,25 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P CopyStringToBuffer(&CollationBuffers->IncludesSearch, "\" defer>"); + if(P) + { + CopyStringToBuffer(&CollationBuffers->IncludesSearch, + "\n" + "\n "); + CopyStringToBufferHTMLSafeSurrounded(&CollationBuffers->IncludesSearch, + Wrap0("\n Title, Wrap0("\">")); + CopyStringToBufferHTMLSafeSurrounded(&CollationBuffers->IncludesSearch, + Wrap0("\n WrittenLineage, Wrap0("\">")); + } + else + { + CopyStringToBuffer(&CollationBuffers->IncludesSearch, + "\n" + "\n "); + CopyStringToBufferHTMLSafeSurrounded(&CollationBuffers->IncludesSearch, + Wrap0("\n InstanceTitle, Wrap0("\">")); + } + OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0); AppendStringToBuffer(B, Wrap0(" class=\"cineraQueryContainer\">")); diff --git a/cinera/cinera_config.c b/cinera/cinera_config.c index 98064f2..456bcdf 100644 --- a/cinera/cinera_config.c +++ b/cinera/cinera_config.c @@ -560,6 +560,8 @@ typedef struct string DatabaseLocation; string CacheDir; + string InstanceTitle; + string GlobalTemplatesDir; string GlobalSearchTemplatePath; string GlobalSearchDir; @@ -903,6 +905,7 @@ InitTypeSpecs(void) PushTypeSpecField(Root, FT_STRING, IDENT_HMML_DIR, TRUE); PushTypeSpecField(Root, FT_STRING, IDENT_IMAGES_PATH, TRUE); PushTypeSpecField(Root, FT_STRING, IDENT_INDEXER, FALSE); + PushTypeSpecField(Root, FT_STRING, IDENT_INSTANCE_TITLE, TRUE); PushTypeSpecField(Root, FT_STRING, IDENT_JS_PATH, TRUE); PushTypeSpecField(Root, FT_STRING, IDENT_LOG_LEVEL, TRUE); PushTypeSpecField(Root, FT_STRING, IDENT_OWNER, TRUE); @@ -2046,6 +2049,12 @@ SetDefaults(scope_tree *Root, memory_book *TypeSpecs) PushDefaultIntPair(SupportPatreon, IDENT_ICON_VARIANTS, GetArtVariantFromString(Wrap0("normal"))); PushDefaultPair(SupportPatreon, IDENT_URL, Wrap0("https://patreon.com/$person")); + scope_tree *SupportGitHub = PushDefaultScope(TypeSpecs, Root, IDENT_SUPPORT, Wrap0("github")); + PushDefaultPair(SupportGitHub, IDENT_ICON, Wrap0("cinera_sprite_github.png")); + PushDefaultIntPair(SupportGitHub, IDENT_ICON_TYPE, IT_GRAPHICAL); + PushDefaultIntPair(SupportGitHub, IDENT_ICON_VARIANTS, GetArtVariantFromString(Wrap0("normal"))); + PushDefaultPair(SupportGitHub, IDENT_URL, Wrap0("https://github.com/sponsors/$person")); + scope_tree *SupportSendOwl = PushDefaultScope(TypeSpecs, Root, IDENT_SUPPORT, Wrap0("sendowl")); PushDefaultPair(SupportSendOwl, IDENT_ICON, Wrap0("cinera_sprite_sendowl.png")); @@ -4581,6 +4590,7 @@ PrintConfig(config *C, bool ShouldClearTerminal) int AvailableColumns = TermCols - StringLength(Typography.Margin); TypesetPair(&Typography, 0, IDENT_DB_LOCATION, C->DatabaseLocation, AvailableColumns); TypesetPair(&Typography, 0, IDENT_CACHE_DIR, C->CacheDir, AvailableColumns); + TypesetPair(&Typography, 0, IDENT_INSTANCE_TITLE, C->InstanceTitle, AvailableColumns); fprintf(stderr, "\n"); TypesetPair(&Typography, 0, IDENT_GLOBAL_TEMPLATES_DIR, C->GlobalTemplatesDir, AvailableColumns); @@ -4800,6 +4810,8 @@ ResolveVariables(scope_tree *S) // NOTE(matt): String case IDENT_DB_LOCATION: { Result->DatabaseLocation = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); } break; + case IDENT_INSTANCE_TITLE: + { Result->InstanceTitle = ResolveString(Result, &Errors, S, Pair, TRUE); } break; case IDENT_GLOBAL_SEARCH_DIR: { Result->GlobalSearchDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); diff --git a/cinera/cinera_sprite_github.png b/cinera/cinera_sprite_github.png new file mode 100644 index 0000000..2cc2ecf Binary files /dev/null and b/cinera/cinera_sprite_github.png differ