@@ -35,6 +35,61 @@ static const char *homeSvg =
3535 " <path d=\" M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8\" />"
3636 " <path d=\" M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2 2z\" /></svg>" ;
3737
38+ static const char *upFolderSvg =
39+ " <svg xmlns=\" http://www.w3.org/2000/svg\" "
40+ " width=\" 18\" height=\" 18\" viewBox=\" 0 0 24 24\" fill=\" none\" stroke=\" %23e0e0e0\" stroke-width=\" 2\" "
41+ " stroke-linecap=\" round\" stroke-linejoin=\" round\" class=\" lucide lucide-folder-up-icon lucide-folder-up\" >"
42+ " <path d=\" M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />"
43+ " <path d=\" M12 10v6\" />"
44+ " <path d=\" m9 13 3-3 3 3\" /></svg>" ;
45+
46+ static const char *filmSvg =
47+ " <svg xmlns=\" http://www.w3.org/2000/svg\" "
48+ " width=\" 18\" height=\" 18\" viewBox=\" 0 0 24 24\" fill=\" none\" stroke=\" %23e0e0e0\" stroke-width=\" 2\" "
49+ " stroke-linecap=\" round\" stroke-linejoin=\" round\" class=\" lucide lucide-film-icon lucide-film\" >"
50+ " <rect width=\" 18\" height=\" 18\" x=\" 3\" y=\" 3\" rx=\" 2\" />"
51+ " <path d=\" M7 3v18\" />"
52+ " <path d=\" M3 7.5h4\" />"
53+ " <path d=\" M3 12h18\" />"
54+ " <path d=\" M3 16.5h4\" />"
55+ " <path d=\" M17 3v18\" />"
56+ " <path d=\" M17 7.5h4\" />"
57+ " <path d=\" M17 16.5h4\" /></svg>" ;
58+
59+ static const char *imageSvg =
60+ " <svg xmlns=\" http://www.w3.org/2000/svg\" "
61+ " width=\" 18\" height=\" 18\" viewBox=\" 0 0 24 24\" fill=\" none\" stroke=\" %23e0e0e0\" stroke-width=\" 2\" "
62+ " stroke-linecap=\" round\" stroke-linejoin=\" round\" class=\" lucide lucide-file-image-icon lucide-file-image\" >"
63+ " <path d=\" M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" />"
64+ " <path d=\" M14 2v4a2 2 0 0 0 2 2h4\" />"
65+ " <circle cx=\" 10\" cy=\" 12\" r=\" 2\" />"
66+ " <path d=\" m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22\" /></svg>" ;
67+
68+ static const char *textfileSvg =
69+ " <svg xmlns=\" http://www.w3.org/2000/svg\" "
70+ " width=\" 18\" height=\" 18\" viewBox=\" 0 0 24 24\" fill=\" none\" stroke=\" %23e0e0e0\" stroke-width=\" 2\" "
71+ " stroke-linecap=\" round\" stroke-linejoin=\" round\" class=\" lucide lucide-file-text-icon lucide-file-text\" >"
72+ " <path d=\" M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" />"
73+ " <path d=\" M14 2v4a2 2 0 0 0 2 2h4\" />"
74+ " <path d=\" M10 9H8\" />"
75+ " <path d=\" M16 13H8\" />"
76+ " <path d=\" M16 17H8\" /></svg>" ;
77+
78+ static const char *activitySvg =
79+ " <svg xmlns=\" http://www.w3.org/2000/svg\" "
80+ " width=\" 18\" height=\" 18\" viewBox=\" 0 0 24 24\" fill=\" none\" stroke=\" %23e0e0e0\" stroke-width=\" 2\" "
81+ " stroke-linecap=\" round\" stroke-linejoin=\" round\" class=\" lucide lucide-activity-icon lucide-activity\" >"
82+ " <path d=\" M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\" /></svg>" ;
83+
84+ static const char *codexmlSvg =
85+ " <svg xmlns=\" http://www.w3.org/2000/svg\" "
86+ " width=\" 18\" height=\" 18\" viewBox=\" 0 0 24 24\" fill=\" none\" stroke=\" %23e0e0e0\" stroke-width=\" 2\" "
87+ " stroke-linecap=\" round\" stroke-linejoin=\" round\" class=\" lucide lucide-code-xml-icon lucide-code-xml\" >"
88+ " <path d=\" m18 16 4-4-4-4\" />"
89+ " <path d=\" m6 8-4 4 4 4\" />"
90+ " <path d=\" m14.5 4-5 16\" />"
91+ " </svg>" ;
92+
3893static const std::string styling =
3994 " <style>"
4095 " body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 20px; background-color: #2d2d2d; color: #e0e0e0; }"
@@ -55,6 +110,18 @@ static const std::string styling =
55110 std::string(fileSvg) + "' ); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
56111 " .home:before { content: url (' data:image/svg+xml;utf8," +
57112 std::string(homeSvg) + "' ); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
113+ " .upfolder:before { content: url (' data:image/svg+xml;utf8," +
114+ std::string(upFolderSvg) + "' ); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
115+ " .film:before { content: url (' data:image/svg+xml;utf8," +
116+ std::string(filmSvg) + "' ); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
117+ " .image:before { content: url (' data:image/svg+xml;utf8," +
118+ std::string(imageSvg) + "' ); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
119+ " .textfile:before { content: url (' data:image/svg+xml;utf8," +
120+ std::string(textfileSvg) + "' ); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
121+ " .activity:before { content: url (' data:image/svg+xml;utf8," +
122+ std::string(activitySvg) + "' ); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
123+ " .codexml:before { content: url (' data:image/svg+xml;utf8," +
124+ std::string(codexmlSvg) + "' ); vertical-align: middle; margin-right: 8px; color: #f0f0f0; }"
58125 " </style>" ;
59126
60127static const std::string pageHeader =
@@ -65,6 +132,28 @@ static const char *pageFooter = "</table></body>"
65132 " <footer><p>Powered by faucet</p></footer>"
66133 " </html>" ;
67134
135+ static std::string getFileTypeClass (const std::string &filename) {
136+ // determine file type by extension for icon
137+ size_t dotPos = filename.rfind (' .' );
138+ if (dotPos == std::string::npos || dotPos == filename.length () - 1 )
139+ return " file" ; // no extension
140+
141+ std::string ext = filename.substr (dotPos + 1 );
142+ std::transform (ext.begin (), ext.end (), ext.begin (), [](unsigned char c) { return std::tolower (c); });
143+
144+ if (ext == " mp4" || ext == " mkv" || ext == " avi" || ext == " mov" || ext == " wmv" || ext == " flv" || ext == " webm" )
145+ return " film" ;
146+ if (ext == " jpg" || ext == " jpeg" || ext == " png" || ext == " gif" || ext == " bmp" || ext == " svg" || ext == " webp" || ext == " tiff" )
147+ return " image" ;
148+ if (ext == " txt" || ext == " md" || ext == " log" || ext == " csv" || ext == " json" || ext == " xml" || ext == " ini" || ext == " cfg" )
149+ return " textfile" ;
150+ if (ext == " html" || ext == " htm" || ext == " css" || ext == " js" || ext == " cpp" || ext == " h" || ext == " hpp" || ext == " c" || ext == " java" || ext == " py" || ext == " rb" || ext == " go" )
151+ return " codexml" ;
152+ if (ext == " log" )
153+ return " activity" ;
154+ return " file" ; // default
155+ }
156+
68157void returnDirListing (int client_fd,
69158 const std::string &siteDir,
70159 const std::string &relPath,
@@ -132,7 +221,7 @@ void returnDirListing(int client_fd,
132221 if (!relPath.empty ())
133222 {
134223 body += " <tr><td><a href=\" /\" class=\" home\" >Home (/)</a></td><td></td><td></td></tr>" ; // root
135- body += " <tr><td><a href=\" ../\" class=\" directory \" >Parent Directory (../)</a></td><td></td><td></td></tr>" ; // parent dir
224+ body += " <tr><td><a href=\" ../\" class=\" upfolder \" >Parent Directory (../)</a></td><td></td><td></td></tr>" ; // parent dir
136225 }
137226
138227 for (auto &e : entries)
@@ -159,7 +248,7 @@ void returnDirListing(int client_fd,
159248 }
160249 else
161250 {
162- body += " \" class=\" file \" >" + display + " </a></td>" ;
251+ body += " \" class=\" " + getFileTypeClass (e) + " \" >" + display + " </a></td>" ;
163252 }
164253
165254 if (!isDir)
@@ -192,6 +281,9 @@ void returnDirListing(int client_fd,
192281 strftime (timebuf, sizeof (timebuf), " %Y-%m-%d %H:%M" , tm_info);
193282 body += " <td>" + std::string (timebuf) + " </td>" ;
194283 }
284+ } else
285+ {
286+ body += " <td></td><td></td>" ; // empty size and date for directories
195287 }
196288
197289 // close
0 commit comments