Nano Obssession: Chromeless window, Styles

Does the following:
 - Adds 'chromeless' mode (NanoUI defaults to using this)
  - Window borders disappear, replaced by in-browser elements for
    minimize/close/move/resize.
  - You *must* move/resize slowly when using this mode, or it can have
    unexpected results, as the JavaScript cannot keep up as well as the
    native windows movement.
 - StatusGroups are now transparent: This looks nice. That's about it.
 - Body background switched to a .svg format for the NanoUI Logo.

 - Coder things:
  - Nano's JavaScript now has a new class, NanoWindow
   - NanoWindow handles all of the chromeless work. It'll be used to
     replace portions of NanoStateManager later.
This commit is contained in:
Tigercat2000
2016-01-18 09:54:40 -08:00
parent 5a88ea74f0
commit 48349a3d9e
22 changed files with 447 additions and 167 deletions
+1
View File
@@ -246,6 +246,7 @@ CREATE TABLE `player` (
`sound` mediumint(8) DEFAULT '31',
`randomslot` tinyint(1) DEFAULT '0',
`volume` smallint(4) DEFAULT '100',
`nanoui_fancy` smallint(4) DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `ckey` (`ckey`)
) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1;
+1
View File
@@ -246,6 +246,7 @@ CREATE TABLE `SS13_player` (
`sound` mediumint(8) DEFAULT '31',
`randomslot` tinyint(1) DEFAULT '0',
`volume` smallint(4) DEFAULT '100',
`nanoui_fancy` smallint(4) DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `ckey` (`ckey`)
) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1;
+5
View File
@@ -80,6 +80,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
var/ooccolor = "#b82e00"
var/be_special = list() //Special role selection
var/UI_style = "Midnight"
var/nanoui_fancy = TRUE
var/toggles = TOGGLES_DEFAULT
var/sound = SOUND_DEFAULT
var/UI_style_color = "#ffffff"
@@ -389,6 +390,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
dat += "<table><tr><td width='340px' height='300px' valign='top'>"
dat += "<h2>General Settings</h2>"
dat += "<b>UI Style:</b> <a href='?_src_=prefs;preference=ui'><b>[UI_style]</b></a><br>"
dat += "<b>Fancy NanoUI:</b> <a href='?_src_=prefs;preference=nanoui'>[(nanoui_fancy) ? "Yes" : "No"]</a><br>"
dat += "<b>Custom UI settings:</b><br>"
dat += "<b>Color:</b> <a href='?_src_=prefs;preference=UIcolor'><b>[UI_style_color]</b></a> <table style='display:inline;' bgcolor='[UI_style_color]'><tr><td>__</td></tr></table><br>"
dat += "<b>Alpha (transparency):</b> <a href='?_src_=prefs;preference=UIalpha'><b>[UI_style_alpha]</b></a><br>"
@@ -1488,6 +1490,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
else
UI_style = "Midnight"
if("nanoui")
nanoui_fancy = !nanoui_fancy
if("UIcolor")
var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!", UI_style_color) as color|null
if(!UI_style_color_new) return
+6 -2
View File
@@ -10,7 +10,8 @@
toggles,
sound,
randomslot,
volume
volume,
nanoui_fancy
FROM [format_table_name("player")]
WHERE ckey='[C.ckey]'"}
)
@@ -34,6 +35,7 @@
sound = text2num(query.item[8])
randomslot = text2num(query.item[9])
volume = text2num(query.item[10])
nanoui_fancy = text2num(query.item[11])
//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
@@ -46,6 +48,7 @@
UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha))
randomslot = sanitize_integer(randomslot, 0, 1, initial(randomslot))
volume = sanitize_integer(volume, 0, 100, initial(volume))
nanoui_fancy = sanitize_integer(nanoui_fancy, 0, 1, initial(nanoui_fancy))
return 1
/datum/preferences/proc/save_preferences(client/C)
@@ -67,7 +70,8 @@
toggles='[toggles]',
sound='[sound]',
randomslot='[randomslot]',
volume='[volume]'
volume='[volume]',
nanoui_fancy='[nanoui_fancy]'
WHERE ckey='[C.ckey]'"}
)
+9 -2
View File
@@ -186,7 +186,15 @@ nanoui is used to open and update nano browser uis
"autoUpdateContent" = auto_update_content,
"showMap" = show_map,
"mapZLevel" = map_z_level,
"user" = list("name" = user.name)
"user" = list(
"name" = user.name,
"fancy" = user.client.prefs.nanoui_fancy
),
"window" = list(
"width" = width,
"height" = height,
"ref" = window_id
)
)
return config_data
@@ -334,7 +342,6 @@ nanoui is used to open and update nano browser uis
/datum/nanoui/proc/get_html()
// before the UI opens, add the layout files based on the layout key
add_stylesheet("layout_[layout_key].css")
add_template("layout", "layout_[layout_key].tmpl")
var/head_content = ""
+24 -6
View File
@@ -5,11 +5,14 @@ s =
# Project Paths
input =
fonts: "**/*.{eot,woff2}"
fonts: "**/*.{eot,woff2}"
images: "images"
layouts: "layouts/"
scripts:
lib: "scripts/libraries"
main: "scripts/nano"
lib: "scripts/libraries"
main: "scripts/nano"
styles: "styles"
templates: "templates/"
output =
dir: "assets"
@@ -20,6 +23,7 @@ output =
### Pacakages ###
bower = require "main-bower-files"
child_process = require "child_process"
del = require "del"
gulp = require "gulp"
merge = require "merge-stream"
@@ -45,12 +49,28 @@ gulp.task "default", ["fonts", "scripts", "styles"]
gulp.task "clean", ->
del glob output.dir
gulp.task "watch", ->
gulp.watch [glob input.images], ["reload"]
gulp.watch [glob input.layouts], ["reload"]
gulp.watch [glob input.scripts.lib], ["reload"]
gulp.watch [glob input.scripts.main], ["reload"]
gulp.watch [glob input.styles], ["reload"]
gulp.watch [glob input.templates], ["reload"]
gulp.task "reload", ["default"], ->
child_process.exec "reload.bat", (err, stdout, stderr) ->
return console.log err if err
gulp.task "fonts", ["clean"], ->
gulp.src bower input.fonts
.pipe gulp.dest output.dir
gulp.task "scripts", ["clean"], ->
lib = gulp.src glob input.scripts.lib
etc = gulp.src bower "**/*.js"
merged = merge lib, etc
.pipe g.order(["jquery.js",
"jquery*.js",
"*.js"])
@@ -66,15 +86,13 @@ gulp.task "scripts", ["clean"], ->
.pipe g.if(s.min, g.uglify().on('error', util.log))
.pipe gulp.dest output.dir
merge lib, main
gulp.task "styles", ["clean"], ->
lib = gulp.src bower "**/*.css"
.pipe g.replace("../fonts/", "")
main = gulp.src glob input.styles
.pipe g.filter(["*.less", "!_*.less"])
.pipe g.less()
.pipe g.less({paths: [input.images]})
.pipe g.postcss([
p.autoprefixer({browsers: ["last 2 versions", "ie >= 8"]}),
p.gradient,
+5 -5
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+7 -1
View File
@@ -3,7 +3,8 @@
"license": "AGPLv3",
"private": true,
"dependencies": {
"font-awesome": "~4.5.0"
"font-awesome": "~4.5.0",
"jsurl": "*"
},
"overrides": {
"font-awesome": {
@@ -11,6 +12,11 @@
"css/font-awesome.css",
"fonts/*"
]
},
"jsurl": {
"dependencies": {
"es5-shim": "*"
}
}
}
}
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 425 200" opacity=".25">
<path d="m 178.00399,0.03869 -71.20393,0 a 6.7613422,6.0255495 0 0 0 -6.76134,6.02555 l 0,187.87147 a 6.7613422,6.0255495 0 0 0 6.76134,6.02554 l 53.1072,0 a 6.7613422,6.0255495 0 0 0 6.76135,-6.02554 l 0,-101.544018 72.21628,104.699398 a 6.7613422,6.0255495 0 0 0 5.76015,2.87016 l 73.55487,0 a 6.7613422,6.0255495 0 0 0 6.76135,-6.02554 l 0,-187.87147 a 6.7613422,6.0255495 0 0 0 -6.76135,-6.02555 l -54.71644,0 a 6.7613422,6.0255495 0 0 0 -6.76133,6.02555 l 0,102.61935 L 183.76413,2.90886 a 6.7613422,6.0255495 0 0 0 -5.76014,-2.87017 z" />
<path d="M 4.8446333,22.10875 A 13.412039,12.501842 0 0 1 13.477588,0.03924 l 66.118315,0 a 5.3648158,5.000737 0 0 1 5.364823,5.00073 l 0,79.87931 z" />
<path d="m 420.15535,177.89119 a 13.412038,12.501842 0 0 1 -8.63295,22.06951 l -66.11832,0 a 5.3648152,5.000737 0 0 1 -5.36482,-5.00074 l 0,-79.87931 z" />
</svg>

After

Width:  |  Height:  |  Size: 1013 B

-126
View File
@@ -1,126 +0,0 @@
body {
background: #272727 url(uiBackground.png) 50% 0 repeat-x;
}
#uiWrapper {
width: 100%;
height: 100%;
-ms-user-select: none;
user-select: none;
}
#uiTitleWrapper {
position: relative;
height: 30px;
}
#uiTitleText {
position: absolute;
top: 6px;
left: 44px;
width: 66%;
overflow: hidden;
color: #E9C183;
font-size: 16px;
}
#uiTitle.icon {
padding: 6px 8px 6px 42px;
background-position: 2px 50%;
background-repeat: no-repeat;
}
#uiTitleFluff {
position: absolute;
top: 4px;
right: 12px;
width: 42px;
height: 24px;
background: url(uiTitleFluff.png) 50% 50% no-repeat;
}
.statusicon {
position: absolute;
top: 4px;
left: 12px;
}
#uiMapWrapper {
clear: both;
padding: 8px;
}
#uiMapHeader {
position: relative;
clear: both;
}
#uiMapContainer {
position: relative;
width: 100%;
height: 600px;
overflow: hidden;
border: 1px solid #40628a;
background: url(nanomapBackground.png);
}
#uiMap {
position: absolute;
top: 50%;
left: 50%;
margin: -512px 0 0 -512px;
width: 256px;
height: 256px;
overflow: hidden;
zoom: 4;
}
#uiMapImage {
position: absolute;
bottom: 1px;
left: 1px;
width: 256px;
height: 256px;
}
#uiMapContent {
position: absolute;
bottom: -13.5px;
left: 0px;
width: 256px;
height: 256px;
}
#uiMapFooter {
position: relative;
clear: both;
}
#uiContent {
clear: both;
padding: 8px;
}
#uiMapTooltip {
position: absolute;
right: 10px;
top: 10px;
border: 1px solid #40628a;
background-color: #272727;
padding: 8px;
display: none;
z-index: 9999;
}
#uiLoadingNotice {
position: relative;
background: url(uiNoticeBackground.jpg) 50% 50%;
color: #000000;
font-size: 14px;
font-style: italic;
font-weight: bold;
padding: 3px 4px 3px 4px;
margin: 4px 0 4px 0;
}
+9 -2
View File
@@ -1,4 +1,10 @@
<div id='uiTitleWrapper' unselectable="on"><i class="statusicon fa fa-eye fa-2x" unselectable="on"></i><div id='uiTitleText' unselectable="on">{{:config.title}}</div><div id='uiTitleFluff' unselectable="on"></div></div>
<div id='uiTitleWrapper'>
<i class="statusicon fa fa-eye fa-2x" unselectable="on"></i>
<div id='uiTitleText' unselectable="on">{{:config.title}}</div>
<div id='uiTitleFluff' unselectable="on"></div>
<i class='minimize fancy fa fa-minus fa-2x' unselectable='on'></i>
&nbsp;&nbsp;<i class='close fancy fa fa-close fa-2x' unselectable='on'></i>
</div>
<div id='uiMapWrapper' class="hidden" unselectable="on">
<div id='uiMapHeader' unselectable="on">
{{:helper.link('Hide Map', 'close', {'showMap' : 0})}}
@@ -27,4 +33,5 @@
</div>
<div id='uiContent' unselectable="on">
<div id='uiLoadingNotice'>Initiating...</div>
</div>
</div>
<div id='resize' class='resize fancy' unselectable='on'></div>
+2
View File
@@ -7,3 +7,5 @@ for /f "tokens=3* delims= " %%a in (
)
copy assets\* "%documents%\BYOND\cache" /y
copy templates\* "%documents%\BYOND\cache" /y
copy layouts\* "%documents%\BYOND\cache" /y
+4
View File
@@ -216,6 +216,10 @@ NanoStateManager = function ()
getCurrentState: function ()
{
return _currentState;
},
getData: function ()
{
return _data;
}
};
} ();
+45
View File
@@ -30,6 +30,50 @@ var NanoUtility = function () {
}
}
return queryString;
},
winset: function (key, value, window) {
var obj, params, winsetRef;
if (window == null) {
window = NanoStateManager.getData().config.window.ref;
}
params = (
obj = {},
obj[window + "." + key] = value,
obj
);
return location.href = NanoUtility.href("winset", params);
},
extend: function(first, second) {
Object.keys(second).forEach(function(key) {
var secondVal;
secondVal = second[key];
if (secondVal && Object.prototype.toString.call(secondVal) === "[object Object]") {
first[key] = first[key] || {};
return util.extend(first[key], secondVal);
} else {
return first[key] = secondVal;
}
});
return first;
},
href: function(url, params) {
if (url == null) {
url = "";
}
if (params == null) {
params = {};
}
url = new Url("byond://" + url);
NanoUtility.extend(url.query, params);
return url;
},
close: function() {
var params;
params = {
command: "nanoclose " + _urlParameters.src
};
this.winset("is-visible", "false");
return location.href = util.href("winset", params);
}
}
} ();
@@ -51,6 +95,7 @@ $(document).ready(function () {
NanoUtility.init();
NanoStateManager.init();
NanoTemplate.init();
NanoWindow.init();
});
if (!Array.prototype.indexOf)
+120
View File
@@ -0,0 +1,120 @@
var NanoWindow = function ()
{
var setPos = function (x, y) {
NanoUtility.winset("pos", x + "," + y);
};
var setSize = function (w, h) {
NanoUtility.winset("size", w + "," + h);
};
var init = function () {
if(NanoStateManager.getData().config.user.fancy) {
fancyChrome();
attachButtons();
attachDrag();
attachResize();
}
};
var fancyChrome = function() {
NanoUtility.winset("titlebar", 0);
NanoUtility.winset("can-resize", 0);
$('.fancy').show();
$('#uiTitleFluff').css("right", "65px");
};
var attachButtons = function() {
var close = function() {
return NanoUtility.close();
};
var minimize = function() {
return NanoUtility.winset("is-minimized", "true");
};
$(".close").on("click", function (event) {
close();
});
$(".minimize").on("click", function (event) {
minimize();
});
};
var dragging, xDrag, yDrag;
var attachDrag = function() {
$("#uiTitleWrapper").on("mousemove", function (event) {
drag();
});
$("#uiTitleWrapper").on("mousedown", function (event) {
dragging = true;
});
$("#uiTitleWrapper").on("mouseup", function (event) {
dragging = false;
xDrag = null;
yDrag = null;
});
};
var drag = function(event) {
var x, y;
if (event == null) {
event = window.event;
}
if (!dragging) {
return;
}
if (xDrag == null) {
xDrag = event.screenX;
}
if (yDrag == null) {
yDrag = event.screenY;
}
x = (event.screenX - xDrag) + (window.screenLeft);
y = (event.screenY - yDrag) + (window.screenTop);
setPos(x, y);
xDrag = event.screenX;
yDrag = event.screenY;
};
var resizing, xResize, yResize;
var attachResize = function () {
$("#resize").on("mousemove", function (event) {
resize();
});
$("#resize").on("mousedown", function (event) {
resizing = true;
});
$("#resize").on("mouseup", function (event) {
resizing = false;
});
};
var resize = function() {
var x, y;
if (event == null) {
event = window.event;
}
if (!resizing) {
return;
}
if (xResize == null) {
xResize = event.screenX;
}
if (yResize == null) {
yResize = event.screenY;
}
x = Math.max(150, (event.screenX - xResize) + window.innerWidth);
y = Math.max(150, (event.screenY - yResize) + window.innerHeight);
setSize(x, y);
xResize = event.screenX;
yResize = event.screenY;
};
return {
init: function () { //crazy but ensures correct load order (nanoutil - nanotemplate - nanowindow)
$(document).on('templatesLoaded', function () {
init();
});
}
};
}();
+7
View File
@@ -0,0 +1,7 @@
// Fonts
@font: Verdana, Geneva, sans-serif;
@fontsize: 12px;
// Body Colors
@background-start: #2a2a2a;
@background-end: #202020;
+43 -3
View File
@@ -127,7 +127,7 @@
.statusDisplay {
background: #000000;
background: rgba(0, 0, 0, 0.5);
color: #ffffff;
border: 1px solid #40628a;
padding: 4px;
@@ -136,7 +136,7 @@
}
.statusDisplayRecords {
background: #000000;
background: rgba(0, 0, 0, 0.5);
color: #ffffff;
border: 1px solid #40628a;
padding: 4px;
@@ -154,4 +154,44 @@
.statusValue {
float: left;
}
}
// CHROMELESS STUFF
.fancy {
display: none;
}
.titlebutton() {
color: #E9C183;
&:hover {
color: lighten(#98b0c3, 10%);
}
}
.minimize {
.titlebutton;
position: absolute;
top: 6px;
right: 46px;
}
.close {
.titlebutton;
position: absolute;
top: 4px;
right: 12px;
}
div.resize {
position: fixed;
bottom: 0;
right: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 0 0 30px 30px;
border-color: transparent transparent #363636 transparent;
transform: rotate(360deg);
}
+9 -6
View File
@@ -1,16 +1,19 @@
@import "_config";
body {
padding: 0;
margin: 0;
font-size: 12px;
color: #ffffff;
line-height: 170%;
font-family: Verdana, Geneva, sans-serif;
background: #272727;
color: #ffffff;
font-family: @font;
font-size: @fontsize;
line-height: 170%;
margin: 0;
padding: 0;
}
hr {
background-color: #40628a;
height: 1px;
border: none;
}
img, a img {
+137 -7
View File
@@ -1,10 +1,140 @@
@charset "utf-8";
@import "_native";
@import "_icon";
@import "_lists";
@import "_formatting";
@import "_link";
@import "_color";
@import "_bars";
@import "_misc";
@import "_color";
@import "_config";
@import "_formatting";
@import "_icon";
@import "_link";
@import "_lists";
@import "_misc";
@import "_native";
body {
background: data-uri('nanotrasen.svg') no-repeat fixed center/70% 70%,
linear-gradient(to bottom,
@background-start 0%,
@background-end 100%) no-repeat fixed center/100% 100%;
}
#uiWrapper {
width: 100%;
height: 100%;
-ms-user-select: none;
user-select: none;
}
#uiTitleWrapper {
position: relative;
height: 30px;
}
#uiTitleText {
position: absolute;
top: 6px;
left: 44px;
width: 66%;
overflow: hidden;
color: #E9C183;
font-size: 16px;
}
#uiTitle.icon {
padding: 6px 8px 6px 42px;
background-position: 2px 50%;
background-repeat: no-repeat;
}
#uiTitleFluff {
position: absolute;
top: 4px;
right: 12px;
width: 42px;
height: 24px;
background: data-uri('nanotrasen.svg') 50% 50% no-repeat;
}
.statusicon {
position: absolute;
top: 4px;
left: 12px;
}
#uiMapWrapper {
clear: both;
padding: 8px;
}
#uiMapHeader {
position: relative;
clear: both;
}
#uiMapContainer {
position: relative;
width: 100%;
height: 600px;
overflow: hidden;
border: 1px solid #40628a;
background: url(nanomapBackground.png);
}
#uiMap {
position: absolute;
top: 50%;
left: 50%;
margin: -512px 0 0 -512px;
width: 256px;
height: 256px;
overflow: hidden;
zoom: 4;
}
#uiMapImage {
position: absolute;
bottom: 1px;
left: 1px;
width: 256px;
height: 256px;
}
#uiMapContent {
position: absolute;
bottom: -13.5px;
left: 0px;
width: 256px;
height: 256px;
}
#uiMapFooter {
position: relative;
clear: both;
}
#uiContent {
clear: both;
padding: 8px;
}
#uiMapTooltip {
position: absolute;
right: 10px;
top: 10px;
border: 1px solid #40628a;
background-color: #272727;
padding: 8px;
display: none;
z-index: 9999;
}
#uiLoadingNotice {
position: relative;
background: url(uiNoticeBackground.jpg) 50% 50%;
color: #000000;
font-size: 14px;
font-style: italic;
font-weight: bold;
padding: 3px 4px 3px 4px;
margin: 4px 0 4px 0;
}
+5 -5
View File
@@ -9,7 +9,7 @@
<div class="line">Cell Unoccupied</div>
{{else}}
<div class="line">
{{:data.occupant.name}}&nbsp;=>&nbsp;
{{:data.occupant.name}}&nbsp;<i class="fa fa-arrow-right"></i>&nbsp;
{{if data.occupant.stat == 0}}
<span class="good">Conscious</span>
{{else data.occupant.stat == 1}}
@@ -31,25 +31,25 @@
</div>
<div class="line">
<div class="statusLabel">=&gt; Brute Damage:</div>
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Brute Damage:</div>
{{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad')}}
<div class="statusValue">{{:helper.round(data.occupant.bruteLoss)}}</div>
</div>
<div class="line">
<div class="statusLabel">=&gt; Resp. Damage:</div>
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Resp. Damage:</div>
{{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad')}}
<div class="statusValue">{{:helper.round(data.occupant.oxyLoss)}}</div>
</div>
<div class="line">
<div class="statusLabel">=&gt; Toxin Damage:</div>
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Toxin Damage:</div>
{{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad')}}
<div class="statusValue">{{:helper.round(data.occupant.toxLoss)}}</div>
</div>
<div class="line">
<div class="statusLabel">=&gt; Burn Severity:</div>
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Burn Severity:</div>
{{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad')}}
<div class="statusValue">{{:helper.round(data.occupant.fireLoss)}}</div>
</div>