[Question]
  [
You know those stackable shelves that are basically just [wooden boxes](http://bangsboutique.com.au/mock/wp-content/uploads/bangs-shelves-storage-cube-01.jpg) that can be stacked together? We're going to simulate building some bookshelves out of those with some ASCII art.
Our books are all *conveniently* uniform in size, and all look like the following:
```
|X|
|X|
|X|
```
The bookshelves are individual boxes, always three characters high on the inside (enough to fit a book standing upright), composed of `|` characters on the left and right, `-` characters for the top and bottom, and wide enough to fit `X` books (where `X` is an input integer). For example, here's a bookshelf of size `3`:
```
|---------|
|         |
|         |
|         |
|---------|
```
because you can fit `3` books into it like so
```
|---------|
||X||X||X||
||X||X||X||
||X||X||X||
|---------|
```
The input is going to be two strictly positive integers, `X` and `Y`, where `X` is the width of the shelves we have (measured in books), and `Y` is how many books we have to stack. If we have more books than fit on a single shelf, we need to add more shelves to the top. For example, here is input `4 wide / 6 books`:
```
|------------|
||X||X|      |
||X||X|      |
||X||X|      |
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
```
If `Y % X > 0`, meaning the number of books is not an integer multiple of the shelf size, the remainder books should go on the top-most left-most position (as in the case with `4 6`, above) and the remaining part of that shelf filled in with spaces.
### Input
* Two strictly positive integers [in any convenient format](http://meta.codegolf.stackexchange.com/q/2447/42963), each `>0`.
* You can take the input in either order (e.g., size of shelves first, then number of books, or vice versa). Please state in your submission the input order.
* You can safely assume that neither input will be larger than your language's default `[int]` size (or equivalent).
### Output
The resulting ASCII art representation of the books and bookshelves.
### Rules
* Leading or trailing newlines or whitespace are all optional, so long as the characters themselves line up correctly.
* Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
* If possible, please include a link to an online testing environment so other people can try out your code!
* [Standard loopholes](http://meta.codegolf.stackexchange.com/q/1061/42963) are forbidden.
* This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'") so all usual golfing rules apply, and the shortest code (in bytes) wins.
### Further Examples
```
6 wide / 2 books
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|
2 wide / 6 books
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
4 wide / 9 books
|------------|
||X|         |
||X|         |
||X|         |
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
```
  
[Answer]
## JavaScript (ES6), ~~100~~ ~~99~~ 98 bytes
Takes the width `w` and the number of books `b` in currying syntax `(w)(b)`.
```
w=>g=(b,s=`|${'-'.repeat(w*3)}|
`,r=s.replace(/---/g,_=>b&&b--?'|X|':'   '))=>(b?g(b)+s:s)+r+r+r+s
```
### Formatted and commented
```
w =>                                // main function: takes width 'w' as input, returns 'g'
  g = (                             // g = recursive function with:
    b,                              //   - b = number of books
    s = `|${'-'.repeat(w * 3)}|\n`, //   - s = top/bottom of shell, filled with '-'
    r = s.replace(                  //   - r = pattern of the current row of books,
      RegExp('---', 'g'),           //         using 's' as a template and updating
      _ => b && b-- ? '|X|' : '   ' //         'b' while building it
    )                               // NB: 'r' must be defined in the scope of 'g',
  ) =>                              //     otherwise it would be overwritten by
    (                               //     subsequent calls
      b ?                           // if there are remaining books:
        g(b) + s                    //   do a recursive call and append shell top
      :                             // else:
        s                           //   just append shell top
    ) + r + r + r + s               // append book rows and shell bottom
```
### Test cases
```
let f =
w=>g=(b,s=`|${'-'.repeat(w*3)}|
`,r=s.replace(/---/g,_=>b&&b--?'|X|':'   '))=>(b?g(b)+s:s)+r+r+r+s
console.log(f(6)(2))
console.log(f(2)(6))
console.log(f(4)(9))
```
[Answer]
# Bash (+utilities), ~~130~~, ~~108~~, 106 bytes
A single, continuous, shell pipeline to render your bookshelves.
Changelog:
* Optimized first sed expression a bit, -12 bytes (Thx @Riley !)
* Replaced `printf + seq` with a raw `printf`, -10 bytes
* Refactored the second sed expression, -2 bytes
**Golfed**
```
printf %$2s\\n|fold -$1|sed "s/ /|X|/g;:;/.\{$[$1*3]\}/!s/$/ /;t;h;s/./-/gp;x;p;p;p;x"|sed 's/.*/|&|/'|tac
```
---
```
$./shelf 6 8
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|
|------------------|
||X||X||X||X||X||X||
||X||X||X||X||X||X||
||X||X||X||X||X||X||
|------------------|
```
[Try It Online !](https://tio.run/nexus/bash#HcvLCsIwEEbhV4lltFBIf6pudF5EMC5KehMkDU4WBcfHdh1LOcuPk@P7GdJg9nQU54IO86szlhqVvjOFwEBvipGvjNp96E5NdXq4L3YCWpETTyyoYTFGXjhuLcW2lytU0IOi1NT6nPM5X35htr71U/8H)
**How It Works**
`$./shelf 2 3`
`printf %$2s\\n` - generate n whitespace characters, one per book (shown as `_`)
`___`
`fold -$1` - fold them by the shelf length
```
__
_
```
`sed "s/ /|X|/g;"` - replace `_` with `X`, add book covers
```
|X||X|
|X|
```
`:;/.\{$[$1*3]\}/!s/$/ /;t` - right pad with spaces (shown as `_`)
```
|X||X|
|X|___
```
`h;s/./-/gp;x;p;p;p;x` - triplicate each line, and add `---` before and after it.
```
------
|X||X|
|X||X|
|X||X|
------
------
|X|   
|X|   
|X|   
------
```
`sed 's/.*/|&|/'|tac` - wrap lines in `| |`, reverse with tac
```
|------|
||X|   |
||X|   |
||X|   |
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
```
[Answer]
# Python 2, ~~133~~ ~~113~~ 105 bytes
I'm sure there's a better way...
```
X,Y=input()
k='|'+'---'*X+'|'
while Y:g=Y%X or X;print k+'\n'+('|'+'|X|'*g+'   '*(X-g)+'|'+'\n')*3+k;Y-=g
```
Input is taken `width, books`
-20 bytes thanks to @ovs for noticing an unnecessary lambda function!  
-8 bytes thanks to @ovs for shortening the input. 
[Answer]
## Batch, 261 bytes
```
@set/an=~-%1%%%2+1,b=%1-n
@set s=
@set t=
@for /l %%i in (1,1,%2)do @call set t=---%%t%%&if %%i gtr %n% (call set s=%%s%%   )else call set s=%%s%%X
@for %%s in ("|%t%|" "|%s:X=|X|%|" "|%s:X=|X|%|" "|%s:X=|X|%|" "|%t%|")do @echo %%~s
@if %b% gtr 0 %0 %b% %2
```
Uses my trick from my Batch answer to [Let's play tennis](https://codegolf.stackexchange.com/questions/103605) to easily print lots of `|` characters.
[Answer]
# [Haskell](https://www.haskell.org/), 100 bytes
`x#y` returns the string for width `x` and `y` books.
```
s?n=[1..n]>>s
x#y|x<y=x#(y-x)++x#x|w<-"---"?x,b<-"|X|"?y++"   "?(x-y)=[w,b,b,b,w]>>=('|':).(++"|\n")
```
[Try it online!](https://tio.run/nexus/haskell#NYyxCsIwFAD3fsXjRWhimoIgDpKX/ICbi1AdWnRwMEhbyQvk32MQ5JYbjnuNzwAE7896Xmcga0EKBXbjYH6M91MAu/1rWXygYdf34ebc0rBImW0iFjIZVlqz4BytQWMMeu6mqvmS0SetEQDQSzZJ0RC76UesG5Jtbo@ql7XJ14CqlH1z@AI "Haskell – TIO Nexus")
The main function/operator is `#`. When `x<y` it splits the books into `y-x` and `x`, then recurses. When `x>=y`, `w` and `b` are the two line types, minus the outer `|`s and the newline.
The helper operator `s?n` concatenates `n` copies of the string `s`.
[Answer]
# [PowerShell](https://github.com/TryItOnline/TioSetup/wiki/Powershell), ~~149~~ 134 bytes
```
param($w,$b)$s="|$('-'*$w*3)|"
if($a=$b%$w){,$s+,"|$('|X|'*$a)$(' '*3*($w-$a))|"*3+$s}
if($b-=$a){(,$s+,"|$('|X|'*$w)|"*3+$s)*($b/$w)}
```
[Try it online!](https://tio.run/nexus/powershell#XYyxCoQwEET7@wqRkWTXhOMIx1X5D9ukECwEuRQpjN@@LoKN3czw3siW/mm1qA6ZUGLfYI03jMqBWv9aZosUkQdU2h3K6C6iTU2ZRBo7w4H1wGtVg8OIclxe9lG33T61emOkXn5rP0TkK5/fCQ "PowerShell – TIO Nexus")
Takes input `$w`idth and `$b`ooks. Sets string `$s` to be one of the horizontal shelves. Then we have two `if` statements.
The first checks whether we have "remainder" books. If so, we output the shelf, the (number of books plus number of spaces)`*3`, and another shelf.
Next, we see if we still have books remaining after removing the remainders (`$a`). Same sort of setup, except we're using `$w` number of books. Since at this point, `$b` is guaranteed to be a multiple of `$w` (because we removed the remainder, `$a`), we don't need to worry about rounding.
*Removed the `[math]::Floor()` call, saving 15 bytes*
All of these strings are left on the pipeline, and implicit `Write-Output` happens at program completion.
[Answer]
# [CJam](https://sourceforge.net/p/cjam), ~~62~~ 61 bytes
```
q~1a*W$/W$f{0e]}{{"|X|"S3*?}%s__'-3*W$*_}%1m>W%"|
|"*"||"\*o;
```
Takes input as `width books`
[Try it online!](https://tio.run/nexus/cjam#@19YZ5ioFa6iH66SVm2QGltbXa1UE1GjFGysZV@rWhwfr65rDJTWiq9VNcy1C1dVquGqUdJSqqlRitHKt/7/30TBEgA "CJam – TIO Nexus")
**Explanation**
```
q~           Read and eval input (pushes width W and books B to the stack)
1a*          Push an array containing  the number 1 B times
W$/          Split it into chunks of size W
W$f{0e]}     Pad each chunk to width W by adding 0's to the right (the last chunk might be 
              shorter than W)
{            Apply the following to each chunk:
 {            Apply the following to each number in the chunk:
  "|X|"S3*?    Push "|X|" if the number is 1, or "   " if it's 0
 }%           (end of block)
 s            Stringify (joins with no separator)
 __           Duplicate twice (each shelf is 3 identical lines)
 '-3*W$*_     Push a string containing '-' repeated 3×W times, then duplicate it
}%           (end of block)
              At this point we have an array containing sequences of 3 identical lines 
              each followed by two lines of -'s
1m>          Rotate the array 1 to the right; brings the final line of -'s to the start
W%           Reverse the array, so that the top shelf is the partially empty one
"|\n|"*      Join the array with the string "|\n|", to build the sides of the shelves
"||"\*       Join the string "||" with the shelf string (adds the first and last | chars)
o            Print the result
;            Pop and discard W
```
[Answer]
# Python 3, 142 bytes
Still working on it. `b` is for 'number of books' and `w` is for shelf width.
```
def s(b,w):
 R=b%w
 B='|\n'
 I='|'
 X='|X|'
 d=I+3*w*'-'+B
 f=I+X*w+B
 p=I+R*X+3*(w-R)*' '+B
 print(R and d+3*p+d or" ")+b//w*(d+3*f+d))
```
[Answer]
# AHK, 208 bytes
```
AutoTrim,Off
w=%1%
b=%2%
f:=Mod(b,w)
Loop,%w%
s=%s%---
s=|%s%|`n
If (f>0) {
Loop,%f%
t=%t%|X|
Loop,% w-f
t=%t% ` ` `
t=|%t%|`n
t:=s t t t s
}
Loop,%w%
r=%r%|X|
r=|%r%|`n
Loop,% (b-f)/w
t:=t s r r r s
Send,%t%
```
There are a few things frustating me from golfing further:
* AutoHotkey doesn't have a built-in repeat function
* You can't directly use the passed in arguments (`%1%` & `%2%`) in math functions because those expect variable or number input and it will assume the unescaped `1` to be the number one rather than the variable name
* I am not very good at golfing
An easier to read version of the above looks like this:
```
AutoTrim,Off
w=%1%
b=%2%
f:=Mod(b,w)
Loop,%w%
   s=%s%---
s=|%s%|`n
If (f>0) {
   Loop,%f%
      t=%t%|X|
   Loop,% w-f
      t=%t% ` ` `
   t=|%t%|`n
   t:=s t t t s
}
Loop,%w%
   r=%r%|X|
r=|%r%|`n
Loop,% (b-f)/w
   t:=t s r r r s
Send,%t%
```
If a `Loop` doesn't use brackets `{}`, then only the next line is part of the loop. If setting a variable's value using `:=` instead of `=`, you can drop the percent sign escape characters. Tilde n is the newline character.
[Answer]
# Java 7, ~~230~~ ~~224~~ 222 bytes
```
String c(int w,int b){String r="",n="|\n",z="|";int i=0,j,k,t=b%w<1?w:b%w,x=b/w+(t!=w?1:0);for(;i++<w;z+="---");z+=n;for(i=0;i<x;i++){r+=z;for(j=0;j++<3;r+=n){r+="|";for(k=0;k<w;r+=i<1&k++>=t?"   ":"|X|");}r+=z;}return r;}
```
**Explanation:**
```
String c(int w, int b){                // Method with two integer parameters and String return-type
  String r = "",                       //  The return-String
         n = "|\n",                    //  Part that's used multiple times in the code
         z = "|";                      //  Shelf part of the book-boxes
  int i = 0, j, k,                     //  Indexes used in the for-loops
      t = b%w < 1 ? w : b%w,           //  Books on top shelf
      x = b/w + (t != w ? 1 : 0);      //  Amount of shelves
  for(; i++ < w; z += "---"); z += n;  //  Create the shelf-part ("|---|"; with w times "---")
  for(i = 0; i < x; i++){              //  Loop over the rows
    r += z;                            //   Append the result with the shelf-part
    for(j = 0; j++ < 3; ){             //   Loop three times (the height of the books & boxes)
      r += "|";                        //    Append the result-String with "|"
      for(k = 0; k < w;                //    Loop over the columns
          r +=                         //     And append the result-String with:
           i < 1                       //      If this is the first row:
           & k++ >= t ?                //      And the current column is larger or equal to the amount of books in the top shelf
             "   "                     //       Use an empty space
           :                           //      Else:
             "|X|"                     //       Use the book-part
            );                         //    End of columns loop
         r += n;                       //    Append the result-String with a "|" and a new-line
       }                               //   End of the loop of three
      r += z;                          //   Append the result-String with the shelf-part
    }                                  //  End of rows loop
    return r;                          //  Return the result-String
 }                                     // End of method
```
**Test code:**
[Try it here.](https://ideone.com/sFoljG)
```
class M{
  static String c(int w,int b){String r="",n="|\n",z="|";int i=0,j,k,t=b%w<1?w:b%w,x=b/w+(t!=w?1:0);for(;i++<w;z+="---");z+=n;for(i=0;i<x;i++){r+=z;for(j=0;j++<3;r+=n){r+="|";for(k=0;k<w;r+=i<1&k++>=t?"   ":"|X|");}r+=z;}return r;}
  public static void main(String[] a){
    System.out.println(c(6, 2));
    System.out.println(c(2, 6));
    System.out.println(c(4, 9));
  }
}
```
**Output:**
```
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------------|
||X|         |
||X|         |
||X|         |
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
```
[Answer]
# PowerShell, 109 bytes
```
param($w,$b)for(;$b;$b-=$c){if(!($c=$b%$w)){$c=$w}($l="|$('-'*$w*3)|")
,"|$('|X|'*$c)$(' '*($w-$c)*3)|"*3
$l}
```
Less golfed test script:
```
$f = {
param($w,$b)
for(;$b;$b-=$c){
    if(!($c=$b%$w)){$c=$w}
    ($l="|$('-'*$w*3)|")
    ,"|$('|X|'*$c)$(' '*($w-$c)*3)|"*3
    $l
}
}
@(
    ,(6, 2, 
    "|------------------|",
    "||X||X|            |",
    "||X||X|            |",
    "||X||X|            |",
    "|------------------|")
    ,(2, 6,
    "|------|",
    "||X||X||",
    "||X||X||",
    "||X||X||",
    "|------|",
    "|------|",
    "||X||X||",
    "||X||X||",
    "||X||X||",
    "|------|",
    "|------|",
    "||X||X||",
    "||X||X||",
    "||X||X||",
    "|------|")
    ,(4, 9,
    "|------------|",
    "||X|         |",
    "||X|         |",
    "||X|         |",
    "|------------|",
    "|------------|",
    "||X||X||X||X||",
    "||X||X||X||X||",
    "||X||X||X||X||",
    "|------------|",
    "|------------|",
    "||X||X||X||X||",
    "||X||X||X||X||",
    "||X||X||X||X||",
    "|------------|")
) | % {
    $w,$b,$expected = $_
    $result = &$f $w $b
    "$result"-eq"$expected"
    $result
}
```
Output:
```
True
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|
True
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
True
|------------|
||X|         |
||X|         |
||X|         |
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
```
## PowerShell, 109 bytes, alternative
```
param($w,$b)for(;$b;$b-=$c){($l="|$('---'*$w)|")
,"|$('|X|'*($c=(($b%$w),$w-ne0)[0]))$('   '*($w-$c))|"*3
$l}
```
[Answer]
# [Python 2](https://docs.python.org/2/), ~~120~~ 118 bytes
```
i,j=input()
a=j%i
n='|\n'
x='|'+'---'*i+n
print(x+('|'+'|x|'*a+' '*(i-a)*3+n)*3,'')[a<1]+(x+('|'+'|x|'*i+n)*3)*(j/i)+x
```
[Try it online!](https://tio.run/nexus/python2#VYo7CsMwEAV7ncJNePuRiE1SRidJUqhcFYsxDqjQ3WXjLs0bmHnDYs3m628nDiXXmwXP6B9HaCehSClBTD2sm/lOTenSvXVIUUwQslRYHurnRIDf5bV89f9pV2WhejfWNsYzLvMB "Python 2 – TIO Nexus")
Have been meaning to have a go at this one for the last few days. Now that I have finally got time to do it there's already a shorter Python answer. Oh well, just posted as an alternative.
Input taken as width,books
[Answer]
# [SOGL](https://github.com/dzaima/SOGL), 64 [bytes](https://github.com/dzaima/SOGL/blob/master/chartable.md)
```
be%→M"Q└ƨS‘*ač;┼→S%‘A |e3* -* |++M?tMSeM-9*@*a+┼Ot}be÷:?{teSa┼Ot
```
Explanation:
First function:
```
   →M  define function M which pushes
b      the book amount
  %    mod
 e     the bookshelf width
```
second function:
```
           →S  create function S (example input: 3)          [3]
"Q└ƨS‘         push the string "|||XXX|||" (the book)        [3, "|||XXX|||"]
      *        multiply by the number on stack (book count)  ["|||XXX||||||XXX||||||XXX|||"]
       a       push variable A (later defined "|||")         ["|||XXX||||||XXX||||||XXX|||", "|||"]
        č      chop into char array                          ["|||XXX||||||XXX||||||XXX|||", ["|", "|", "|"]]
         ;     swap top 2 on stack                           [["|", "|", "|"], "|||XXX||||||XXX||||||XXX|||"]
          ┼    horizontally append                           [["||X||X||X|", "||X||X||X|", "||X||X||X|"]]
```
this function expects a number (book count) on stack and outputs the bookshelfs books
```
["||X||X||X|",
 "||X||X||X|",
 "||X||X||X|"]
```
Further down example given is e=3 (bookshelf width) and b=8 (book amount)
```
%‘A              var A = "|||"                        
    |            push "|"                      ["|"]                
     e3*         push E * 3                    ["|", 9]             
         -*      push that many "-"es          ["|", "---------"]   
            |+   append "|"                    ["|", "---------|"]  
              +  prepend the "|"               ["|---------|"]      
```
this is the bookshelf top/bottom line and always stays on the stack
first part (half-empty bookshelf)
First main part
```
M?               }               if the modulo != 0
  tM                             output the bookshelf top/bottom line
    S                            execute the S function width the modulo
     eM-                         push bookshelf width - modulo (empty space count)
        9*                       multiply by 9 (books are 3x3 so 3x3 spaces)
          @*                     get that many spaces
            a+                   append to that "|||"
              ┼                  horizontally append
               O                 output
                t                output the bookshelf top/bottom line
```
And the last part
```
be÷            floor divide book amout by width (full shelves)
   :?          if not 0 (a bug makes all loops execute once)
     {         repeat
      t        output the bookshelf top/bottom line
       eS      execute S with shelf width (full shelf)
         a┼    horizontally append "|||"
           O   output
            t  output the bookshelf top/bottom line
```
[Answer]
# [Java (JDK)](http://jdk.java.net/), 124 bytes
```
s->b->{for(int i=0;i++<(b-~s)/s*5;)System.out.printf("|%-"+s*3+"s|%n",i%5<2?"-".repeat(s*3):"|X|".repeat(i<5&b%s>0?b%s:s));}
```
[Try it online!](https://tio.run/##XY9Pb4JAEMXvfooJCc2uwNbaalJBPDRp0kNPXkwMhwXBrIWFMIOJEfrV6arUND3sn/fe5Jc3B3mU3mH31auiKmuCg9GiIZWLrNEJqVKLsT@qmjhXCSS5RIRPqTScRwCDiyTJPMdS7aAwGVtTrfR@G4Gs98ivowAfmt4HYmD@b6XGpkjrEDJY9uiFsRees7JmShOo5cRXjhOw2PtG/ojjmc/XJ6S0EGVDojJ4ypjV2p7l4PjZsbC1teUqexZMV5ZniTqtUknMZHxhtZv27qhg9hDbGE5W5l4g537X@9d@BrmNTGdKkRCWQ2uAM8xdmELn3vXUhflf/eLC66/ubrBhkQG3uEH5nZkJWVX5iV3s7STiQiZJWtFNP0XcH@b@75xrNmTd6HK6/gc "Java (JDK) – Try It Online")
## Credits
* -2 bytes thanks to [ceilingcat](https://codegolf.stackexchange.com/users/52904/ceilingcat)
[Answer]
# PHP>=7.1, 138 Bytes
```
for([,$w,$b]=$argv;$i<ceil($b/$w)*5;)echo str_pad("|".str_repeat(["","|X|"][$t=($i+1)%5>1],$i++<5&&$b%$w?$b%$w:$w),$w*3+1,"- "[$t])."|\n";
```
[Online Version](http://sandbox.onlinephpfunctions.com/code/e08ab44e74ca3839fa77163601db3dd27dcb7955)
[Answer]
# [Canvas](https://github.com/dzaima/Canvas), 33 [bytes](https://github.com/dzaima/Canvas/blob/master/files/chartable.md)
```
|X|３＊×⁷３×⇵-×|３＊×╫│；２２╋Ｐ
％？％⁸｝÷［⁷⁸
```
[Try it here!](https://dzaima.github.io/Canvas/?u=JTdDWCU3QyV1RkYxMyV1RkYwQSVENyV1MjA3NyV1RkYxMyVENyV1MjFGNS0lRDclN0MldUZGMTMldUZGMEElRDcldTI1NkIldTI1MDIldUZGMUIldUZGMTIldUZGMTIldTI1NEIldUZGMzAlMEEldUZGMDUldUZGMUYldUZGMDUldTIwNzgldUZGNUQlRjcldUZGM0IldTIwNzcldTIwNzg_,i=NSUwQTM_,v=1)
Explanation (some characters have been replaced to look more monospace):
```
|X|3*×⁷3×⇵-×|3*×╫│;22╋P  helper function. Prints a shelf with X books
|X|                      push "|X|"
   3*                    repeat it 3 times vertically
     ×                   repeat that horizontally by the item (X) below on the stack
      ⁷3×                push width * 3
         ⇵               ceiling divide that by 2
          -×             repeat "-" that many times
            |3*          repeat "|" vertically 3 times (aka "|¶|¶|")
               ×         prepend that to the dashes (aka ¼ of a bookshelf)
                ╫│       quad-palindromize with horizontal overlap of the remainder
                           taken before and vertical overlap of 1
                  ;      get the books on top
                   22╋   and at coordinates (2;2) in the shelf, place them in
                      P  print that whole thing
%?%⁸}÷[⁷⁸  
%?  }      if width%amount (!= 0)
  %⁸         execute the helper function with width%amount on the stack
     ÷[    repeat floor(width/amount) times
       ⁷     push width
        ⁸    execute the helper function
```
[Answer]
# [Pip](https://github.com/dloscutoff/pip) `-n`, 45 bytes
```
Wb-:yPPZ['-X3Xa"|X|"X(Yb%a|a).sX3Xa-yRL3]WR'|
```
Takes the width and book count, respectively, as command-line arguments. [Try it online!](https://tio.run/##K8gs@P8/PEnXqjIgICpaXTfCOCJRqSaiRilCIzJJNbEmUVOvGCSmWxnkYxwbHqRe8///f928/6b/DY0A "Pip – Try It Online")
### Explanation
We run a loop to print the shelves one by one from top to bottom. At each iteration, we update `b` (the number of books to print) by subtracting `y` (the number of books printed on that iteration). When `b` reaches 0, the loop exits.
```
Wb-:yPPZ['-X3Xa"|X|"X(Yb%a|a).sX3Xa-yRL3]WR'|
                                               a is 1st cmdline arg (shelf width); b is 2nd cmdline
                                                 arg (# books); s is space; y is ""
                                               Note that "" becomes zero in numeric contexts
Wb-:y                                          While b decremented by y is nonzero:
                       b%a|a                    b mod a, or a if that quantity is zero
                      Y                         Yank that value into y
                     (      )                   This is the number of books on the current shelf
               "|X|"                            Book-spine string
                    X                           Repeated y times
                                  a-y           Number of empty slots on the current shelf
                              sX3X              Three spaces for each slot
                             .                  Concatenate to the book-spines string
                                     RL3        Make a list of 3 copies of that string
         '-X3Xa                                 3*a hyphens
        [                               ]       Put that string and the above list in a list
                                         WR'|   Wrap all strings in the nested list in |
      PZ                                        Palindromize the outer list (adding a copy of the
                                                hyphens to the end of it)
     P                                          Print, joining all sublists on newlines (-n flag)
```
Because that's a little involved, here's an example of the first iteration when `a = 3, b = 8`:
```
Yb%a|a       2
"|X|"X ^     "|X||X|"
^ .sX3Xa-y   "|X||X|   "
^ RL3        ["|X||X|   ";"|X||X|   ";"|X||X|   "]
['-X3Xa ^ ]  ["---------";["|X||X|   ";"|X||X|   ";"|X||X|   "]]
^ WR'|       ["|---------|";["||X||X|   |";"||X||X|   |";"||X||X|   |"]]
PZ ^         ["|---------|";["||X||X|   |";"||X||X|   |";"||X||X|   |"];"|---------|"]
```
which then prints as
```
|---------|
||X||X|   |
||X||X|   |
||X||X|   |
|---------|
```
[Answer]
# [Pyth](https://github.com/isaacg1/pyth), 56 bytes
```
M++GHGV_fTs*V,]Q1.DEQjCg*5\|smgL\-*L3?d"|X|""   ".[*]1N0
```
Accepts shelf width, book count as separate arguments in that order. Try it online [here](https://pyth.herokuapp.com/?code=M%2B%2BGHGV_fTs%2AV%2C%5DQ1.DEQjCg%2A5%5C%7CsmgL%5C-%2AL3%3Fd%22%7CX%7C%22%22%20%20%20%22.%5B%2A%5D1N0&input=7%0A12&debug=0), or verify all the test cases at once [here](https://pyth.herokuapp.com/?code=M%2B%2BGHGV_fTs%2AV%2C%5DQ1.DEQjCg%2A5%5C%7CsmgL%5C-%2AL3%3Fd%22%7CX%7C%22%22%20%20%20%22.%5B%2A%5D1N0&test_suite=1&test_suite_input=6%0A2%0A2%0A6%0A4%0A9&debug=0&input_size=2).
```
M++GHGV_fTs*V,]Q1.DEQjCg*5\|smgL\-*L3?d"|X|""   ".[*]1N0Q   Implicit: Q=1st arg, E=2nd arg
                                                            Trailing Q inferred
M                                                           Define a function, g(G,H):
 ++GHG                                                        Return G + H + G
                 .DEQ                                       Divmod E by Q, yields [E//Q, E%Q]
             ,]Q1                                           [[Q], 1]
           *V                                               Vectorised multiply the two previous results
                                                              This yields Q repeated E//Q times, then E%Q
          s                                                 Flatten
        fT                                                  Filter out falsey values (i.e. trailing 0 if present)
       _                                                    Reverse (to put partially filled shelf on top)
      V                                                     For N in the above:
                                                    ]1        [1]
                                                   *  N       Repeat the above N times
                                                 .[    0Q     Pad the above on the right with 0, to length Q
                             m                                Map the above, as d, using:
                                     ?d"|X|""   "               If d != 0, yield "|X|", else "   "
                                  *L3                           Multiply each char by 3
                                                                  Yields ['|||','XXX','|||'] or ['   ','   ','   ']
                              gL\-                              Use g to wrap each element in '-'
                            s                                 Flatten
                       g*5\|                                  Use g to add '|||||' to start and end of the above
                      C                                       Transpose
                     j                                        Join on newlines, implicit print
```
[Answer]
# [Forth (gforth)](http://www.complang.tuwien.ac.at/forth/gforth/Docs-html/), 622 bytes (minimized (remove comments, indentation, 1-char word names) to 303 bytes)
My first play with Forth :)
```
: bar 124 EMIT ;
: delimline ( width -- )
    bar
    3 * 0 DO 45 EMIT LOOP
    bar CR
;
: bookline ( width books -- )
    bar
    DUP 0 DO bar 88 EMIT bar LOOP
    2DUP = IF
        DROP DROP
    ELSE
        - 0 do 3 SPACES LOOP
    THEN
    bar CR
;
: shelf ( width books -- )
    DUP 0 = IF
        DROP DROP
    ELSE
        OVER delimline
        3 0 DO OVER OVER bookline LOOP
        DROP delimline
    THEN
;
: stack ( width books -- )
    CR
    OVER OVER OVER MOD shelf
    OVER /
    DUP 0 = IF
        DROP DROP
    ELSE 
        0 DO DUP DUP shelf LOOP
    THEN
;
6 2 stack
2 6 stack
3 5 stack
4 4 stack
```
[Try it online!](https://tio.run/##jZBvi4JAEMbf76d4Xl4HcqUW0dGLyD0uqFa07n2lnpJ3Qgl9fNudqRWJIGFnx/nz7G8mq0517vxm5mqaCfa7EwauD7labPApxARJWhZ/ZfGf4g2XIqlzOA56AvrTxXR7eEcfgYI/5MalUuG9AvNIkNC@qo4dHRM4P6oF25DVTPN4zIrGt6quKZli8UV/1BOpkAxF5DKWNuVosaTSjHE4m8u4Vdl8y/UD5DlPy@wZIZO9@rD6kVG7PRv2eDjKkrF7sWRWuNtNwExZ7w7HZ5R6FPt8a1Yq4OHa5MfrQ8HmCN70mMPb6m5UA47gMqJwMbp5HoY3z4fPXtNcAQ "Forth (gforth) – Try It Online")
# Output
```
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|---------|
||X||X|   |
||X||X|   |
||X||X|   |
|---------|
|---------|
||X||X||X||
||X||X||X||
||X||X||X||
|---------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
```
]