cjerzak commited on
Commit
b74a0a8
·
verified ·
1 Parent(s): 377339a

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +134 -187
app.R CHANGED
@@ -16,230 +16,183 @@ library(leaflet) # <-- For OpenStreetMap-based map
16
  # =============================
17
  ui <- dashboardPage(
18
  skin = "black",
 
 
 
 
19
  dashboardHeader(
20
  title = span(
21
  style = "font-weight: 600; font-size: 13px;",
22
  a(
23
- href = "http://www.globalleadershipproject.net",
24
- "GlobalLeadershipProject.net",
25
  target = "_blank",
26
- style = "color: white; text-decoration: underline;"
27
  )
28
  )
29
  ),
 
 
 
 
30
  dashboardSidebar(
31
  sidebarMenu(
32
  menuItem("Map Type", tabName = "cartogramTab", icon = icon("globe"))
33
  ),
 
34
  div(
35
  style = "margin: 15px;",
36
  selectInput(
37
- inputId = "indexChoice",
38
- label = "Select Representation Index:",
39
- choices = c("Overall", "RepresentationGap", "Ethnicity",
40
- "Gender", "Religion", "Language"),
41
  selected = "Overall"
42
  )
43
  ),
44
 
45
- # ---- Minimal "Share" button HTML + JS inlined ----
46
  tags$div(
47
  style = "text-align: left; margin: 1em 0 1em 2em;",
48
  HTML('
49
- <button id="share-button"
50
  style="
51
- display: inline-flex;
52
- align-items: center;
53
- justify-content: center;
54
- gap: 8px;
55
- padding: 5px 10px;
56
- font-size: 16px;
57
- font-weight: normal;
58
- color: #000;
59
- background-color: #fff;
60
- border: 1px solid #ddd;
61
- border-radius: 6px;
62
- cursor: pointer;
63
- box-shadow: 0 1.5px 0 #000;
64
- ">
65
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"
66
- stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
67
- <circle cx="18" cy="5" r="3"></circle>
68
- <circle cx="6" cy="12" r="3"></circle>
69
  <circle cx="18" cy="19" r="3"></circle>
70
- <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
71
- <line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
72
  </svg>
73
  <strong>Share</strong>
74
  </button>
75
  '),
76
- tags$script(
77
- HTML("
78
- (function() {
79
- const shareBtn = document.getElementById('share-button');
80
- // Reusable helper function to show a small “Copied!” message
81
- function showCopyNotification() {
82
- const notification = document.createElement('div');
83
- notification.innerText = 'Copied to clipboard';
84
- notification.style.position = 'fixed';
85
- notification.style.bottom = '20px';
86
- notification.style.right = '20px';
87
- notification.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
88
- notification.style.color = '#fff';
89
- notification.style.padding = '8px 12px';
90
- notification.style.borderRadius = '4px';
91
- notification.style.zIndex = '9999';
92
- document.body.appendChild(notification);
93
- setTimeout(() => { notification.remove(); }, 2000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  }
95
- shareBtn.addEventListener('click', function() {
96
- const currentURL = window.location.href;
97
- const pageTitle = document.title || 'Check this out!';
98
- // If browser supports Web Share API
99
- if (navigator.share) {
100
- navigator.share({
101
- title: pageTitle,
102
- text: '',
103
- url: currentURL
104
- })
105
- .catch((error) => {
106
- console.log('Sharing failed', error);
107
- });
108
- } else {
109
- // Fallback: Copy URL
110
- if (navigator.clipboard && navigator.clipboard.writeText) {
111
- navigator.clipboard.writeText(currentURL).then(() => {
112
- showCopyNotification();
113
- }, (err) => {
114
- console.error('Could not copy text: ', err);
115
- });
116
- } else {
117
- // Double fallback for older browsers
118
- const textArea = document.createElement('textarea');
119
- textArea.value = currentURL;
120
- document.body.appendChild(textArea);
121
- textArea.select();
122
- try {
123
- document.execCommand('copy');
124
- showCopyNotification();
125
- } catch (err) {
126
- alert('Please copy this link:\\n' + currentURL);
127
- }
128
- document.body.removeChild(textArea);
129
- }
130
- }
131
- });
132
- })();
133
- ")
134
- )
135
  )
136
- # ---- End: Minimal Share button snippet ----
137
  ),
 
 
 
 
138
  dashboardBody(
139
  tags$head(
140
  tags$link(
141
  href = "https://fonts.googleapis.com/css2?family=OCR+A+Extended&display=swap",
142
- rel = "stylesheet"
143
  ),
144
  tags$style(HTML("
145
- /* Force OCR A Extended font across the entire UI and all HTML elements */
146
- html, body, h1, h2, h3, h4, h5, h6, p, div, span, label, input, button, select,
147
- .box, .content-wrapper, .main-sidebar, .main-header .navbar, .main-header .logo,
148
- .sidebar-menu, .sidebar-menu li a, .sidebar-menu .fa {
149
  font-family: 'OCR A Extended', monospace !important;
150
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
- /* Header gradient background */
153
- .main-header .navbar {
154
- background: linear-gradient(to right, #3b6978, #204051) !important;
155
- }
156
- /* Logo area (left corner of the header) */
157
- .main-header .logo {
158
- background: #1b2a2f !important;
159
- color: #ffffff !important;
160
- border-bottom: none;
161
- font-size: 18px;
162
- font-weight: 600;
163
- }
164
- /* Sidebar background */
165
- .main-sidebar {
166
- background-color: #1b2a2f !important;
167
- }
168
- /* Active or hovered tab in the sidebar */
169
- .sidebar-menu > li.active > a,
170
- .sidebar-menu > li:hover > a {
171
- background-color: #344e5c !important;
172
- border-left-color: #78cdd7 !important;
173
- color: #ffffff !important;
174
- }
175
-
176
- /* Sidebar menu item icons */
177
- .sidebar-menu .fa {
178
- color: #78cdd7 !important;
179
- }
180
-
181
- /* Sidebar menu item text */
182
- .sidebar-menu > li > a {
183
- color: #b8c7ce !important;
184
- font-size: 15px;
185
- font-weight: 500;
186
- }
187
-
188
- /* Customize the boxes */
189
- .box {
190
- border-top: none !important;
191
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
192
- border-radius: 6px;
193
- }
194
- .box.box-solid > .box-header {
195
- background-color: #204051;
196
- color: #fff;
197
- border-radius: 6px 6px 0 0;
198
- }
199
- /* Plot box spacing */
200
- .box .box-body {
201
- padding: 0 !important;
202
- }
203
- /* Footer text styling (plot captions, etc.) */
204
- .small, small {
205
- font-size: 75%;
206
- }
207
- /* Responsive map container */
208
- .map-container {
209
- height: 70vh;
210
- width: 100%;
211
- }
212
- @media (max-width: 768px) {
213
- .map-container {
214
- height: 50vh;
215
- }
216
  }
217
  "))
218
  ),
 
219
  tabItem(
220
  tabName = "cartogramTab",
 
221
  fluidRow(
222
  column(
223
  width = 9,
224
  box(
225
- width = NULL,
226
- title = strong("Country-level Representation"),
227
  solidHeader = TRUE,
228
- div(
229
- class = "map-container",
230
- leafletOutput("cartogramPlot", width = "100%", height = "100%")
231
- )
232
  )
233
  ),
234
-
235
  column(
236
  width = 3,
237
  box(
238
- width = NULL,
239
- title = strong("Selected Country Data"),
240
  solidHeader = TRUE,
241
  uiOutput("selectedCountryData"),
242
- style = "overflow-y: auto;" # Scroll if content overflows
243
  )
244
  )
245
  ),
@@ -248,30 +201,24 @@ ui <- dashboardPage(
248
  column(
249
  width = 9,
250
  box(
251
- width = NULL,
252
- title = strong("Citation"),
253
  solidHeader = TRUE,
254
-
255
  tags$p(
256
- "John Gerring, Connor T. Jerzak, Erzen Öncel.
257
- The Composition of Descriptive Representation. ",
258
- em("American Political Science Review,"), " 118(2): 784–801, 2024.",
259
  tags$a(
260
- href = "https://www.cambridge.org/core/services/aop-cambridge-core/content/view/7EAEA1CA4C553AB9D76054D1FA9C0840/S0003055423000680a.pdf/the-composition-of-descriptive-representation.pdf",
261
- "PDF",
262
- target = "_blank"
263
- ),
264
- " | ",
265
  tags$a(
266
- href = "https://connorjerzak.com/wp-content/uploads/2024/07/CompositionBib.txt",
267
- "BibTeX",
268
- target = "_blank"
269
- ),
270
- " | ",
271
  tags$a(
272
- href = "https://www.youtube.com/watch?v=nnfDj1NdOMo",
273
- "YouTube",
274
- target = "_blank"
275
  )
276
  )
277
  )
@@ -281,6 +228,7 @@ ui <- dashboardPage(
281
  )
282
  )
283
 
 
284
  # =============================
285
  # SERVER
286
  # =============================
@@ -453,4 +401,3 @@ server <- function(input, output, session) {
453
  # Launch the Shiny App
454
  # =============================
455
  shinyApp(ui = ui, server = server)
456
-
 
16
  # =============================
17
  ui <- dashboardPage(
18
  skin = "black",
19
+
20
+ # =======================
21
+ # HEADER
22
+ # =======================
23
  dashboardHeader(
24
  title = span(
25
  style = "font-weight: 600; font-size: 13px;",
26
  a(
27
+ href = "http://www.globalleadershipproject.net",
28
+ "GlobalLeadershipProject.net",
29
  target = "_blank",
30
+ style = "color: white; text-decoration: underline;"
31
  )
32
  )
33
  ),
34
+
35
+ # =======================
36
+ # SIDEBAR
37
+ # =======================
38
  dashboardSidebar(
39
  sidebarMenu(
40
  menuItem("Map Type", tabName = "cartogramTab", icon = icon("globe"))
41
  ),
42
+
43
  div(
44
  style = "margin: 15px;",
45
  selectInput(
46
+ inputId = "indexChoice",
47
+ label = "Select Representation Index:",
48
+ choices = c("Overall", "RepresentationGap", "Ethnicity",
49
+ "Gender", "Religion", "Language"),
50
  selected = "Overall"
51
  )
52
  ),
53
 
54
+ # ---- Share button ----
55
  tags$div(
56
  style = "text-align: left; margin: 1em 0 1em 2em;",
57
  HTML('
58
+ <button id="share-button"
59
  style="
60
+ display:inline-flex;
61
+ align-items:center;
62
+ justify-content:center;
63
+ gap:8px;
64
+ padding:5px 10px;
65
+ font-size:16px;
66
+ font-weight:normal;
67
+ color:#000;
68
+ background-color:#fff;
69
+ border:1px solid #ddd;
70
+ border-radius:6px;
71
+ cursor:pointer;
72
+ box-shadow:0 1.5px 0 #000;">
73
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none"
74
+ stroke="currentColor" stroke-width="2"
75
+ stroke-linecap="round" stroke-linejoin="round">
76
+ <circle cx="18" cy="5" r="3"></circle>
77
+ <circle cx="6" cy="12" r="3"></circle>
78
  <circle cx="18" cy="19" r="3"></circle>
79
+ <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
80
+ <line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
81
  </svg>
82
  <strong>Share</strong>
83
  </button>
84
  '),
85
+
86
+ tags$script(HTML("
87
+ (function () {
88
+ const shareBtn = document.getElementById('share-button');
89
+ function showCopyNotification () {
90
+ const n = document.createElement('div');
91
+ n.innerText = 'Copied to clipboard';
92
+ n.style.position = 'fixed';
93
+ n.style.bottom = '20px';
94
+ n.style.right = '20px';
95
+ n.style.background = 'rgba(0,0,0,0.8)';
96
+ n.style.color = '#fff';
97
+ n.style.padding = '8px 12px';
98
+ n.style.borderRadius = '4px';
99
+ n.style.zIndex = '9999';
100
+ document.body.appendChild(n);
101
+ setTimeout(() => n.remove(), 2000);
102
+ }
103
+ shareBtn.addEventListener('click', () => {
104
+ const url = window.location.href;
105
+ const title = document.title || 'Check this out!';
106
+ if (navigator.share) {
107
+ navigator.share({ title, text: '', url }).catch(console.log);
108
+ } else if (navigator.clipboard && navigator.clipboard.writeText) {
109
+ navigator.clipboard.writeText(url).then(showCopyNotification);
110
+ } else {
111
+ const ta = document.createElement('textarea');
112
+ ta.value = url;
113
+ document.body.appendChild(ta);
114
+ ta.select();
115
+ try { document.execCommand('copy'); showCopyNotification(); }
116
+ catch { alert('Please copy this link:\\n' + url); }
117
+ document.body.removeChild(ta);
118
  }
119
+ });
120
+ })();
121
+ "))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  )
123
+ # ---- /Share button ----
124
  ),
125
+
126
+ # =======================
127
+ # BODY
128
+ # =======================
129
  dashboardBody(
130
  tags$head(
131
  tags$link(
132
  href = "https://fonts.googleapis.com/css2?family=OCR+A+Extended&display=swap",
133
+ rel = "stylesheet"
134
  ),
135
  tags$style(HTML("
136
+ /* -------- Base typography & theme -------- */
137
+ html, body, h1, h2, h3, h4, h5, h6, p, div, span, label, input, button,
138
+ select, .box, .content-wrapper, .main-sidebar, .main-header .navbar,
139
+ .main-header .logo, .sidebar-menu, .sidebar-menu li a, .sidebar-menu .fa {
140
  font-family: 'OCR A Extended', monospace !important;
141
  }
142
+ .main-header .navbar { background: linear-gradient(to right,#3b6978,#204051)!important; }
143
+ .main-header .logo { background:#1b2a2f!important; color:#fff!important;
144
+ border-bottom:none; font-size:18px; font-weight:600; }
145
+ .main-sidebar { background-color:#1b2a2f!important; }
146
+ .sidebar-menu>li.active>a,
147
+ .sidebar-menu>li:hover>a { background:#344e5c!important; border-left-color:#78cdd7!important;
148
+ color:#fff!important; }
149
+ .sidebar-menu .fa { color:#78cdd7!important; }
150
+ .sidebar-menu>li>a { color:#b8c7ce!important; font-size:15px; font-weight:500; }
151
+ .box { border-top:none!important; box-shadow:0 4px 8px rgba(0,0,0,.1);
152
+ border-radius:6px; }
153
+ .box.box-solid>.box-header{ background:#204051; color:#fff; border-radius:6px 6px 0 0; }
154
+ .box .box-body { padding:0!important; }
155
+ .small, small { font-size:75%; }
156
+ .map-container { height:70vh; width:100%; }
157
+ @media (max-width:768px) { .map-container{height:50vh;} }
158
 
159
+ /* -------- Mobile font bump -------- */
160
+ @media (max-width:768px){
161
+ html, body { font-size:18px!important; line-height:1.4!important; }
162
+ .sidebar-menu>li>a { font-size:18px!important; }
163
+ .sidebar-menu .fa { font-size:20px!important; }
164
+ .main-header .logo { font-size:22px!important; }
165
+ .box.box-solid>.box-header,
166
+ .box>.box-header>.box-title { font-size:20px!important; }
167
+ input, select, button { font-size:18px!important; }
168
+ .leaflet-popup-content,
169
+ .leaflet-tooltip { font-size:16px!important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  }
171
  "))
172
  ),
173
+
174
  tabItem(
175
  tabName = "cartogramTab",
176
+
177
  fluidRow(
178
  column(
179
  width = 9,
180
  box(
181
+ width = NULL,
182
+ title = strong("Country-level Representation"),
183
  solidHeader = TRUE,
184
+ div(class = "map-container",
185
+ leafletOutput("cartogramPlot", width = "100%", height = "100%"))
 
 
186
  )
187
  ),
 
188
  column(
189
  width = 3,
190
  box(
191
+ width = NULL,
192
+ title = strong("Selected Country Data"),
193
  solidHeader = TRUE,
194
  uiOutput("selectedCountryData"),
195
+ style = "overflow-y: auto;"
196
  )
197
  )
198
  ),
 
201
  column(
202
  width = 9,
203
  box(
204
+ width = NULL,
205
+ title = strong("Citation"),
206
  solidHeader = TRUE,
 
207
  tags$p(
208
+ "John Gerring, Connor T. Jerzak, Erzen Öncel. ",
209
+ "The Composition of Descriptive Representation. ",
210
+ em("American Political Science Review,"), " 118(2): 784–801, 2024. ",
211
  tags$a(
212
+ href = "https://www.cambridge.org/core/services/aop-cambridge-core/content/view/7EAEA1CA4C553AB9D76054D1FA9C0840/S0003055423000680a.pdf/the-composition-of-descriptive-representation.pdf",
213
+ "PDF", target = "_blank"
214
+ ), " | ",
 
 
215
  tags$a(
216
+ href = "https://connorjerzak.com/wp-content/uploads/2024/07/CompositionBib.txt",
217
+ "BibTeX", target = "_blank"
218
+ ), " | ",
 
 
219
  tags$a(
220
+ href = "https://www.youtube.com/watch?v=nnfDj1NdOMo",
221
+ "YouTube", target = "_blank"
 
222
  )
223
  )
224
  )
 
228
  )
229
  )
230
 
231
+
232
  # =============================
233
  # SERVER
234
  # =============================
 
401
  # Launch the Shiny App
402
  # =============================
403
  shinyApp(ui = ui, server = server)